feat(app): render static meshes from Holtburg LandBlockInfo
This commit is contained in:
parent
cefc689ba8
commit
1375780e14
4 changed files with 232 additions and 0 deletions
134
src/AcDream.App/Rendering/StaticMeshRenderer.cs
Normal file
134
src/AcDream.App/Rendering/StaticMeshRenderer.cs
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
// src/AcDream.App/Rendering/StaticMeshRenderer.cs
|
||||
using System.Numerics;
|
||||
using AcDream.Core.Meshing;
|
||||
using AcDream.Core.Terrain;
|
||||
using AcDream.Core.World;
|
||||
using Silk.NET.OpenGL;
|
||||
|
||||
namespace AcDream.App.Rendering;
|
||||
|
||||
public sealed unsafe class StaticMeshRenderer : IDisposable
|
||||
{
|
||||
private readonly GL _gl;
|
||||
private readonly Shader _shader;
|
||||
private readonly TextureCache _textures;
|
||||
|
||||
// One GPU bundle per unique GfxObj id. Each GfxObj can have multiple sub-meshes.
|
||||
private readonly Dictionary<uint, List<SubMeshGpu>> _gpuByGfxObj = new();
|
||||
|
||||
public StaticMeshRenderer(GL gl, Shader shader, TextureCache textures)
|
||||
{
|
||||
_gl = gl;
|
||||
_shader = shader;
|
||||
_textures = textures;
|
||||
}
|
||||
|
||||
public void EnsureUploaded(uint gfxObjId, IReadOnlyList<GfxObjSubMesh> subMeshes)
|
||||
{
|
||||
if (_gpuByGfxObj.ContainsKey(gfxObjId))
|
||||
return;
|
||||
|
||||
var list = new List<SubMeshGpu>(subMeshes.Count);
|
||||
foreach (var sm in subMeshes)
|
||||
list.Add(UploadSubMesh(sm));
|
||||
_gpuByGfxObj[gfxObjId] = list;
|
||||
}
|
||||
|
||||
private SubMeshGpu UploadSubMesh(GfxObjSubMesh sm)
|
||||
{
|
||||
uint vao = _gl.GenVertexArray();
|
||||
_gl.BindVertexArray(vao);
|
||||
|
||||
uint vbo = _gl.GenBuffer();
|
||||
_gl.BindBuffer(BufferTargetARB.ArrayBuffer, vbo);
|
||||
fixed (void* p = sm.Vertices)
|
||||
_gl.BufferData(BufferTargetARB.ArrayBuffer,
|
||||
(nuint)(sm.Vertices.Length * sizeof(Vertex)), p, BufferUsageARB.StaticDraw);
|
||||
|
||||
uint ebo = _gl.GenBuffer();
|
||||
_gl.BindBuffer(BufferTargetARB.ElementArrayBuffer, ebo);
|
||||
fixed (void* p = sm.Indices)
|
||||
_gl.BufferData(BufferTargetARB.ElementArrayBuffer,
|
||||
(nuint)(sm.Indices.Length * sizeof(uint)), p, BufferUsageARB.StaticDraw);
|
||||
|
||||
uint stride = (uint)sizeof(Vertex);
|
||||
_gl.EnableVertexAttribArray(0);
|
||||
_gl.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, (void*)0);
|
||||
_gl.EnableVertexAttribArray(1);
|
||||
_gl.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, stride, (void*)(3 * sizeof(float)));
|
||||
_gl.EnableVertexAttribArray(2);
|
||||
_gl.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, stride, (void*)(6 * sizeof(float)));
|
||||
|
||||
_gl.BindVertexArray(0);
|
||||
|
||||
return new SubMeshGpu
|
||||
{
|
||||
Vao = vao,
|
||||
Vbo = vbo,
|
||||
Ebo = ebo,
|
||||
IndexCount = sm.Indices.Length,
|
||||
SurfaceId = sm.SurfaceId,
|
||||
};
|
||||
}
|
||||
|
||||
public void Draw(OrbitCamera camera, IEnumerable<WorldEntity> entities)
|
||||
{
|
||||
_shader.Use();
|
||||
_shader.SetMatrix4("uView", camera.View);
|
||||
_shader.SetMatrix4("uProjection", camera.Projection);
|
||||
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
if (entity.MeshRefs.Count == 0)
|
||||
continue;
|
||||
|
||||
foreach (var meshRef in entity.MeshRefs)
|
||||
{
|
||||
if (!_gpuByGfxObj.TryGetValue(meshRef.GfxObjId, out var subMeshes))
|
||||
continue;
|
||||
|
||||
// model = entity root transform * per-part transform
|
||||
var entityRoot =
|
||||
Matrix4x4.CreateFromQuaternion(entity.Rotation) *
|
||||
Matrix4x4.CreateTranslation(entity.Position);
|
||||
var model = meshRef.PartTransform * entityRoot;
|
||||
|
||||
_shader.SetMatrix4("uModel", model);
|
||||
|
||||
foreach (var sub in subMeshes)
|
||||
{
|
||||
uint tex = _textures.GetOrUpload(sub.SurfaceId);
|
||||
_gl.ActiveTexture(TextureUnit.Texture0);
|
||||
_gl.BindTexture(TextureTarget.Texture2D, tex);
|
||||
|
||||
_gl.BindVertexArray(sub.Vao);
|
||||
_gl.DrawElements(PrimitiveType.Triangles, (uint)sub.IndexCount, DrawElementsType.UnsignedInt, (void*)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
_gl.BindVertexArray(0);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var subs in _gpuByGfxObj.Values)
|
||||
{
|
||||
foreach (var sub in subs)
|
||||
{
|
||||
_gl.DeleteBuffer(sub.Vbo);
|
||||
_gl.DeleteBuffer(sub.Ebo);
|
||||
_gl.DeleteVertexArray(sub.Vao);
|
||||
}
|
||||
}
|
||||
_gpuByGfxObj.Clear();
|
||||
}
|
||||
|
||||
private sealed class SubMeshGpu
|
||||
{
|
||||
public uint Vao;
|
||||
public uint Vbo;
|
||||
public uint Ebo;
|
||||
public int IndexCount;
|
||||
public uint SurfaceId;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue