using System.Drawing; using static OpenGL.GL; namespace OpenGLTutorial.Rendering.Display { public class Shape { public int Mode { get; set; } public uint Vao { get; private set; } private uint Vbo { get; set; } private float[] Vertices { get; set; } private bool _loaded = false; public Shape(float[] vertices, int mode = GL_STATIC_DRAW) { Vertices = vertices; Mode = mode; } public unsafe void Load() { if (_loaded || Vertices.Length == 0) return; _loaded = true; Vao = glGenVertexArray(); Vbo = glGenBuffer(); glBindVertexArray(Vao); glBindBuffer(GL_ARRAY_BUFFER, Vbo); fixed (float* v = &Vertices[0]) { glBufferData(GL_ARRAY_BUFFER, sizeof(float) * Vertices.Length, v, Mode); } glVertexAttribPointer(0, 2, GL_FLOAT, false, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 4, GL_FLOAT, false, 8 * sizeof(float), (void*)(2 * sizeof(float))); glEnableVertexAttribArray(1); glVertexAttribPointer(2, 2, GL_FLOAT, false, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } public void Delete() { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); glDeleteBuffer(Vbo); glDeleteVertexArray(Vao); } public unsafe void SetVertices(float[] vertices) { Vertices = vertices; if (vertices.Length == 0) return; glBindVertexArray(Vao); glBindBuffer(GL_ARRAY_BUFFER, Vbo); fixed (float* v = &Vertices[0]) { glBufferData(GL_ARRAY_BUFFER, sizeof(float) * Vertices.Length, v, Mode); } glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } public int GetVertexCount() => Vertices.Length / 8; } public static class Shapes { public static float[] Rectangle => new[] { -0.5f, 0.5f, 1f, 1f, 1f, 1f, 0.0f, 1.0f, // top left 0.5f, 0.5f, 1f, 1f, 1f, 1f, 1.0f, 1.0f, // top right -0.5f, -0.5f, 1f, 1f, 1f, 1f, 0.0f, 0.0f, // bottom left 0.5f, 0.5f, 1f, 1f, 1f, 1f, 1.0f, 1.0f, // top right 0.5f, -0.5f, 1f, 1f, 1f, 1f, 1.0f, 0.0f, // bottom right -0.5f, -0.5f, 1f, 1f, 1f, 1f, 0.0f, 0.0f, // bottom left }; public static float[] Triangle => new[] { 0.0f, -0.5f, 1f, 1f, 1f, 1f, 0.5f, 1.0f, // top center 0.5f, 0.5f, 1f, 1f, 1f, 1f, 1.0f, 0.0f, // bottom right -0.5f, 0.5f, 1f, 1f, 1f, 1f, 0.0f, 0.0f, // bottom left }; public static float[] CreateRectangle(Dimensions position, Color color, Dimensions uv) => new[] { position.X, position.MaxY, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha(), uv.X, uv.MaxY, // top left position.MaxX, position.MaxY, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha(), uv.MaxX, uv.MaxY, // top right position.X, position.Y, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha(), uv.X, uv.Y, // bottom left position.MaxX, position.MaxY, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha(), uv.MaxX, uv.MaxY, // top right position.MaxX, position.Y, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha(), uv.MaxX, uv.Y, // bottom right position.X, position.Y, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha(), uv.X, uv.Y, // bottom left }; public static float[] CreateTriangle(Dimensions position, Color color, Dimensions uv) => new[] { position.CenterX, position.Y, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha(), uv.CenterX, uv.MaxY, // top center position.MaxX, position.MaxY, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha(), uv.MaxX, uv.Y, // bottom right position.X, position.MaxY, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha(), uv.X, uv.Y, // bottom left }; } public readonly struct Dimensions { public static Dimensions Identity => new (0.0f, 0.0f, 1.0f, 1.0f); public static Dimensions Centered => new (-0.5f, -0.5f, 1.0f, 1.0f); public float X { get; } public float Y { get; } public float Width { get; } public float Height { get; } public Dimensions(float x, float y, float width, float height) { X = x; Y = y; Width = width; Height = height; } public float MaxX => X + Width; public float MaxY => Y + Height; public float CenterX => X + (Width / 2.0f); public float CenterY => Y + (Height / 2.0f); } public static class ColorExtensions { private static float Map(float value, float min, float max, float mMin, float mMax) { float norm = (value - min) / (max - min); return (mMax - mMin) * norm + mMin; } public static float GetRed(this Color color) { return Map(color.R, 0, 255, 0, 1); } public static float GetGreen(this Color color) { return Map(color.G, 0, 255, 0, 1); } public static float GetBlue(this Color color) { return Map(color.B, 0, 255, 0, 1); } public static float GetAlpha(this Color color) { return Map(color.A, 0, 255, 0, 1); } } }