using System; using gaemstone.ECS; using Silk.NET.Maths; using Silk.NET.OpenGL; using ModelRoot = SharpGLTF.Schema2.ModelRoot; namespace gaemstone.Client; public static class MeshManager { const uint PositionAttribIndex = 0; const uint NormalAttribIndex = 1; const uint UvAttribIndex = 2; public static Mesh Load(Universe universe, string name) { ModelRoot root; using (var stream = Resources.GetStream(name)) root = ModelRoot.ReadGLB(stream, new()); var primitive = root.LogicalMeshes[0].Primitives[0]; var indices = primitive.IndexAccessor; var vertices = primitive.VertexAccessors["POSITION"]; var normals = primitive.VertexAccessors["NORMAL"]; var GL = universe.Lookup().Get().GL; var vao = GL.GenVertexArray(); GL.BindVertexArray(vao); GL.CreateBufferFromData(indices.SourceBufferView.Content, BufferTargetARB.ElementArrayBuffer); GL.CreateBufferFromData(vertices.SourceBufferView.Content); GL.EnableVertexAttribArray(PositionAttribIndex); unsafe { GL.VertexAttribPointer(PositionAttribIndex, 3, (VertexAttribPointerType)vertices.Encoding, vertices.Normalized, (uint)vertices.SourceBufferView.ByteStride, (void*)vertices.ByteOffset); } GL.CreateBufferFromData(normals.SourceBufferView.Content); GL.EnableVertexAttribArray(NormalAttribIndex); unsafe { GL.VertexAttribPointer(NormalAttribIndex, 3, (VertexAttribPointerType)vertices.Encoding, vertices.Normalized, (uint)vertices.SourceBufferView.ByteStride, (void*)vertices.ByteOffset); } var numVertices = primitive.IndexAccessor.Count; return new(vao, numVertices); } public static Mesh Create(Universe universe, ReadOnlySpan indices, ReadOnlySpan> vertices, ReadOnlySpan> normals, ReadOnlySpan> uvs) { var GL = universe.Lookup().Get().GL; var vao = GL.GenVertexArray(); GL.BindVertexArray(vao); GL.CreateBufferFromData(indices, BufferTargetARB.ElementArrayBuffer); GL.CreateBufferFromData(vertices); GL.EnableVertexAttribArray(PositionAttribIndex); unsafe { GL.VertexAttribPointer(PositionAttribIndex, 3, VertexAttribPointerType.Float, false, 0, (void*)0); } if (!normals.IsEmpty) { GL.CreateBufferFromData(normals); GL.EnableVertexAttribArray(NormalAttribIndex); unsafe { GL.VertexAttribPointer(NormalAttribIndex, 3, VertexAttribPointerType.Float, false, 0, (void*)0); } } if (!uvs.IsEmpty) { GL.CreateBufferFromData(uvs); GL.EnableVertexAttribArray(UvAttribIndex); unsafe { GL.VertexAttribPointer(UvAttribIndex, 2, VertexAttribPointerType.Float, false, 0, (void*)0); } } return new(vao, indices.Length); } public static Mesh Create(Universe universe, ReadOnlySpan> vertices, ReadOnlySpan> normals, ReadOnlySpan> uvs) { var GL = universe.Lookup().Get().GL; var vao = GL.GenVertexArray(); GL.BindVertexArray(vao); GL.CreateBufferFromData(vertices); GL.EnableVertexAttribArray(PositionAttribIndex); unsafe { GL.VertexAttribPointer(PositionAttribIndex, 3, VertexAttribPointerType.Float, false, 0, (void*)0); } if (!normals.IsEmpty) { GL.CreateBufferFromData(normals); GL.EnableVertexAttribArray(NormalAttribIndex); unsafe { GL.VertexAttribPointer(NormalAttribIndex, 3, VertexAttribPointerType.Float, false, 0, (void*)0); } } if (!uvs.IsEmpty) { GL.CreateBufferFromData(uvs); GL.EnableVertexAttribArray(UvAttribIndex); unsafe { GL.VertexAttribPointer(UvAttribIndex, 2, VertexAttribPointerType.Float, false, 0, (void*)0); } } return new(vao, vertices.Length, false); } }