using LearnOpenTK.Common; using OpenTK.Graphics.OpenGL4; using OpenTK.Mathematics; using OpenTK.Windowing.Desktop; using StbImageSharp; namespace TheLabs.Shapes; public class TexturedCube { // Vertex Array Object, Vertex Buffer Object, Element Buffer Object private int _vao; private int _vbo; private int _ebo; private int _tb; 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, 0f, 0f, // Bottom-left 0.5f, -0.5f, 0.5f, 1f, 0f, // Bottom-right 0.5f, 0.5f, 0.5f, 1f, 1f, // Top-right -0.5f, 0.5f, 0.5f, 0f, 1f, // Top-left // Back face (z = -0.5) -0.5f, -0.5f, -0.5f, 1f, 0f, // Bottom-left 0.5f, -0.5f, -0.5f, 0f, 0f, // Bottom-right 0.5f, 0.5f, -0.5f, 0f, 1f, // Top-right -0.5f, 0.5f, -0.5f, 1f, 1f, // Top-left // Left face (x = -0.5) -0.5f, -0.5f, -0.5f, 0f, 0f, // Bottom-left -0.5f, -0.5f, 0.5f, 1f, 0f, // Bottom-right -0.5f, 0.5f, 0.5f, 1f, 1f, // Top-right -0.5f, 0.5f, -0.5f, 0f, 1f, // Top-left // Right face (x = +0.5) 0.5f, -0.5f, -0.5f, 1f, 0f, // Bottom-left 0.5f, -0.5f, 0.5f, 0f, 0f, // Bottom-right 0.5f, 0.5f, 0.5f, 0f, 1f, // Top-right 0.5f, 0.5f, -0.5f, 1f, 1f, // Top-left // Top face (y = +0.5) -0.5f, 0.5f, -0.5f, 0f, 1f, // Bottom-left 0.5f, 0.5f, -0.5f, 1f, 1f, // Bottom-right 0.5f, 0.5f, 0.5f, 1f, 0f, // Top-right -0.5f, 0.5f, 0.5f, 0f, 0f, // Top-left // Bottom face (y = -0.5) -0.5f, -0.5f, -0.5f, 1f, 1f, // Bottom-left 0.5f, -0.5f, -0.5f, 0f, 1f, // Bottom-right 0.5f, -0.5f, 0.5f, 0f, 0f, // Top-right -0.5f, -0.5f, 0.5f, 1f, 0f, // Top-left }; private readonly uint[] _cubeIndices = { // Front face 0, 2, 1, 0, 2, 3, // Back face 4, 5, 6, 4, 6, 7, // Left face 8, 9, 10, 8, 10, 11, // Right face 12, 14, 13, 12, 14, 15, // Top face 16, 17, 18, 16, 18, 19, // Bottom face 20, 22, 21, 20, 22, 23 }; public TexturedCube() { _tb = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, _tb); StbImage.stbi_set_flip_vertically_on_load(1); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); // Load the image ImageResult image = ImageResult.FromStream(File.OpenRead("Textures/placeholder.png"), ColorComponents.RedGreenBlueAlpha); GL.TexImage2D(TextureTarget.Texture2D,0, PixelInternalFormat.Rgba, image.Width, image.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, image.Data); GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); // 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 = 5 * sizeof(float); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0); GL.EnableVertexAttribArray(0); GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 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); shader.Use(); GL.Uniform1(GL.GetUniformLocation(shader.Handle, "uTexture"), 0); GL.UniformMatrix4(GL.GetUniformLocation(shader.Handle, "model"), false, ref model); GL.UniformMatrix4(GL.GetUniformLocation(shader.Handle, "view"), false, ref view); GL.UniformMatrix4(GL.GetUniformLocation(shader.Handle, "projection"), false, ref projection); int texLoc = GL.GetUniformLocation(shader.Handle, "uTexture"); GL.Uniform1(texLoc, 0); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, _tb); GL.BindVertexArray(_vao); GL.DrawElements(PrimitiveType.Triangles, _vertexCount, DrawElementsType.UnsignedInt, 0); } public void Dispose() { GL.DeleteBuffer(_vbo); GL.DeleteBuffer(_ebo); GL.DeleteVertexArray(_vao); } }