feat(core): add LandblockMesh flat-terrain generator

Pure CPU mesh generator: takes a DatReaderWriter LandBlock DBObj and
produces 81 vertices + 128 triangles covering 192x192 world units.
Vertices are a readonly record struct (position, normal, texcoord)
so the upcoming GPU upload in Task 8 can sizeof() them directly.
Height byte -> world z uses a simple 2x scale; the real AC height
lookup table is a Phase 2+ concern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-10 16:37:52 +02:00
parent f6a57cbc6c
commit baf0db303d
3 changed files with 131 additions and 0 deletions

View file

@ -0,0 +1,50 @@
using System.Numerics;
using DatReaderWriter.DBObjs;
namespace AcDream.Core.Terrain;
public sealed record LandblockMeshData(Vertex[] Vertices, uint[] Indices);
public static class LandblockMesh
{
// AC landblock geometry constants
private const int VerticesPerSide = 9; // 9x9 heightmap grid
private const int CellsPerSide = VerticesPerSide - 1; // 8x8 cells
private const float CellSize = 24.0f; // world units per cell edge
private const float HeightScale = 2.0f; // byte height -> world z
public static LandblockMeshData Build(LandBlock block)
{
var vertices = new Vertex[VerticesPerSide * VerticesPerSide];
for (int y = 0; y < VerticesPerSide; y++)
{
for (int x = 0; x < VerticesPerSide; x++)
{
int i = y * VerticesPerSide + x;
float height = block.Height[i] * HeightScale;
vertices[i] = new Vertex(
Position: new Vector3(x * CellSize, y * CellSize, height),
Normal: Vector3.UnitZ,
TexCoord: new Vector2(x / (float)CellsPerSide, y / (float)CellsPerSide));
}
}
var indices = new uint[CellsPerSide * CellsPerSide * 6];
int idx = 0;
for (int y = 0; y < CellsPerSide; y++)
{
for (int x = 0; x < CellsPerSide; x++)
{
uint a = (uint)(y * VerticesPerSide + x);
uint b = (uint)(y * VerticesPerSide + x + 1);
uint c = (uint)((y + 1) * VerticesPerSide + x);
uint d = (uint)((y + 1) * VerticesPerSide + x + 1);
// two triangles per cell, CCW
indices[idx++] = a; indices[idx++] = b; indices[idx++] = d;
indices[idx++] = a; indices[idx++] = d; indices[idx++] = c;
}
}
return new LandblockMeshData(vertices, indices);
}
}

View file

@ -0,0 +1,5 @@
using System.Numerics;
namespace AcDream.Core.Terrain;
public readonly record struct Vertex(Vector3 Position, Vector3 Normal, Vector2 TexCoord);