|
|
@ -40,6 +40,7 @@ public class FpsCounter { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public class CameraInfo { |
|
|
|
public readonly Vector2i Resolution; |
|
|
|
|
|
|
@ -52,12 +53,14 @@ public class CameraInfo { |
|
|
|
public static readonly CameraInfo IPHONE_12_MINI = new(new Vector2i(4032, 3024)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public enum ToolState { |
|
|
|
Active, |
|
|
|
Done, |
|
|
|
Canceled |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public interface ITool { |
|
|
|
void SetActivePhoto(Photo photo); |
|
|
|
ToolState HandleInput(UiGeometry geometry, KeyboardState input, MouseState mouse, Game game); |
|
|
@ -65,6 +68,7 @@ public interface ITool { |
|
|
|
void Draw(UiGeometry geometry, Game game); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public class ViewTool : ITool { |
|
|
|
Photo? activePhoto; |
|
|
|
|
|
|
@ -99,35 +103,40 @@ public class CropTool : ITool { |
|
|
|
|
|
|
|
public void SetActivePhoto(Photo photo) { |
|
|
|
if (photo != activePhoto) { |
|
|
|
// FIXME: handle this sensibly.
|
|
|
|
mouseDragStart = Vector2i.Zero; |
|
|
|
mouseDragEnd = Vector2i.Zero; |
|
|
|
} |
|
|
|
activePhoto = photo; |
|
|
|
} |
|
|
|
|
|
|
|
public ToolState HandleInput(UiGeometry geometry, KeyboardState input, MouseState mouse, Game game) { |
|
|
|
Vector2i mousePosition = (Vector2i) mouse.Position; |
|
|
|
Vector2i imagePosition = game.ScreenToImage(mousePosition); |
|
|
|
|
|
|
|
if (mouse.IsButtonPressed(MouseButton.Button1)) { |
|
|
|
if (geometry.PhotoBox.ContainsInclusive(mousePosition)) { |
|
|
|
mouseDragStart = mousePosition; |
|
|
|
mouseDragStart = imagePosition; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (mouse.IsButtonDown(MouseButton.Button1)) { |
|
|
|
if (geometry.PhotoBox.ContainsInclusive(mousePosition)) { |
|
|
|
// FIXME: really this should be clipped to the active photo's drawable area, not the whole photobox.
|
|
|
|
mouseDragEnd = mousePosition; |
|
|
|
mouseDragEnd = imagePosition; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Vector2i start = game.ScreenToImage(mouseDragStart); |
|
|
|
// FIXME: this needs to be the actual width of the computed box.
|
|
|
|
Vector2i size = game.ScreenToImage(mouseDragEnd) - start; |
|
|
|
var (left, right, top, bottom) = GetCrop(); |
|
|
|
|
|
|
|
Vector2i size = new(right - left, bottom - top); |
|
|
|
status = $"({left}, {top}) {size.X}x{size.Y}"; |
|
|
|
|
|
|
|
status = $"({start.X}, {start.Y}) {size.X}x{size.Y}"; |
|
|
|
Rectangle crop = Rectangle.Empty; |
|
|
|
if (size.X > 0 && size.Y > 0) { |
|
|
|
crop = Rectangle.FromLTRB(left, top, right, bottom); |
|
|
|
} |
|
|
|
activePhoto.CropRectangle = crop; |
|
|
|
|
|
|
|
if (input.IsKeyPressed(Keys.Enter)) { |
|
|
|
ApplyCrop(game); |
|
|
|
return ToolState.Done; |
|
|
|
} |
|
|
|
|
|
|
@ -157,29 +166,16 @@ public class CropTool : ITool { |
|
|
|
return (left, right, top, bottom); |
|
|
|
} |
|
|
|
|
|
|
|
void ApplyCrop(Game game) { |
|
|
|
var (left, right, top, bottom) = GetCrop(); |
|
|
|
int area = (right - left) * (bottom - top); |
|
|
|
if (area == 0) { |
|
|
|
public void Draw(UiGeometry geometry, Game game) { |
|
|
|
if (activePhoto.CropRectangle == Rectangle.Empty) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
Vector2i leftTop = game.ScreenToImage(left, top); |
|
|
|
Vector2i rightBottom = game.ScreenToImage(right, bottom); |
|
|
|
Rectangle crop = Rectangle.FromLTRB(leftTop.X, leftTop.Y, rightBottom.X, rightBottom.Y); |
|
|
|
// FIXME: make sure this doesn't exceed image.Bounds.
|
|
|
|
// FIXME: once set, display it properly in the PhotoBox.
|
|
|
|
activePhoto.CropRectangle = crop; |
|
|
|
Console.WriteLine(crop); |
|
|
|
} |
|
|
|
|
|
|
|
public void Draw(UiGeometry geometry, Game game) { |
|
|
|
var (left, right, top, bottom) = GetCrop(); |
|
|
|
int area = (right - left) * (bottom - top); |
|
|
|
Vector2i leftTop = game.ImageToScreen(activePhoto.CropRectangle.Left, activePhoto.CropRectangle.Top); |
|
|
|
Vector2i rightBottom = game.ImageToScreen(activePhoto.CropRectangle.Right, activePhoto.CropRectangle.Bottom); |
|
|
|
var (left, top) = leftTop; |
|
|
|
var (right, bottom) = rightBottom; |
|
|
|
|
|
|
|
if (area == 0) { |
|
|
|
return; |
|
|
|
} |
|
|
|
Color4 shadeColor = new Color4(0, 0, 0, 0.75f); |
|
|
|
game.DrawFilledBox(new Box2i(0, 0, left, geometry.PhotoBox.Max.Y), shadeColor); |
|
|
|
game.DrawFilledBox(new Box2i(left, 0, geometry.PhotoBox.Max.X, top), shadeColor); |
|
|
@ -199,7 +195,7 @@ public class CropTool : ITool { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// FIXME: this should probably be IDisposable?
|
|
|
|
|
|
|
|
public class Photo { |
|
|
|
public string Filename; |
|
|
|
public bool Loaded = false; |
|
|
@ -481,6 +477,7 @@ public class Photo { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public class Texture : IDisposable { |
|
|
|
public int Handle; |
|
|
|
public Vector2i Size; |
|
|
@ -531,6 +528,7 @@ public class Texture : IDisposable { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public class UiGeometry { |
|
|
|
public static Vector2i MIN_WINDOW_SIZE = new(1024, 768); |
|
|
|
private static CameraInfo activeCamera = CameraInfo.CANON_EOS_R6M2; |
|
|
@ -572,6 +570,7 @@ public class UiGeometry { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static class Util { |
|
|
|
public const float PI = (float) Math.PI; |
|
|
|
|
|
|
@ -664,6 +663,7 @@ public static class Util { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public class Game : GameWindow { |
|
|
|
public Game(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings) { |
|
|
|
activeTool = viewTool; |
|
|
@ -936,9 +936,9 @@ public class Game : GameWindow { |
|
|
|
GL.VertexAttribPointer(texCoordLocation, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 3 * sizeof(float)); |
|
|
|
|
|
|
|
// Load photos from a directory.
|
|
|
|
string[] files = Directory.GetFiles(@"c:\users\colin\desktop\photos-test\"); |
|
|
|
// string[] files = Directory.GetFiles(@"c:\users\colin\desktop\photos-test\");
|
|
|
|
// string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\07\14\");
|
|
|
|
// string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\07\23\");
|
|
|
|
string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\07\23\"); |
|
|
|
// string[] files = Directory.GetFiles(@"G:\DCIM\100EOSR6\");
|
|
|
|
// string[] files = Directory.GetFiles(@"c:\users\colin\desktop\totte-output\2023\07\31");
|
|
|
|
// string[] files = Directory.GetFiles(@"C:\Users\colin\Pictures\photos\2018\06\23");
|
|
|
@ -1115,7 +1115,9 @@ public class Game : GameWindow { |
|
|
|
|
|
|
|
public Vector2i ScreenToImage(int x, int y) { |
|
|
|
int rx = (int) ((x - activeOffset.X) / activeScale); |
|
|
|
rx = Math.Clamp(rx, 0, photos[photoIndex].Size.X); |
|
|
|
int ry = (int) ((y - activeOffset.Y) / activeScale); |
|
|
|
ry = Math.Clamp(ry, 0, photos[photoIndex].Size.Y); |
|
|
|
return new(rx, ry); |
|
|
|
} |
|
|
|
|
|
|
@ -1123,6 +1125,16 @@ public class Game : GameWindow { |
|
|
|
return ScreenToImage(position.X, position.Y); |
|
|
|
} |
|
|
|
|
|
|
|
public Vector2i ImageToScreen(int x, int y) { |
|
|
|
int rx = (int) ((x * activeScale) + activeOffset.X); |
|
|
|
int ry = (int) ((y * activeScale) + activeOffset.Y); |
|
|
|
return new(rx, ry); |
|
|
|
} |
|
|
|
|
|
|
|
public Vector2i ImageToScreen(Vector2i position) { |
|
|
|
return ImageToScreen(position.X, position.Y); |
|
|
|
} |
|
|
|
|
|
|
|
public void DrawTexture(Texture texture, int x, int y) { |
|
|
|
DrawTexture(texture, Util.MakeBox(x, y, texture.Size.X, texture.Size.Y)); |
|
|
|
} |
|
|
@ -1206,6 +1218,7 @@ public class Game : GameWindow { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static class Program { |
|
|
|
static void Main(string[] args) { |
|
|
|
List<MonitorInfo> monitors = Monitors.GetMonitors(); |
|
|
|