using LearnOpenTK.Common; using OpenTK.Graphics.OpenGL4; using OpenTK.Mathematics; using OpenTK.Windowing.Desktop; namespace TheLabs.Shapes; public class Cylinder { // Vertex Array Object, Vertex Buffer Object, Element Buffer Object private int _vao; private int _vbo; private int _ebo; private int _vertexCount; private Circle _topCircle; private Circle _bottomCircle; private float _radius = 0.5f; private float _height = 1.0f; private float[] _vertices = { }; private uint[] _indices = { }; public Cylinder() { // The number of vertices to draw _vertexCount = _indices.Length; _topCircle = new Circle(0.5f, 100, new Vector4(1f, 1f, 0f, 1f)); _bottomCircle = new Circle(-0.5f, 100, new Vector4(1f, 0f, 0f, 1f)); GenerateCylinder(100); } private void GenerateCylinder(int segments) { var vertices = new List(); var indices = new List(); for (int i = 0; i < segments; i++) { float angle1 = 2.0f * MathF.PI * i / segments; float angle2 = 2.0f * MathF.PI * ((i + 1) % segments) / segments; float x1 = _radius * MathF.Cos(angle1); float y1 = _radius * MathF.Sin(angle1); float x2 = _radius * MathF.Cos(angle2); float y2 = _radius * MathF.Sin(angle2); float zTop = _height / 2f; float zBottom = -_height / 2f; Vector4 sideColor = new Vector4(0f, 1f, 1f, 1f); // side color // Add vertices: top1, bottom1, top2, bottom2 int top1Index = vertices.Count / 7; vertices.AddRange(new float[] { x1, y1, zTop, sideColor.X, sideColor.Y, sideColor.Z, sideColor.W }); int bottom1Index = vertices.Count / 7; vertices.AddRange(new float[] { x1, y1, zBottom, sideColor.X, sideColor.Y, sideColor.Z, sideColor.W }); int top2Index = vertices.Count / 7; vertices.AddRange(new float[] { x2, y2, zTop, sideColor.X, sideColor.Y, sideColor.Z, sideColor.W }); int bottom2Index = vertices.Count / 7; vertices.AddRange(new float[] { x2, y2, zBottom, sideColor.X, sideColor.Y, sideColor.Z, sideColor.W }); // First triangle indices.Add((uint)top1Index); indices.Add((uint)bottom1Index); indices.Add((uint)top2Index); // Second triangle indices.Add((uint)top2Index); indices.Add((uint)bottom1Index); indices.Add((uint)bottom2Index); } _vertices = vertices.ToArray(); _indices = indices.ToArray(); _vertexCount = indices.Count; // OpenGL setup _vao = GL.GenVertexArray(); _vbo = GL.GenBuffer(); _ebo = GL.GenBuffer(); GL.BindVertexArray(_vao); GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); GL.BufferData(BufferTarget.ArrayBuffer, vertices.Count * sizeof(float), vertices.ToArray(), BufferUsageHint.StaticDraw); GL.BindBuffer(BufferTarget.ElementArrayBuffer, _ebo); GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Count * sizeof(uint), indices.ToArray(), BufferUsageHint.StaticDraw); 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 model, Matrix4 view, Matrix4 projection) { shader.SetMatrix4("model", model); // 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, _indices.Length, DrawElementsType.UnsignedInt, 0); _topCircle.Draw(shader, view, projection, model); _bottomCircle.Draw(shader, view, projection, model); } public void Dispose() { GL.DeleteBuffer(_vbo); GL.DeleteBuffer(_ebo); GL.DeleteVertexArray(_vao); } }