Colin McMillen
1 year ago
1 changed files with 366 additions and 366 deletions
-
732Program.cs
@ -1,366 +1,366 @@ |
|||
using OpenTK.Graphics.OpenGL4; |
|||
using OpenTK.Mathematics; |
|||
using OpenTK.Windowing.Common; |
|||
using OpenTK.Windowing.Desktop; |
|||
using OpenTK.Windowing.GraphicsLibraryFramework; |
|||
// https://docs.sixlabors.com/api/ImageSharp/SixLabors.ImageSharp.Image.html
|
|||
using SixLabors.ImageSharp; |
|||
using SixLabors.ImageSharp.Metadata.Profiles.Exif; |
|||
using System.IO; |
|||
using System.Reflection.Metadata; |
|||
using System.Runtime.CompilerServices; |
|||
using static System.Runtime.InteropServices.JavaScript.JSType; |
|||
using System.Xml.Linq; |
|||
using Image = SixLabors.ImageSharp.Image; |
|||
|
|||
namespace SemiColinGames; |
|||
|
|||
public class Shader : IDisposable { |
|||
int Handle; |
|||
|
|||
public Shader() { |
|||
int VertexShader; |
|||
int FragmentShader; |
|||
|
|||
string VertexShaderSource = @"
|
|||
#version 330 |
|||
|
|||
layout(location = 0) in vec3 aPosition; |
|||
layout(location = 1) in vec2 aTexCoord; |
|||
|
|||
out vec2 texCoord; |
|||
|
|||
uniform mat4 projection; |
|||
|
|||
void main(void) { |
|||
texCoord = aTexCoord; |
|||
gl_Position = vec4(aPosition, 1.0) * projection; |
|||
}";
|
|||
|
|||
string FragmentShaderSource = @"
|
|||
#version 330 |
|||
|
|||
out vec4 outputColor; |
|||
in vec2 texCoord; |
|||
uniform sampler2D texture0; |
|||
|
|||
void main() { |
|||
outputColor = texture(texture0, texCoord); |
|||
}";
|
|||
|
|||
VertexShader = GL.CreateShader(ShaderType.VertexShader); |
|||
GL.ShaderSource(VertexShader, VertexShaderSource); |
|||
|
|||
FragmentShader = GL.CreateShader(ShaderType.FragmentShader); |
|||
GL.ShaderSource(FragmentShader, FragmentShaderSource); |
|||
|
|||
GL.CompileShader(VertexShader); |
|||
|
|||
int success; |
|||
GL.GetShader(VertexShader, ShaderParameter.CompileStatus, out success); |
|||
if (success == 0) { |
|||
string infoLog = GL.GetShaderInfoLog(VertexShader); |
|||
Console.WriteLine(infoLog); |
|||
} |
|||
|
|||
GL.CompileShader(FragmentShader); |
|||
|
|||
GL.GetShader(FragmentShader, ShaderParameter.CompileStatus, out success); |
|||
if (success == 0) { |
|||
string infoLog = GL.GetShaderInfoLog(FragmentShader); |
|||
Console.WriteLine(infoLog); |
|||
} |
|||
Handle = GL.CreateProgram(); |
|||
|
|||
GL.AttachShader(Handle, VertexShader); |
|||
GL.AttachShader(Handle, FragmentShader); |
|||
|
|||
GL.LinkProgram(Handle); |
|||
|
|||
GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out success); |
|||
if (success == 0) { |
|||
string infoLog = GL.GetProgramInfoLog(Handle); |
|||
Console.WriteLine(infoLog); |
|||
} |
|||
|
|||
GL.DetachShader(Handle, VertexShader); |
|||
GL.DetachShader(Handle, FragmentShader); |
|||
GL.DeleteShader(FragmentShader); |
|||
GL.DeleteShader(VertexShader); |
|||
} |
|||
|
|||
public void Use() { |
|||
GL.UseProgram(Handle); |
|||
} |
|||
|
|||
private bool disposedValue = false; |
|||
|
|||
protected virtual void Dispose(bool disposing) { |
|||
if (!disposedValue) { |
|||
GL.DeleteProgram(Handle); |
|||
disposedValue = true; |
|||
} |
|||
} |
|||
|
|||
~Shader() { |
|||
if (disposedValue == false) { |
|||
Console.WriteLine("~Shader(): resource leak? Dispose() should be called manually."); |
|||
} |
|||
} |
|||
|
|||
public void Dispose() { |
|||
Dispose(true); |
|||
GC.SuppressFinalize(this); |
|||
} |
|||
|
|||
public int GetAttribLocation(string name) { |
|||
return GL.GetAttribLocation(Handle, name); |
|||
} |
|||
|
|||
public int GetUniformLocation(string name) { |
|||
return GL.GetUniformLocation(Handle, name); |
|||
} |
|||
|
|||
} |
|||
|
|||
public class Texture : IDisposable { |
|||
public int Handle; |
|||
|
|||
public Texture(string path) { |
|||
Image<Rgba32> image = Image.Load<Rgba32>(path); |
|||
Console.WriteLine($"image loaded: {image.Width}x{image.Height}"); |
|||
//foreach (IExifValue exif in image.Metadata.ExifProfile.Values) {
|
|||
// Console.WriteLine($"{exif.Tag} : {exif.GetValue()}");
|
|||
//}
|
|||
byte[] pixelBytes = new byte[image.Width * image.Height * Unsafe.SizeOf<Rgba32>()]; |
|||
image.CopyPixelDataTo(pixelBytes); |
|||
image.Dispose(); |
|||
|
|||
Handle = GL.GenTexture(); |
|||
GL.ActiveTexture(TextureUnit.Texture0); |
|||
GL.BindTexture(TextureTarget.Texture2D, Handle); |
|||
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, image.Width, image.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, pixelBytes); |
|||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.LinearMipmapLinear); // FIXME: is this right?
|
|||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) TextureMagFilter.Nearest); |
|||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) TextureWrapMode.ClampToBorder); |
|||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToBorder); |
|||
float[] borderColor = { 0.0f, 0.0f, 0.0f, 1.0f }; |
|||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, borderColor); |
|||
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); |
|||
} |
|||
|
|||
private bool disposedValue = false; |
|||
|
|||
protected virtual void Dispose(bool disposing) { |
|||
if (!disposedValue) { |
|||
GL.DeleteTexture(Handle); |
|||
disposedValue = true; |
|||
} |
|||
} |
|||
|
|||
~Texture() { |
|||
if (!disposedValue) { |
|||
Console.WriteLine("~Texture(): resource leak? Dispose() should be called manually."); |
|||
} |
|||
} |
|||
|
|||
public void Dispose() { |
|||
Dispose(true); |
|||
GC.SuppressFinalize(this); |
|||
} |
|||
} |
|||
|
|||
public class Game : GameWindow { |
|||
public Game(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings) { } |
|||
|
|||
int frameCount; |
|||
int windowWidth; |
|||
int windowHeight; |
|||
float[] vertices = { |
|||
// Position Texture coordinates
|
|||
0f, 0f, 0.0f, 0.0f, 0.0f, // top left
|
|||
2560f, 0f, 0.0f, 1.0f, 0.0f, // top right
|
|||
2560f, 1440f, 0.0f, 1.0f, 1.0f, // bottom right
|
|||
0f, 1440f, 0.0f, 0.0f, 1.0f, // bottom left
|
|||
}; |
|||
|
|||
uint[] indices = { |
|||
0, 1, 3, // first triangle
|
|||
1, 2, 3 // second triangle
|
|||
}; |
|||
|
|||
int VertexBufferObject; |
|||
int ElementBufferObject; |
|||
int VertexArrayObject; |
|||
List<Texture> textures; |
|||
int textureIndex = 0; |
|||
Shader shader; |
|||
Matrix4 projection; |
|||
|
|||
protected override void OnUpdateFrame(FrameEventArgs e) { |
|||
base.OnUpdateFrame(e); |
|||
|
|||
KeyboardState input = KeyboardState; |
|||
|
|||
if (input.IsKeyDown(Keys.Escape)) { |
|||
Close(); |
|||
} |
|||
|
|||
if (input.IsKeyPressed(Keys.Down)) { |
|||
if (textureIndex < textures.Count - 1) { |
|||
textureIndex++; |
|||
} |
|||
} |
|||
if (input.IsKeyPressed(Keys.Up)) { |
|||
if (textureIndex > 0) { |
|||
textureIndex--; |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected override void OnLoad() { |
|||
base.OnLoad(); |
|||
|
|||
GL.ClearColor(0.0f, 0.0f, 0.05f, 1.0f); |
|||
|
|||
VertexArrayObject = GL.GenVertexArray(); |
|||
GL.BindVertexArray(VertexArrayObject); |
|||
|
|||
VertexBufferObject = GL.GenBuffer(); |
|||
ElementBufferObject = GL.GenBuffer(); |
|||
|
|||
GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBufferObject); |
|||
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.DynamicDraw); |
|||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ElementBufferObject); |
|||
GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(uint), indices, BufferUsageHint.DynamicDraw); |
|||
|
|||
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).
|
|||
// This will now pass the new vertex array to the buffer.
|
|||
var vertexLocation = shader.GetAttribLocation("aPosition"); |
|||
GL.EnableVertexAttribArray(vertexLocation); |
|||
GL.VertexAttribPointer(vertexLocation, 3, VertexAttribPointerType.Float, false, 5 * sizeof(float), 0); |
|||
|
|||
// Next, we also setup texture coordinates. It works in much the same way.
|
|||
// We add an offset of 3, since the texture coordinates comes after the position data.
|
|||
// We also change the amount of data to 2 because there's only 2 floats for texture coordinates.
|
|||
var texCoordLocation = shader.GetAttribLocation("aTexCoord"); |
|||
GL.EnableVertexAttribArray(texCoordLocation); |
|||
GL.VertexAttribPointer(texCoordLocation, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 3 * sizeof(float)); |
|||
|
|||
// Load textures from JPEGs.
|
|||
string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\06\27\"); |
|||
textures = new List<Texture>(); |
|||
foreach (string file in files) { |
|||
if (file.ToLower().EndsWith(".jpg")) { |
|||
textures.Add(new Texture(file)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected override void OnUnload() { |
|||
base.OnUnload(); |
|||
} |
|||
|
|||
protected override void OnRenderFrame(FrameEventArgs e) { |
|||
base.OnRenderFrame(e); |
|||
frameCount++; |
|||
GL.Clear(ClearBufferMask.ColorBufferBit); |
|||
|
|||
SetVertices(0, 0, windowWidth - 152, windowHeight); |
|||
GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBufferObject); |
|||
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.DynamicDraw); |
|||
GL.ActiveTexture(TextureUnit.Texture0); |
|||
GL.BindTexture(TextureTarget.Texture2D, textures[textureIndex].Handle); |
|||
shader.Use(); |
|||
GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); |
|||
|
|||
for (int i = 0; i < textures.Count; i++) { |
|||
SetVertices(windowWidth - 150, i * 100, windowWidth, i * 100 + 98); |
|||
GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBufferObject); |
|||
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.DynamicDraw); |
|||
GL.ActiveTexture(TextureUnit.Texture0); |
|||
GL.BindTexture(TextureTarget.Texture2D, textures[i].Handle); |
|||
shader.Use(); |
|||
GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); |
|||
} |
|||
|
|||
SwapBuffers(); |
|||
} |
|||
|
|||
protected override void OnResize(ResizeEventArgs e) { |
|||
base.OnResize(e); |
|||
Console.WriteLine($"OnResize: {e.Width}x{e.Height}"); |
|||
windowWidth = e.Width; |
|||
windowHeight = e.Height; |
|||
|
|||
projection = Matrix4.CreateOrthographicOffCenter(0f, windowWidth, windowHeight, 0f, -1f, 1f); |
|||
GL.UniformMatrix4(shader.GetUniformLocation("projection"), true, ref projection); |
|||
GL.Viewport(0, 0, windowWidth, windowHeight); |
|||
} |
|||
|
|||
private void SetVertices(float left, float top, float right, float bottom) { |
|||
// top left
|
|||
vertices[0] = left; |
|||
vertices[1] = top; |
|||
vertices[2] = 0f; |
|||
vertices[3] = 0f; |
|||
vertices[4] = 0f; |
|||
|
|||
// top right
|
|||
vertices[5] = right; |
|||
vertices[6] = top; |
|||
vertices[7] = 0f; |
|||
vertices[8] = 1f; |
|||
vertices[9] = 0f; |
|||
|
|||
// bottom right
|
|||
vertices[10] = right; |
|||
vertices[11] = bottom; |
|||
vertices[12] = 0f; |
|||
vertices[13] = 1f; |
|||
vertices[14] = 1f; |
|||
|
|||
// bottom left
|
|||
vertices[15] = left; |
|||
vertices[16] = bottom; |
|||
vertices[17] = 0f; |
|||
vertices[18] = 0f; |
|||
vertices[19] = 1f; |
|||
} |
|||
} |
|||
|
|||
static class Program { |
|||
static void Main(string[] args) { |
|||
List<MonitorInfo> monitors = Monitors.GetMonitors(); |
|||
MonitorInfo bestMonitor = monitors[0]; |
|||
int bestResolution = bestMonitor.HorizontalResolution * bestMonitor.VerticalResolution; |
|||
for (int i = 1; i < monitors.Count; i++) { |
|||
MonitorInfo monitor = monitors[i]; |
|||
int resolution = monitor.HorizontalResolution * monitor.VerticalResolution; |
|||
if (resolution > bestResolution) { |
|||
bestResolution = resolution; |
|||
bestMonitor = monitor; |
|||
} |
|||
} |
|||
Console.WriteLine($"best monitor: {bestMonitor.HorizontalResolution}x{bestMonitor.VerticalResolution}"); |
|||
GameWindowSettings gwSettings = new GameWindowSettings(); |
|||
gwSettings.RenderFrequency = 60.0; |
|||
|
|||
NativeWindowSettings nwSettings = new NativeWindowSettings(); |
|||
nwSettings.WindowState = WindowState.Normal; |
|||
nwSettings.CurrentMonitor = bestMonitor.Handle; |
|||
nwSettings.Location = new Vector2i(bestMonitor.WorkArea.Min.X + 1, bestMonitor.WorkArea.Min.Y + 31); |
|||
nwSettings.Size = new Vector2i(bestMonitor.WorkArea.Size.X - 2, bestMonitor.WorkArea.Size.Y - 32); |
|||
nwSettings.Title = "Totte"; |
|||
// FIXME: nwSettings.Icon = ...
|
|||
|
|||
using (Game game = new Game(gwSettings, nwSettings)) { |
|||
game.Run(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
using OpenTK.Graphics.OpenGL4; |
|||
using OpenTK.Mathematics; |
|||
using OpenTK.Windowing.Common; |
|||
using OpenTK.Windowing.Desktop; |
|||
using OpenTK.Windowing.GraphicsLibraryFramework; |
|||
// https://docs.sixlabors.com/api/ImageSharp/SixLabors.ImageSharp.Image.html
|
|||
using SixLabors.ImageSharp; |
|||
using SixLabors.ImageSharp.Metadata.Profiles.Exif; |
|||
using System.IO; |
|||
using System.Reflection.Metadata; |
|||
using System.Runtime.CompilerServices; |
|||
using static System.Runtime.InteropServices.JavaScript.JSType; |
|||
using System.Xml.Linq; |
|||
using Image = SixLabors.ImageSharp.Image; |
|||
|
|||
namespace SemiColinGames; |
|||
|
|||
public class Shader : IDisposable { |
|||
int Handle; |
|||
|
|||
public Shader() { |
|||
int VertexShader; |
|||
int FragmentShader; |
|||
|
|||
string VertexShaderSource = @"
|
|||
#version 330 |
|||
|
|||
layout(location = 0) in vec3 aPosition; |
|||
layout(location = 1) in vec2 aTexCoord; |
|||
|
|||
out vec2 texCoord; |
|||
|
|||
uniform mat4 projection; |
|||
|
|||
void main(void) { |
|||
texCoord = aTexCoord; |
|||
gl_Position = vec4(aPosition, 1.0) * projection; |
|||
}";
|
|||
|
|||
string FragmentShaderSource = @"
|
|||
#version 330 |
|||
|
|||
out vec4 outputColor; |
|||
in vec2 texCoord; |
|||
uniform sampler2D texture0; |
|||
|
|||
void main() { |
|||
outputColor = texture(texture0, texCoord); |
|||
}";
|
|||
|
|||
VertexShader = GL.CreateShader(ShaderType.VertexShader); |
|||
GL.ShaderSource(VertexShader, VertexShaderSource); |
|||
|
|||
FragmentShader = GL.CreateShader(ShaderType.FragmentShader); |
|||
GL.ShaderSource(FragmentShader, FragmentShaderSource); |
|||
|
|||
GL.CompileShader(VertexShader); |
|||
|
|||
int success; |
|||
GL.GetShader(VertexShader, ShaderParameter.CompileStatus, out success); |
|||
if (success == 0) { |
|||
string infoLog = GL.GetShaderInfoLog(VertexShader); |
|||
Console.WriteLine(infoLog); |
|||
} |
|||
|
|||
GL.CompileShader(FragmentShader); |
|||
|
|||
GL.GetShader(FragmentShader, ShaderParameter.CompileStatus, out success); |
|||
if (success == 0) { |
|||
string infoLog = GL.GetShaderInfoLog(FragmentShader); |
|||
Console.WriteLine(infoLog); |
|||
} |
|||
Handle = GL.CreateProgram(); |
|||
|
|||
GL.AttachShader(Handle, VertexShader); |
|||
GL.AttachShader(Handle, FragmentShader); |
|||
|
|||
GL.LinkProgram(Handle); |
|||
|
|||
GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out success); |
|||
if (success == 0) { |
|||
string infoLog = GL.GetProgramInfoLog(Handle); |
|||
Console.WriteLine(infoLog); |
|||
} |
|||
|
|||
GL.DetachShader(Handle, VertexShader); |
|||
GL.DetachShader(Handle, FragmentShader); |
|||
GL.DeleteShader(FragmentShader); |
|||
GL.DeleteShader(VertexShader); |
|||
} |
|||
|
|||
public void Use() { |
|||
GL.UseProgram(Handle); |
|||
} |
|||
|
|||
private bool disposedValue = false; |
|||
|
|||
protected virtual void Dispose(bool disposing) { |
|||
if (!disposedValue) { |
|||
GL.DeleteProgram(Handle); |
|||
disposedValue = true; |
|||
} |
|||
} |
|||
|
|||
~Shader() { |
|||
if (disposedValue == false) { |
|||
Console.WriteLine("~Shader(): resource leak? Dispose() should be called manually."); |
|||
} |
|||
} |
|||
|
|||
public void Dispose() { |
|||
Dispose(true); |
|||
GC.SuppressFinalize(this); |
|||
} |
|||
|
|||
public int GetAttribLocation(string name) { |
|||
return GL.GetAttribLocation(Handle, name); |
|||
} |
|||
|
|||
public int GetUniformLocation(string name) { |
|||
return GL.GetUniformLocation(Handle, name); |
|||
} |
|||
|
|||
} |
|||
|
|||
public class Texture : IDisposable { |
|||
public int Handle; |
|||
|
|||
public Texture(string path) { |
|||
Image<Rgba32> image = Image.Load<Rgba32>(path); |
|||
Console.WriteLine($"image loaded: {image.Width}x{image.Height}"); |
|||
//foreach (IExifValue exif in image.Metadata.ExifProfile.Values) {
|
|||
// Console.WriteLine($"{exif.Tag} : {exif.GetValue()}");
|
|||
//}
|
|||
byte[] pixelBytes = new byte[image.Width * image.Height * Unsafe.SizeOf<Rgba32>()]; |
|||
image.CopyPixelDataTo(pixelBytes); |
|||
image.Dispose(); |
|||
|
|||
Handle = GL.GenTexture(); |
|||
GL.ActiveTexture(TextureUnit.Texture0); |
|||
GL.BindTexture(TextureTarget.Texture2D, Handle); |
|||
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, image.Width, image.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, pixelBytes); |
|||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.LinearMipmapLinear); // FIXME: is this right?
|
|||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) TextureMagFilter.Nearest); |
|||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) TextureWrapMode.ClampToBorder); |
|||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToBorder); |
|||
float[] borderColor = { 0.0f, 0.0f, 0.0f, 1.0f }; |
|||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, borderColor); |
|||
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); |
|||
} |
|||
|
|||
private bool disposedValue = false; |
|||
|
|||
protected virtual void Dispose(bool disposing) { |
|||
if (!disposedValue) { |
|||
GL.DeleteTexture(Handle); |
|||
disposedValue = true; |
|||
} |
|||
} |
|||
|
|||
~Texture() { |
|||
if (!disposedValue) { |
|||
Console.WriteLine("~Texture(): resource leak? Dispose() should be called manually."); |
|||
} |
|||
} |
|||
|
|||
public void Dispose() { |
|||
Dispose(true); |
|||
GC.SuppressFinalize(this); |
|||
} |
|||
} |
|||
|
|||
public class Game : GameWindow { |
|||
public Game(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings) { } |
|||
|
|||
int frameCount; |
|||
int windowWidth; |
|||
int windowHeight; |
|||
float[] vertices = { |
|||
// Position Texture coordinates
|
|||
0f, 0f, 0.0f, 0.0f, 0.0f, // top left
|
|||
2560f, 0f, 0.0f, 1.0f, 0.0f, // top right
|
|||
2560f, 1440f, 0.0f, 1.0f, 1.0f, // bottom right
|
|||
0f, 1440f, 0.0f, 0.0f, 1.0f, // bottom left
|
|||
}; |
|||
|
|||
uint[] indices = { |
|||
0, 1, 3, // first triangle
|
|||
1, 2, 3 // second triangle
|
|||
}; |
|||
|
|||
int VertexBufferObject; |
|||
int ElementBufferObject; |
|||
int VertexArrayObject; |
|||
List<Texture> textures; |
|||
int textureIndex = 0; |
|||
Shader shader; |
|||
Matrix4 projection; |
|||
|
|||
protected override void OnUpdateFrame(FrameEventArgs e) { |
|||
base.OnUpdateFrame(e); |
|||
|
|||
KeyboardState input = KeyboardState; |
|||
|
|||
if (input.IsKeyDown(Keys.Escape)) { |
|||
Close(); |
|||
} |
|||
|
|||
if (input.IsKeyPressed(Keys.Down)) { |
|||
if (textureIndex < textures.Count - 1) { |
|||
textureIndex++; |
|||
} |
|||
} |
|||
if (input.IsKeyPressed(Keys.Up)) { |
|||
if (textureIndex > 0) { |
|||
textureIndex--; |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected override void OnLoad() { |
|||
base.OnLoad(); |
|||
|
|||
GL.ClearColor(0.0f, 0.0f, 0.05f, 1.0f); |
|||
|
|||
VertexArrayObject = GL.GenVertexArray(); |
|||
GL.BindVertexArray(VertexArrayObject); |
|||
|
|||
VertexBufferObject = GL.GenBuffer(); |
|||
ElementBufferObject = GL.GenBuffer(); |
|||
|
|||
GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBufferObject); |
|||
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.DynamicDraw); |
|||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ElementBufferObject); |
|||
GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(uint), indices, BufferUsageHint.DynamicDraw); |
|||
|
|||
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).
|
|||
// This will now pass the new vertex array to the buffer.
|
|||
var vertexLocation = shader.GetAttribLocation("aPosition"); |
|||
GL.EnableVertexAttribArray(vertexLocation); |
|||
GL.VertexAttribPointer(vertexLocation, 3, VertexAttribPointerType.Float, false, 5 * sizeof(float), 0); |
|||
|
|||
// Next, we also setup texture coordinates. It works in much the same way.
|
|||
// We add an offset of 3, since the texture coordinates comes after the position data.
|
|||
// We also change the amount of data to 2 because there's only 2 floats for texture coordinates.
|
|||
var texCoordLocation = shader.GetAttribLocation("aTexCoord"); |
|||
GL.EnableVertexAttribArray(texCoordLocation); |
|||
GL.VertexAttribPointer(texCoordLocation, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 3 * sizeof(float)); |
|||
|
|||
// Load textures from JPEGs.
|
|||
string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\06\27\"); |
|||
textures = new List<Texture>(); |
|||
foreach (string file in files) { |
|||
if (file.ToLower().EndsWith(".jpg")) { |
|||
textures.Add(new Texture(file)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected override void OnUnload() { |
|||
base.OnUnload(); |
|||
} |
|||
|
|||
protected override void OnRenderFrame(FrameEventArgs e) { |
|||
base.OnRenderFrame(e); |
|||
frameCount++; |
|||
GL.Clear(ClearBufferMask.ColorBufferBit); |
|||
|
|||
SetVertices(0, 0, windowWidth - 152, windowHeight); |
|||
GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBufferObject); |
|||
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.DynamicDraw); |
|||
GL.ActiveTexture(TextureUnit.Texture0); |
|||
GL.BindTexture(TextureTarget.Texture2D, textures[textureIndex].Handle); |
|||
shader.Use(); |
|||
GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); |
|||
|
|||
for (int i = 0; i < textures.Count; i++) { |
|||
SetVertices(windowWidth - 150, i * 100, windowWidth, i * 100 + 98); |
|||
GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBufferObject); |
|||
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.DynamicDraw); |
|||
GL.ActiveTexture(TextureUnit.Texture0); |
|||
GL.BindTexture(TextureTarget.Texture2D, textures[i].Handle); |
|||
shader.Use(); |
|||
GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); |
|||
} |
|||
|
|||
SwapBuffers(); |
|||
} |
|||
|
|||
protected override void OnResize(ResizeEventArgs e) { |
|||
base.OnResize(e); |
|||
Console.WriteLine($"OnResize: {e.Width}x{e.Height}"); |
|||
windowWidth = e.Width; |
|||
windowHeight = e.Height; |
|||
|
|||
projection = Matrix4.CreateOrthographicOffCenter(0f, windowWidth, windowHeight, 0f, -1f, 1f); |
|||
GL.UniformMatrix4(shader.GetUniformLocation("projection"), true, ref projection); |
|||
GL.Viewport(0, 0, windowWidth, windowHeight); |
|||
} |
|||
|
|||
private void SetVertices(float left, float top, float right, float bottom) { |
|||
// top left
|
|||
vertices[0] = left; |
|||
vertices[1] = top; |
|||
vertices[2] = 0f; |
|||
vertices[3] = 0f; |
|||
vertices[4] = 0f; |
|||
|
|||
// top right
|
|||
vertices[5] = right; |
|||
vertices[6] = top; |
|||
vertices[7] = 0f; |
|||
vertices[8] = 1f; |
|||
vertices[9] = 0f; |
|||
|
|||
// bottom right
|
|||
vertices[10] = right; |
|||
vertices[11] = bottom; |
|||
vertices[12] = 0f; |
|||
vertices[13] = 1f; |
|||
vertices[14] = 1f; |
|||
|
|||
// bottom left
|
|||
vertices[15] = left; |
|||
vertices[16] = bottom; |
|||
vertices[17] = 0f; |
|||
vertices[18] = 0f; |
|||
vertices[19] = 1f; |
|||
} |
|||
} |
|||
|
|||
static class Program { |
|||
static void Main(string[] args) { |
|||
List<MonitorInfo> monitors = Monitors.GetMonitors(); |
|||
MonitorInfo bestMonitor = monitors[0]; |
|||
int bestResolution = bestMonitor.HorizontalResolution * bestMonitor.VerticalResolution; |
|||
for (int i = 1; i < monitors.Count; i++) { |
|||
MonitorInfo monitor = monitors[i]; |
|||
int resolution = monitor.HorizontalResolution * monitor.VerticalResolution; |
|||
if (resolution > bestResolution) { |
|||
bestResolution = resolution; |
|||
bestMonitor = monitor; |
|||
} |
|||
} |
|||
Console.WriteLine($"best monitor: {bestMonitor.HorizontalResolution}x{bestMonitor.VerticalResolution}"); |
|||
GameWindowSettings gwSettings = new GameWindowSettings(); |
|||
gwSettings.RenderFrequency = 60.0; |
|||
|
|||
NativeWindowSettings nwSettings = new NativeWindowSettings(); |
|||
nwSettings.WindowState = WindowState.Normal; |
|||
nwSettings.CurrentMonitor = bestMonitor.Handle; |
|||
nwSettings.Location = new Vector2i(bestMonitor.WorkArea.Min.X + 1, bestMonitor.WorkArea.Min.Y + 31); |
|||
nwSettings.Size = new Vector2i(bestMonitor.WorkArea.Size.X - 2, bestMonitor.WorkArea.Size.Y - 32); |
|||
nwSettings.Title = "Totte"; |
|||
// FIXME: nwSettings.Icon = ...
|
|||
|
|||
using (Game game = new Game(gwSettings, nwSettings)) { |
|||
game.Run(); |
|||
} |
|||
} |
|||
} |
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue