|
|
@ -184,29 +184,43 @@ public class Texture : IDisposable { |
|
|
|
|
|
|
|
public class UiGeometry { |
|
|
|
public static Vector2i MIN_WINDOW_SIZE = new Vector2i(640, 480); |
|
|
|
private static CameraInfo activeCamera = CameraInfo.NIKON_D7000; |
|
|
|
|
|
|
|
public readonly Vector2i WindowSize; |
|
|
|
public readonly List<Box2i> ThumbnailBoxes = new(); |
|
|
|
|
|
|
|
public UiGeometry() : this(MIN_WINDOW_SIZE) {} |
|
|
|
|
|
|
|
public UiGeometry(Vector2i windowSize) { |
|
|
|
WindowSize = windowSize; |
|
|
|
|
|
|
|
int thumbnailHeight = 150; |
|
|
|
int thumbnailWidth = (int) 1.0 * thumbnailHeight * activeCamera.Resolution.X / activeCamera.Resolution.Y; |
|
|
|
int numBoxes = 10; // FIXME
|
|
|
|
for (int i = 0; i < numBoxes; i++) { |
|
|
|
Box2i box = Util.makeBox(WindowSize.X - thumbnailWidth, i * thumbnailHeight, thumbnailWidth, thumbnailHeight); |
|
|
|
ThumbnailBoxes.Add(box); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public static class Util { |
|
|
|
public static Box2i makeBox(int left, int top, int width, int height) { |
|
|
|
return new Box2i(left, top, left + width, top + height); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public class Game : GameWindow { |
|
|
|
public Game(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings) { } |
|
|
|
|
|
|
|
static CameraInfo activeCamera = CameraInfo.NIKON_D7000; |
|
|
|
static int thumbnailHeight = 150; |
|
|
|
static int thumbnailWidth = (int) 1.0 * thumbnailHeight * activeCamera.Resolution.X / activeCamera.Resolution.Y; |
|
|
|
static Texture TEXTURE_WHITE; |
|
|
|
|
|
|
|
UiGeometry geometry = new UiGeometry(); |
|
|
|
UiGeometry geometry = new(); |
|
|
|
|
|
|
|
// four points of (x, y, z, tex_x, tex_y)
|
|
|
|
// Four points, each consisting of (x, y, z, tex_x, tex_y).
|
|
|
|
float[] vertices = new float[20]; |
|
|
|
|
|
|
|
// Indices to draw a rectangle from two triangles.
|
|
|
|
uint[] indices = { |
|
|
|
0, 1, 3, // first triangle
|
|
|
|
1, 2, 3 // second triangle
|
|
|
@ -215,7 +229,7 @@ public class Game : GameWindow { |
|
|
|
int VertexBufferObject; |
|
|
|
int ElementBufferObject; |
|
|
|
int VertexArrayObject; |
|
|
|
List<Texture> textures = new List<Texture>(); |
|
|
|
List<Texture> textures = new(); |
|
|
|
int textureIndex = 0; |
|
|
|
Shader shader; |
|
|
|
Matrix4 projection; |
|
|
@ -244,8 +258,6 @@ public class Game : GameWindow { |
|
|
|
protected override void OnLoad() { |
|
|
|
base.OnLoad(); |
|
|
|
|
|
|
|
Console.WriteLine($"thumbnail size: {thumbnailWidth}x{thumbnailHeight}"); |
|
|
|
|
|
|
|
GL.ClearColor(0f, 0f, 0f, 1f); |
|
|
|
|
|
|
|
VertexArrayObject = GL.GenVertexArray(); |
|
|
@ -262,8 +274,8 @@ public class Game : GameWindow { |
|
|
|
shader = new Shader(); |
|
|
|
shader.Use(); |
|
|
|
|
|
|
|
// Because there's now 5 floats between the start of the first vertex and the start of the second,
|
|
|
|
// we modify the stride from 3 * sizeof(float) to 5 * sizeof(float).
|
|
|
|
// Because there's 5 floats between the start of the first vertex and the start of the second,
|
|
|
|
// the stride is 5 * sizeof(float).
|
|
|
|
// This will now pass the new vertex array to the buffer.
|
|
|
|
var vertexLocation = shader.GetAttribLocation("aPosition"); |
|
|
|
GL.EnableVertexAttribArray(vertexLocation); |
|
|
@ -276,8 +288,8 @@ public class Game : GameWindow { |
|
|
|
GL.EnableVertexAttribArray(texCoordLocation); |
|
|
|
GL.VertexAttribPointer(texCoordLocation, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 3 * sizeof(float)); |
|
|
|
|
|
|
|
// Load blank white texture.
|
|
|
|
Image<Rgba32> white1x1 = new Image<Rgba32>(1, 1, new Rgba32(255, 255, 255)); |
|
|
|
// Create a blank white texture.
|
|
|
|
Image<Rgba32> white1x1 = new(1, 1, new Rgba32(255, 255, 255)); |
|
|
|
TEXTURE_WHITE = new Texture(white1x1); |
|
|
|
|
|
|
|
// Load textures from JPEGs.
|
|
|
@ -294,26 +306,22 @@ public class Game : GameWindow { |
|
|
|
base.OnUnload(); |
|
|
|
} |
|
|
|
|
|
|
|
private static Box2i makeBox(int left, int top, int width, int height) { |
|
|
|
return new Box2i(left, top, left + width, top + height); |
|
|
|
} |
|
|
|
|
|
|
|
protected override void OnRenderFrame(FrameEventArgs e) { |
|
|
|
base.OnRenderFrame(e); |
|
|
|
GL.Clear(ClearBufferMask.ColorBufferBit); |
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBufferObject); |
|
|
|
GL.ActiveTexture(TextureUnit.Texture0); |
|
|
|
|
|
|
|
int maxPhotoWidth = geometry.WindowSize.X - thumbnailWidth; |
|
|
|
int maxPhotoWidth = geometry.WindowSize.X - geometry.ThumbnailBoxes[0].Size.X; // FIXME
|
|
|
|
|
|
|
|
Texture active = textures[textureIndex]; |
|
|
|
// TODO: handle the case where we need to letterbox vertically instead.
|
|
|
|
int photoWidth = (int) (1.0 * geometry.WindowSize.Y / active.Height * active.Width); |
|
|
|
int letterboxWidth = (maxPhotoWidth - photoWidth) / 2; |
|
|
|
|
|
|
|
DrawTexture(active, makeBox(letterboxWidth, 0, photoWidth, geometry.WindowSize.Y)); |
|
|
|
DrawTexture(active, Util.makeBox(letterboxWidth, 0, photoWidth, geometry.WindowSize.Y)); |
|
|
|
for (int i = 0; i < textures.Count; i++) { |
|
|
|
Box2i box = makeBox(geometry.WindowSize.X - thumbnailWidth, i * thumbnailHeight, thumbnailWidth, thumbnailHeight); |
|
|
|
Box2i box = geometry.ThumbnailBoxes[i]; |
|
|
|
DrawTexture(textures[i], box); |
|
|
|
if (i == textureIndex) { |
|
|
|
DrawBox(box, 5, Color4.Black); |
|
|
@ -337,10 +345,10 @@ public class Game : GameWindow { |
|
|
|
} |
|
|
|
|
|
|
|
void DrawBox(Box2i box, int thickness, Color4 color) { |
|
|
|
DrawTexture(TEXTURE_WHITE, makeBox(box.Min.X, box.Min.Y, box.Size.X, thickness), color); |
|
|
|
DrawTexture(TEXTURE_WHITE, makeBox(box.Min.X, box.Min.Y, thickness, box.Size.Y), color); |
|
|
|
DrawTexture(TEXTURE_WHITE, makeBox(box.Min.X, box.Max.Y - thickness, box.Size.X, thickness), color); |
|
|
|
DrawTexture(TEXTURE_WHITE, makeBox(box.Max.X - thickness, box.Min.Y, thickness, box.Size.Y), color); |
|
|
|
DrawTexture(TEXTURE_WHITE, Util.makeBox(box.Min.X, box.Min.Y, box.Size.X, thickness), color); |
|
|
|
DrawTexture(TEXTURE_WHITE, Util.makeBox(box.Min.X, box.Min.Y, thickness, box.Size.Y), color); |
|
|
|
DrawTexture(TEXTURE_WHITE, Util.makeBox(box.Min.X, box.Max.Y - thickness, box.Size.X, thickness), color); |
|
|
|
DrawTexture(TEXTURE_WHITE, Util.makeBox(box.Max.X - thickness, box.Min.Y, thickness, box.Size.Y), color); |
|
|
|
} |
|
|
|
|
|
|
|
protected override void OnResize(ResizeEventArgs e) { |
|
|
@ -399,10 +407,10 @@ static class Program { |
|
|
|
} |
|
|
|
} |
|
|
|
Console.WriteLine($"best monitor: {bestMonitor.HorizontalResolution}x{bestMonitor.VerticalResolution}"); |
|
|
|
GameWindowSettings gwSettings = new GameWindowSettings(); |
|
|
|
GameWindowSettings gwSettings = new(); |
|
|
|
gwSettings.RenderFrequency = 60.0; |
|
|
|
|
|
|
|
NativeWindowSettings nwSettings = new NativeWindowSettings(); |
|
|
|
NativeWindowSettings nwSettings = new(); |
|
|
|
nwSettings.WindowState = WindowState.Normal; |
|
|
|
nwSettings.CurrentMonitor = bestMonitor.Handle; |
|
|
|
nwSettings.Location = new Vector2i(bestMonitor.WorkArea.Min.X + 1, bestMonitor.WorkArea.Min.Y + 31); |
|
|
|