fix(terrain): use real LandHeightTable from Region dat

Phase 1 simplified per-vertex height as byte * 2.0f, but AC stores
heights as byte indices into a 256-entry non-linear float lookup
(Region.LandDefs.LandHeightTable). Static object placements in
LandBlockInfo use the real table, so terrain rendered with the
simplified scale left buildings floating or buried.

LandblockMesh.Build now takes an explicit float[] heightTable so
the core code stays testable without a DatCollection. GameWindow
loads Region id 0x13000000 once at startup and passes its
LandDefs.LandHeightTable into every landblock mesh build. The
Phase 1 tests use an identity table (i * 2f for i in 0..255) so
their expectations remain unchanged.

Addresses the 'buildings buried and floating' issue the user
observed after the Phase 2a visual checkpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-10 19:09:27 +02:00
parent 1d1e668a2f
commit 4763b973da
3 changed files with 34 additions and 8 deletions

View file

@ -123,7 +123,17 @@ public sealed class GameWindow : IDisposable
Console.WriteLine($"loaded landblock 0x{landblockId:X8}");
var meshData = LandblockMesh.Build(block);
// Load the non-linear LandHeightTable from the Region dat. AC encodes
// per-vertex heights as byte indices into this 256-entry float table,
// not as a simple * 2.0 ramp — building placements depend on the real
// table, so terrain rendered with the simplified scale would leave
// buildings floating or buried.
var region = _dats.Get<DatReaderWriter.DBObjs.Region>(0x13000000u);
var heightTable = region?.LandDefs.LandHeightTable;
if (heightTable is null || heightTable.Length < 256)
throw new InvalidOperationException("Region.LandDefs.LandHeightTable missing or truncated");
var meshData = LandblockMesh.Build(block, heightTable);
_terrain = new TerrainRenderer(_gl, meshData, _shader);
_textureCache = new TextureCache(_gl, _dats);