2025-11-24 15:14:10 +00:00

134 lines
4.7 KiB
C#

namespace TheLabs;
using LearnOpenTK.Common;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using System;
public class Mesh : IDisposable
{
private readonly int _vao;
private readonly int _vbo;
private readonly int _ebo;
private readonly int _vertexCount;
private readonly bool _useIndices;
public enum VertexLayout { PosColor, PosTex, PosTexNormal }
public Mesh(float[] vertices, uint[] indices, VertexLayout layout)
{
_vertexCount = indices.Length;
_useIndices = true;
_vao = GL.GenVertexArray();
GL.BindVertexArray(_vao);
_vbo = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo);
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw);
_ebo = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _ebo);
GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(uint), indices, BufferUsageHint.StaticDraw);
SetupAttributes(layout); // Refactored into a helper method to avoid duplication
GL.BindVertexArray(0);
}
public Mesh(float[] vertices, VertexLayout layout)
{
// Calculate vertex count based on the layout size
int strideCount = 0;
if (layout == VertexLayout.PosColor) strideCount = 7;
else if (layout == VertexLayout.PosTex) strideCount = 5;
else if (layout == VertexLayout.PosTexNormal) strideCount = 8;
_vertexCount = vertices.Length / strideCount;
_useIndices = false;
_ebo = 0;
_vao = GL.GenVertexArray();
GL.BindVertexArray(_vao);
_vbo = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo);
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw);
SetupAttributes(layout);
GL.BindVertexArray(0);
}
// Helper method to set up pointers (shared by both constructors)
private void SetupAttributes(VertexLayout layout)
{
if (layout == VertexLayout.PosColor)
{
// Stride = 7 floats (3 Pos + 4 Color)
var stride = 7 * sizeof(float);
// Location 0: Position
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
GL.EnableVertexAttribArray(0);
// Location 1: Color
GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
GL.EnableVertexAttribArray(2);
}
else if (layout == VertexLayout.PosTex)
{
// Stride = 5 floats (3 Pos + 2 Tex)
var stride = 5 * sizeof(float);
// Location 0: Position
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
GL.EnableVertexAttribArray(0);
// Location 2: TexCoord (I used 2 to match the Normal layout below, but 1 works too if you change shader)
// Let's keep it at 1 for now to break less code, but for lighting we usually move Tex to 2.
// For now, let's assume your shader uses Location 2 for Texture if using Normals.
GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
GL.EnableVertexAttribArray(2);
}
else if (layout == VertexLayout.PosTexNormal)
{
// Stride = 8 floats (3 Pos + 3 Normal + 2 Tex)
var stride = 8 * sizeof(float);
// Location 0: Position
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
GL.EnableVertexAttribArray(0);
// Location 1: Normal (Offset 3 floats)
GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
GL.EnableVertexAttribArray(1);
// Location 2: TexCoord (Offset 6 floats: 3 pos + 3 normal)
GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, stride, 6 * sizeof(float));
GL.EnableVertexAttribArray(2);
}
}
public void Draw()
{
GL.BindVertexArray(_vao);
if (_useIndices)
{
GL.DrawElements(PrimitiveType.Triangles, _vertexCount, DrawElementsType.UnsignedInt, 0);
}
else
{
GL.DrawArrays(PrimitiveType.TriangleFan, 0, _vertexCount);
}
}
public void Dispose()
{
GL.DeleteBuffer(_vbo);
GL.DeleteBuffer(_ebo);
GL.DeleteVertexArray(_vao);
}
}