2025-11-11 14:28:12 +00:00

133 lines
4.5 KiB
C#

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, 10, new Vector4(1f, 1f, 0f, 1f));
_bottomCircle = new Circle(-0.5f, 10, new Vector4(1f, 0f, 0f, 1f));
GenerateCylinder(10);
}
private void GenerateCylinder(int segments)
{
var vertices = new List<float>();
var indices = new List<uint>();
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);
}
}