using LearnOpenTK.Common; using OpenTK.Graphics.OpenGL4; using OpenTK.Mathematics; using OpenTK.Windowing.Desktop; namespace TheLabs.Shapes; public class Cube { // Vertex Array Object, Vertex Buffer Object, Element Buffer Object private int _vao; private int _vbo; private int _ebo; private int _vertexCount; public Vector3 Position = Vector3.Zero; private readonly float[] _cubevertices = { // Position // Color (RGBA) // Front face (z = +0.5) -0.5f, -0.5f, 0.5f, 1f, 0f, 0f, 1f, // Bottom-left 0.5f, -0.5f, 0.5f, 1f, 0f, 0f, 1f, // Bottom-right 0.5f, 0.5f, 0.5f, 0f, 0f, 0f, 1f, // Top-right -0.5f, 0.5f, 0.5f, 1f, 0f, 0f, 1f, // Top-left // Back face (z = -0.5) -0.5f, -0.5f, -0.5f, 1f, 0f, 1f, 1f, // Bottom-left 0.5f, -0.5f, -0.5f, 0f, 1f, 1f, 1f, // Bottom-right 0.5f, 0.5f, -0.5f, 1f, 1f, 1f, 1f, // Top-right -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 1f // Top-left }; private readonly uint[] _cubeIndices = { // Front face 0, 1, 2, 2, 3, 0, // Back face 4, 5, 6, 6, 7, 4, // Left face 4, 0, 3, 3, 7, 4, // Right face 1, 5, 6, 6, 2, 1, // Top face 3, 2, 6, 6, 7, 3, // Bottom face 4, 5, 1, 1, 0, 4 }; public Cube() { // The number of vertices to draw _vertexCount = _cubeIndices.Length; // The Vertex Array Object // This stores the confifuration of vertex atributes _vao = GL.GenVertexArray(); // The Vertex Buffer Object // This stores the actual vertex data e.g. positions, colors, normals, texture coordinates _vbo = GL.GenBuffer(); // The Element Buffer Object, stores the indices for indexed drawing _ebo = GL.GenBuffer(); // We bind the VAO GL.BindVertexArray(_vao); GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); // Specifying the type of buffer // Uploading the vertex data to the GPU GL.BufferData(BufferTarget.ArrayBuffer, _cubevertices.Length * sizeof(float), _cubevertices, BufferUsageHint.StaticDraw); // Now we set up the EBO GL.BindBuffer(BufferTarget.ElementArrayBuffer, _ebo); // Uploading the index data to the GPU GL.BufferData(BufferTarget.ElementArrayBuffer, _cubeIndices.Length * sizeof(uint), _cubeIndices, BufferUsageHint.StaticDraw); // We tell opengl how to interpret the vertex data. // The Location 0 corresponds to the layout(location = 0) in the vertex shader // How many components (x, y, z) -> 3 // Data type -> float // Not normalized // The Stride -> The total size of a vertex (in bytes) // The offset -> The position data starts at the beginning of the vertex data so 0 var stride = 7 * sizeof(float); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0); GL.EnableVertexAttribArray(0); GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float)); GL.EnableVertexAttribArray(1); GL.BindVertexArray(0); } public void Draw(Shader shader, Matrix4 view, Matrix4 projection, float rotation) { // Create the model matrix with rotation and translation Matrix4 model = Matrix4.CreateRotationY(rotation) * Matrix4.CreateRotationX(rotation * 0.5f) * Matrix4.CreateTranslation(Position); // Set the matrices in the shader int modelLoc = GL.GetUniformLocation(shader.Handle, "model"); int viewLoc = GL.GetUniformLocation(shader.Handle, "view"); int projLoc = GL.GetUniformLocation(shader.Handle, "projection"); // Send the matrices to the shader GL.UniformMatrix4(modelLoc, false, ref model); GL.UniformMatrix4(viewLoc, false, ref view); GL.UniformMatrix4(projLoc, false, ref projection); GL.BindVertexArray(_vao); GL.DrawElements(PrimitiveType.Triangles, _cubeIndices.Length, DrawElementsType.UnsignedInt, 0); } public void Dispose() { GL.DeleteBuffer(_vbo); GL.DeleteBuffer(_ebo); GL.DeleteVertexArray(_vao); } }