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
|
|
@ -21,6 +21,10 @@ public sealed class GameWindow : IDisposable
|
|||
private DatCollection? _dats;
|
||||
private float _lastMouseX;
|
||||
private float _lastMouseY;
|
||||
private StaticMeshRenderer? _staticMesh;
|
||||
private Shader? _meshShader;
|
||||
private TextureCache? _textureCache;
|
||||
private IReadOnlyList<AcDream.Core.World.WorldEntity> _entities = Array.Empty<AcDream.Core.World.WorldEntity>();
|
||||
|
||||
public GameWindow(string datDir) => _datDir = datDir;
|
||||
|
||||
|
|
@ -83,6 +87,10 @@ public sealed class GameWindow : IDisposable
|
|||
Path.Combine(shadersDir, "terrain.vert"),
|
||||
Path.Combine(shadersDir, "terrain.frag"));
|
||||
|
||||
_meshShader = new Shader(_gl,
|
||||
Path.Combine(shadersDir, "mesh.vert"),
|
||||
Path.Combine(shadersDir, "mesh.frag"));
|
||||
|
||||
_camera = new OrbitCamera
|
||||
{
|
||||
Aspect = _window!.Size.X / (float)_window.Size.Y,
|
||||
|
|
@ -117,16 +125,82 @@ public sealed class GameWindow : IDisposable
|
|||
|
||||
var meshData = LandblockMesh.Build(block);
|
||||
_terrain = new TerrainRenderer(_gl, meshData, _shader);
|
||||
|
||||
_textureCache = new TextureCache(_gl, _dats);
|
||||
_staticMesh = new StaticMeshRenderer(_gl, _meshShader, _textureCache);
|
||||
|
||||
// Load LandBlockInfo for Holtburg, hydrate entities.
|
||||
var info = _dats.Get<DatReaderWriter.DBObjs.LandBlockInfo>((landblockId & 0xFFFF0000u) | 0xFFFEu);
|
||||
var entities = info is not null
|
||||
? AcDream.Core.World.LandblockLoader.BuildEntitiesFromInfo(info)
|
||||
: Array.Empty<AcDream.Core.World.WorldEntity>();
|
||||
|
||||
// Populate MeshRefs for each entity by resolving its source id to GfxObj or Setup
|
||||
// and extracting sub-meshes. Store back onto the entity. Since WorldEntity is
|
||||
// `required init`, we rebuild the entity here.
|
||||
var hydratedEntities = new List<AcDream.Core.World.WorldEntity>(entities.Count);
|
||||
foreach (var e in entities)
|
||||
{
|
||||
var meshRefs = new List<AcDream.Core.World.MeshRef>();
|
||||
|
||||
if ((e.SourceGfxObjOrSetupId & 0xFF000000u) == 0x01000000u)
|
||||
{
|
||||
// GfxObj: one mesh ref with identity transform.
|
||||
var gfx = _dats.Get<DatReaderWriter.DBObjs.GfxObj>(e.SourceGfxObjOrSetupId);
|
||||
if (gfx is not null)
|
||||
{
|
||||
var subMeshes = AcDream.Core.Meshing.GfxObjMesh.Build(gfx);
|
||||
_staticMesh.EnsureUploaded(e.SourceGfxObjOrSetupId, subMeshes);
|
||||
meshRefs.Add(new AcDream.Core.World.MeshRef(e.SourceGfxObjOrSetupId, System.Numerics.Matrix4x4.Identity));
|
||||
}
|
||||
}
|
||||
else if ((e.SourceGfxObjOrSetupId & 0xFF000000u) == 0x02000000u)
|
||||
{
|
||||
// Setup: flatten into parts, upload each part's GfxObj.
|
||||
var setup = _dats.Get<DatReaderWriter.DBObjs.Setup>(e.SourceGfxObjOrSetupId);
|
||||
if (setup is not null)
|
||||
{
|
||||
var flat = AcDream.Core.Meshing.SetupMesh.Flatten(setup);
|
||||
foreach (var mr in flat)
|
||||
{
|
||||
var gfx = _dats.Get<DatReaderWriter.DBObjs.GfxObj>(mr.GfxObjId);
|
||||
if (gfx is null) continue;
|
||||
var subMeshes = AcDream.Core.Meshing.GfxObjMesh.Build(gfx);
|
||||
_staticMesh.EnsureUploaded(mr.GfxObjId, subMeshes);
|
||||
meshRefs.Add(mr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (meshRefs.Count > 0)
|
||||
{
|
||||
hydratedEntities.Add(new AcDream.Core.World.WorldEntity
|
||||
{
|
||||
Id = e.Id,
|
||||
SourceGfxObjOrSetupId = e.SourceGfxObjOrSetupId,
|
||||
Position = e.Position,
|
||||
Rotation = e.Rotation,
|
||||
MeshRefs = meshRefs,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_entities = hydratedEntities;
|
||||
Console.WriteLine($"hydrated {_entities.Count} entities on landblock 0x{landblockId:X8}");
|
||||
}
|
||||
|
||||
private void OnRender(double deltaSeconds)
|
||||
{
|
||||
_gl!.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
|
||||
_terrain?.Draw(_camera!);
|
||||
_staticMesh?.Draw(_camera!, _entities);
|
||||
}
|
||||
|
||||
private void OnClosing()
|
||||
{
|
||||
_staticMesh?.Dispose();
|
||||
_textureCache?.Dispose();
|
||||
_meshShader?.Dispose();
|
||||
_terrain?.Dispose();
|
||||
_shader?.Dispose();
|
||||
_dats?.Dispose();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue