|
|
|
using System;
|
|
|
|
using System.IO;
|
|
|
|
using System.Numerics;
|
|
|
|
using gaemstone.ECS;
|
|
|
|
using Silk.NET.OpenGL;
|
|
|
|
using static gaemstone.Client.Components.RenderingComponents;
|
|
|
|
using static gaemstone.Client.Components.ResourceComponents;
|
|
|
|
using static gaemstone.Client.Systems.Windowing;
|
|
|
|
using ModelRoot = SharpGLTF.Schema2.ModelRoot;
|
|
|
|
|
|
|
|
namespace gaemstone.Client.Systems;
|
|
|
|
|
|
|
|
[Module]
|
|
|
|
[DependsOn<gaemstone.Client.Components.RenderingComponents>]
|
|
|
|
[DependsOn<gaemstone.Client.Components.ResourceComponents>]
|
|
|
|
[DependsOn<gaemstone.Client.Systems.Windowing>]
|
|
|
|
public class MeshManager
|
|
|
|
{
|
|
|
|
private const uint PositionAttribIndex = 0;
|
|
|
|
private const uint NormalAttribIndex = 1;
|
|
|
|
private const uint UvAttribIndex = 2;
|
|
|
|
|
|
|
|
[System]
|
|
|
|
public static void LoadMeshWhenDefined(
|
|
|
|
[Game] Canvas canvas, EntityRef entity,
|
|
|
|
Mesh _1, [Not] MeshHandle _2)
|
|
|
|
{
|
|
|
|
var path = entity.GetFullPath();
|
|
|
|
using var stream = Resources.GetStream(path);
|
|
|
|
var handle = CreateFromStream(canvas.GL, stream);
|
|
|
|
entity.Set(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static MeshHandle CreateFromStream(GL GL, Stream stream)
|
|
|
|
{
|
|
|
|
var root = ModelRoot.ReadGLB(stream);
|
|
|
|
var primitive = root.LogicalMeshes[0].Primitives[0];
|
|
|
|
|
|
|
|
var indices = primitive.IndexAccessor;
|
|
|
|
var vertices = primitive.VertexAccessors["POSITION"];
|
|
|
|
var normals = primitive.VertexAccessors["NORMAL"];
|
|
|
|
|
|
|
|
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 MeshHandle Create(GL GL,
|
|
|
|
ReadOnlySpan<ushort> indices, ReadOnlySpan<Vector3> vertices,
|
|
|
|
ReadOnlySpan<Vector3> normals, ReadOnlySpan<Vector2> uvs)
|
|
|
|
{
|
|
|
|
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 MeshHandle Create(GL GL, ReadOnlySpan<Vector3> vertices,
|
|
|
|
ReadOnlySpan<Vector3> normals, ReadOnlySpan<Vector2> uvs)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|