Compare commits
No commits in common. "08862f52af46051c20e2c0c2968ff599f953c808" and "6df7f1e53b6bf791b463aed1f9eb5342ba778e5f" have entirely different histories.
08862f52af
...
6df7f1e53b
103
Program.cs
103
Program.cs
@ -40,7 +40,6 @@ public class FpsCounter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class CameraInfo {
|
public class CameraInfo {
|
||||||
public readonly Vector2i Resolution;
|
public readonly Vector2i Resolution;
|
||||||
|
|
||||||
@ -53,14 +52,12 @@ public class CameraInfo {
|
|||||||
public static readonly CameraInfo IPHONE_12_MINI = new(new Vector2i(4032, 3024));
|
public static readonly CameraInfo IPHONE_12_MINI = new(new Vector2i(4032, 3024));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public enum ToolState {
|
public enum ToolState {
|
||||||
Active,
|
Active,
|
||||||
Done,
|
Done,
|
||||||
Canceled
|
Canceled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public interface ITool {
|
public interface ITool {
|
||||||
void SetActivePhoto(Photo photo);
|
void SetActivePhoto(Photo photo);
|
||||||
ToolState HandleInput(UiGeometry geometry, KeyboardState input, MouseState mouse, Game game);
|
ToolState HandleInput(UiGeometry geometry, KeyboardState input, MouseState mouse, Game game);
|
||||||
@ -68,7 +65,6 @@ public interface ITool {
|
|||||||
void Draw(UiGeometry geometry, Game game);
|
void Draw(UiGeometry geometry, Game game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class ViewTool : ITool {
|
public class ViewTool : ITool {
|
||||||
Photo? activePhoto;
|
Photo? activePhoto;
|
||||||
|
|
||||||
@ -81,7 +77,7 @@ public class ViewTool : ITool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public string Status() {
|
public string Status() {
|
||||||
return "";
|
return "view";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw(UiGeometry geometry, Game game) {
|
public void Draw(UiGeometry geometry, Game game) {
|
||||||
@ -92,51 +88,39 @@ public class ViewTool : ITool {
|
|||||||
// FIXME: remove unneeded dependencies on "Game" or at least refactor them a bit.
|
// FIXME: remove unneeded dependencies on "Game" or at least refactor them a bit.
|
||||||
public class CropTool : ITool {
|
public class CropTool : ITool {
|
||||||
|
|
||||||
Photo activePhoto;
|
Photo? activePhoto;
|
||||||
Vector2i mouseDragStart;
|
Vector2i mouseDragStart;
|
||||||
Vector2i mouseDragEnd;
|
Vector2i mouseDragEnd;
|
||||||
string status = "";
|
string status = "";
|
||||||
|
|
||||||
public CropTool(Photo photo) {
|
|
||||||
activePhoto = photo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetActivePhoto(Photo photo) {
|
public void SetActivePhoto(Photo photo) {
|
||||||
if (photo != activePhoto) {
|
|
||||||
mouseDragStart = Vector2i.Zero;
|
|
||||||
mouseDragEnd = Vector2i.Zero;
|
|
||||||
}
|
|
||||||
activePhoto = photo;
|
activePhoto = photo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ToolState HandleInput(UiGeometry geometry, KeyboardState input, MouseState mouse, Game game) {
|
public ToolState HandleInput(UiGeometry geometry, KeyboardState input, MouseState mouse, Game game) {
|
||||||
Vector2i mousePosition = (Vector2i) mouse.Position;
|
Vector2i mousePosition = (Vector2i) mouse.Position;
|
||||||
Vector2i imagePosition = game.ScreenToImage(mousePosition);
|
|
||||||
|
|
||||||
if (mouse.IsButtonPressed(MouseButton.Button1)) {
|
if (mouse.IsButtonPressed(MouseButton.Button1)) {
|
||||||
if (geometry.PhotoBox.ContainsInclusive(mousePosition)) {
|
if (geometry.PhotoBox.ContainsInclusive(mousePosition)) {
|
||||||
mouseDragStart = imagePosition;
|
mouseDragStart = mousePosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mouse.IsButtonDown(MouseButton.Button1)) {
|
if (mouse.IsButtonDown(MouseButton.Button1)) {
|
||||||
if (geometry.PhotoBox.ContainsInclusive(mousePosition)) {
|
if (geometry.PhotoBox.ContainsInclusive(mousePosition)) {
|
||||||
mouseDragEnd = imagePosition;
|
// FIXME: really this should be clipped to the active photo's drawable area, not the whole photobox.
|
||||||
|
mouseDragEnd = mousePosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (left, right, top, bottom) = GetCrop();
|
Vector2i start = game.ScreenToImage(mouseDragStart);
|
||||||
|
// FIXME: this needs to be the actual width of the computed box.
|
||||||
|
Vector2i size = game.ScreenToImage(mouseDragEnd) - start;
|
||||||
|
|
||||||
Vector2i size = new(right - left, bottom - top);
|
status = $"({start.X}, {start.Y}) {size.X}x{size.Y}";
|
||||||
status = $"({left}, {top}) {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)) {
|
if (input.IsKeyPressed(Keys.Enter)) {
|
||||||
|
ApplyCrop(game);
|
||||||
return ToolState.Done;
|
return ToolState.Done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,8 +139,6 @@ public class CropTool : ITool {
|
|||||||
// in other direction work well.
|
// in other direction work well.
|
||||||
Vector2i start = mouseDragStart;
|
Vector2i start = mouseDragStart;
|
||||||
Vector2i end = mouseDragEnd;
|
Vector2i end = mouseDragEnd;
|
||||||
// FIXME: choose the aspect ratio based on the original image aspect ratio.
|
|
||||||
// FIXME: allow for unconstrained crop, 1:1, etc.
|
|
||||||
end.Y = Math.Min(end.Y, start.Y + (end.X - start.X) * 4 / 6);
|
end.Y = Math.Min(end.Y, start.Y + (end.X - start.X) * 4 / 6);
|
||||||
end.X = start.X + (end.Y - start.Y) * 6 / 4;
|
end.X = start.X + (end.Y - start.Y) * 6 / 4;
|
||||||
int left = Math.Min(start.X, end.X);
|
int left = Math.Min(start.X, end.X);
|
||||||
@ -166,16 +148,31 @@ public class CropTool : ITool {
|
|||||||
return (left, right, top, bottom);
|
return (left, right, top, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw(UiGeometry geometry, Game game) {
|
void ApplyCrop(Game game) {
|
||||||
if (activePhoto.CropRectangle == Rectangle.Empty) {
|
var (left, right, top, bottom) = GetCrop();
|
||||||
|
int area = (right - left) * (bottom - top);
|
||||||
|
if (area == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2i leftTop = game.ImageToScreen(activePhoto.CropRectangle.Left, activePhoto.CropRectangle.Top);
|
Vector2i leftTop = game.ScreenToImage(left, top);
|
||||||
Vector2i rightBottom = game.ImageToScreen(activePhoto.CropRectangle.Right, activePhoto.CropRectangle.Bottom);
|
Vector2i rightBottom = game.ScreenToImage(right, bottom);
|
||||||
var (left, top) = leftTop;
|
Rectangle crop = Rectangle.FromLTRB(leftTop.X, leftTop.Y, rightBottom.X, rightBottom.Y);
|
||||||
var (right, bottom) = rightBottom;
|
// FIXME: make sure this doesn't exceed image.Bounds.
|
||||||
|
// FIXME: once set, display it properly in the PhotoBox.
|
||||||
|
if (activePhoto != null) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (area == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Color4 shadeColor = new Color4(0, 0, 0, 0.75f);
|
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(0, 0, left, geometry.PhotoBox.Max.Y), shadeColor);
|
||||||
game.DrawFilledBox(new Box2i(left, 0, geometry.PhotoBox.Max.X, top), shadeColor);
|
game.DrawFilledBox(new Box2i(left, 0, geometry.PhotoBox.Max.X, top), shadeColor);
|
||||||
@ -195,7 +192,7 @@ public class CropTool : ITool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: this should probably be IDisposable?
|
||||||
public class Photo {
|
public class Photo {
|
||||||
public string Filename;
|
public string Filename;
|
||||||
public bool Loaded = false;
|
public bool Loaded = false;
|
||||||
@ -477,7 +474,6 @@ public class Photo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class Texture : IDisposable {
|
public class Texture : IDisposable {
|
||||||
public int Handle;
|
public int Handle;
|
||||||
public Vector2i Size;
|
public Vector2i Size;
|
||||||
@ -528,7 +524,6 @@ public class Texture : IDisposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class UiGeometry {
|
public class UiGeometry {
|
||||||
public static Vector2i MIN_WINDOW_SIZE = new(1024, 768);
|
public static Vector2i MIN_WINDOW_SIZE = new(1024, 768);
|
||||||
private static CameraInfo activeCamera = CameraInfo.CANON_EOS_R6M2;
|
private static CameraInfo activeCamera = CameraInfo.CANON_EOS_R6M2;
|
||||||
@ -570,7 +565,6 @@ public class UiGeometry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class Util {
|
public static class Util {
|
||||||
public const float PI = (float) Math.PI;
|
public const float PI = (float) Math.PI;
|
||||||
|
|
||||||
@ -593,7 +587,7 @@ public static class Util {
|
|||||||
}
|
}
|
||||||
// FIXME: I'm not convinced that all of these are correct, especially the
|
// FIXME: I'm not convinced that all of these are correct, especially the
|
||||||
// cases that involve flipping (because whether you're flipping before or
|
// cases that involve flipping (because whether you're flipping before or
|
||||||
// after rotation matters.)
|
// after rotation matters.).
|
||||||
var operations = new Dictionary<ushort, (RotateMode, FlipMode)> {
|
var operations = new Dictionary<ushort, (RotateMode, FlipMode)> {
|
||||||
{ 2, (RotateMode.None, FlipMode.Horizontal) },
|
{ 2, (RotateMode.None, FlipMode.Horizontal) },
|
||||||
{ 3, (RotateMode.Rotate180, FlipMode.None) },
|
{ 3, (RotateMode.Rotate180, FlipMode.None) },
|
||||||
@ -612,11 +606,6 @@ public static class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Texture RenderText(string text, int size) {
|
public static Texture RenderText(string text, int size) {
|
||||||
// Make sure that 0-length text doesn't end up as a 0-size texture, which
|
|
||||||
// might cause problems.
|
|
||||||
if (text.Length == 0) {
|
|
||||||
text = " ";
|
|
||||||
}
|
|
||||||
Font font = SystemFonts.CreateFont("Consolas", size, FontStyle.Bold);
|
Font font = SystemFonts.CreateFont("Consolas", size, FontStyle.Bold);
|
||||||
TextOptions options = new(font);
|
TextOptions options = new(font);
|
||||||
FontRectangle rect = TextMeasurer.Measure(text, new TextOptions(font));
|
FontRectangle rect = TextMeasurer.Measure(text, new TextOptions(font));
|
||||||
@ -663,7 +652,6 @@ public static class Util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class Game : GameWindow {
|
public class Game : GameWindow {
|
||||||
public Game(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings) {
|
public Game(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings) {
|
||||||
activeTool = viewTool;
|
activeTool = viewTool;
|
||||||
@ -725,6 +713,8 @@ public class Game : GameWindow {
|
|||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lastPhotoIndex = photoIndex;
|
||||||
|
|
||||||
mousePosition = (Vector2i) MouseState.Position;
|
mousePosition = (Vector2i) MouseState.Position;
|
||||||
|
|
||||||
// Look for mouse clicks on thumbnails or stars.
|
// Look for mouse clicks on thumbnails or stars.
|
||||||
@ -796,6 +786,10 @@ public class Game : GameWindow {
|
|||||||
photoIndex = Math.Clamp(photoIndex, 0, photos.Count - 1);
|
photoIndex = Math.Clamp(photoIndex, 0, photos.Count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (photoIndex != lastPhotoIndex) {
|
||||||
|
// FIXME!!!: do something to reset tool state here
|
||||||
|
}
|
||||||
|
|
||||||
// Handle presses of the "rating" keys -- 0-5 and `.
|
// Handle presses of the "rating" keys -- 0-5 and `.
|
||||||
// A normal press just sets the rating of the current photo.
|
// A normal press just sets the rating of the current photo.
|
||||||
// If the user is holding "shift", we instead filter to only show photos of that rating or higher.
|
// If the user is holding "shift", we instead filter to only show photos of that rating or higher.
|
||||||
@ -862,7 +856,7 @@ public class Game : GameWindow {
|
|||||||
// Handle tool switching.
|
// Handle tool switching.
|
||||||
if (activeTool == viewTool) {
|
if (activeTool == viewTool) {
|
||||||
if (input.IsKeyPressed(Keys.C)) {
|
if (input.IsKeyPressed(Keys.C)) {
|
||||||
activeTool = new CropTool(photos[photoIndex]);
|
activeTool = new CropTool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -936,9 +930,9 @@ public class Game : GameWindow {
|
|||||||
GL.VertexAttribPointer(texCoordLocation, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 3 * sizeof(float));
|
GL.VertexAttribPointer(texCoordLocation, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 3 * sizeof(float));
|
||||||
|
|
||||||
// Load photos from a directory.
|
// 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\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(@"G:\DCIM\100EOSR6\");
|
||||||
// string[] files = Directory.GetFiles(@"c:\users\colin\desktop\totte-output\2023\07\31");
|
// 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");
|
// string[] files = Directory.GetFiles(@"C:\Users\colin\Pictures\photos\2018\06\23");
|
||||||
@ -1115,9 +1109,7 @@ public class Game : GameWindow {
|
|||||||
|
|
||||||
public Vector2i ScreenToImage(int x, int y) {
|
public Vector2i ScreenToImage(int x, int y) {
|
||||||
int rx = (int) ((x - activeOffset.X) / activeScale);
|
int rx = (int) ((x - activeOffset.X) / activeScale);
|
||||||
rx = Math.Clamp(rx, 0, photos[photoIndex].Size.X);
|
|
||||||
int ry = (int) ((y - activeOffset.Y) / activeScale);
|
int ry = (int) ((y - activeOffset.Y) / activeScale);
|
||||||
ry = Math.Clamp(ry, 0, photos[photoIndex].Size.Y);
|
|
||||||
return new(rx, ry);
|
return new(rx, ry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1125,16 +1117,6 @@ public class Game : GameWindow {
|
|||||||
return ScreenToImage(position.X, position.Y);
|
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) {
|
public void DrawTexture(Texture texture, int x, int y) {
|
||||||
DrawTexture(texture, Util.MakeBox(x, y, texture.Size.X, texture.Size.Y));
|
DrawTexture(texture, Util.MakeBox(x, y, texture.Size.X, texture.Size.Y));
|
||||||
}
|
}
|
||||||
@ -1218,7 +1200,6 @@ public class Game : GameWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static class Program {
|
static class Program {
|
||||||
static void Main(string[] args) {
|
static void Main(string[] args) {
|
||||||
List<MonitorInfo> monitors = Monitors.GetMonitors();
|
List<MonitorInfo> monitors = Monitors.GetMonitors();
|
||||||
|
Loading…
Reference in New Issue
Block a user