fix(rendering): restore retail terrain texture tiling
Carry TerrainTex.TexTiling through the terrain atlas and upload a layer-indexed table to the modern bindless shader so base, overlay, and road textures repeat at retail scale. Keep alpha masks cell-scaled and preserve retail's verified source-level-zero high-detail selection. Add the named-retail pseudocode, WorldBuilder/ACE/ACME cross-reference, adapter conformance tests, and inventory documentation so a future renderer migration keeps the contract. Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
parent
84b7d2d7cd
commit
bb5acab9e6
7 changed files with 297 additions and 7 deletions
|
|
@ -34,6 +34,12 @@ public sealed unsafe class TerrainAtlas : IDisposable
|
|||
public uint GlTexture { get; } // terrain atlas, kept as GlTexture for back-compat with TerrainRenderer
|
||||
public IReadOnlyDictionary<uint, uint> TerrainTypeToLayer { get; }
|
||||
public int LayerCount { get; }
|
||||
/// <summary>
|
||||
/// UV repeat count for each terrain-array layer. Retail forwards
|
||||
/// <c>TerrainTex::tex_tiling</c> to both base and merged terrain textures
|
||||
/// (`TexMerge::CopyAndTile` 0x00503580, `TexMerge::Merge` 0x005038C0).
|
||||
/// </summary>
|
||||
public IReadOnlyList<float> TilingByLayer { get; }
|
||||
|
||||
// --- Alpha atlas (new in Phase 3c.2) ---
|
||||
public uint GlAlphaTexture { get; }
|
||||
|
|
@ -86,6 +92,7 @@ public sealed unsafe class TerrainAtlas : IDisposable
|
|||
GL gl,
|
||||
Wb.BindlessSupport? bindless,
|
||||
uint glTexture, IReadOnlyDictionary<uint, uint> map, int layerCount,
|
||||
IReadOnlyList<float> tilingByLayer,
|
||||
uint glAlphaTexture, int alphaLayerCount,
|
||||
IReadOnlyList<byte> cornerLayers, IReadOnlyList<byte> sideLayers, IReadOnlyList<byte> roadLayers,
|
||||
IReadOnlyList<uint> cornerTCodes, IReadOnlyList<uint> sideTCodes, IReadOnlyList<uint> roadRCodes)
|
||||
|
|
@ -95,6 +102,7 @@ public sealed unsafe class TerrainAtlas : IDisposable
|
|||
GlTexture = glTexture;
|
||||
TerrainTypeToLayer = map;
|
||||
LayerCount = layerCount;
|
||||
TilingByLayer = tilingByLayer;
|
||||
GlAlphaTexture = glAlphaTexture;
|
||||
AlphaLayerCount = alphaLayerCount;
|
||||
CornerAlphaLayers = cornerLayers;
|
||||
|
|
@ -125,6 +133,7 @@ public sealed unsafe class TerrainAtlas : IDisposable
|
|||
|
||||
// ---- Terrain atlas (unchanged Phase 2b logic) ----
|
||||
var decodedByType = new Dictionary<uint, DecodedTexture>();
|
||||
var tilingByType = new Dictionary<uint, uint>();
|
||||
int maxW = 1, maxH = 1;
|
||||
foreach (var tmtd in terrainDesc)
|
||||
{
|
||||
|
|
@ -132,6 +141,12 @@ public sealed unsafe class TerrainAtlas : IDisposable
|
|||
if (decodedByType.ContainsKey(typeKey))
|
||||
continue;
|
||||
|
||||
// Retail terrain composition repeats this surface exactly
|
||||
// TerrainTex::tex_tiling times in each axis before applying the
|
||||
// cell-scale alpha mask. Preserve the dat field alongside the
|
||||
// decoded surface while layer assignment is still type-keyed.
|
||||
tilingByType[typeKey] = tmtd.TerrainTex.TexTiling;
|
||||
|
||||
var surfaceTextureId = (uint)tmtd.TerrainTex.TextureId;
|
||||
var st = dats.Get<SurfaceTexture>(surfaceTextureId);
|
||||
if (st is null || st.Textures.Count == 0)
|
||||
|
|
@ -141,6 +156,10 @@ public sealed unsafe class TerrainAtlas : IDisposable
|
|||
continue;
|
||||
}
|
||||
|
||||
// Retail ImgTex::GetSurfaceDID (0x0053F0E0) returns source level
|
||||
// zero unless Render::ShouldDropHighDetail explicitly selects
|
||||
// level one. acdream currently has no low-detail quality mode, so
|
||||
// index zero is the retail high-detail source.
|
||||
var rs = dats.Get<RenderSurface>((uint)st.Textures[0]);
|
||||
if (rs is null)
|
||||
{
|
||||
|
|
@ -183,6 +202,12 @@ public sealed unsafe class TerrainAtlas : IDisposable
|
|||
layerIdx++;
|
||||
}
|
||||
|
||||
var tilingByLayer = TerrainTextureTilingTable.Build(
|
||||
map.Select(entry =>
|
||||
(entry.Value, tilingByType.TryGetValue(entry.Key, out uint repeatCount)
|
||||
? repeatCount
|
||||
: 1u)));
|
||||
|
||||
// A.5 T19: generate mipmaps + trilinear + 16x anisotropic for distant-LB quality.
|
||||
gl.GenerateMipmap(TextureTarget.Texture2DArray);
|
||||
gl.TexParameter(TextureTarget.Texture2DArray, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
|
||||
|
|
@ -203,7 +228,7 @@ public sealed unsafe class TerrainAtlas : IDisposable
|
|||
return new TerrainAtlas(
|
||||
gl,
|
||||
bindless,
|
||||
tex, map, layerCount,
|
||||
tex, map, layerCount, tilingByLayer,
|
||||
alphaBuild.gl, alphaBuild.layerCount,
|
||||
alphaBuild.corner, alphaBuild.side, alphaBuild.road,
|
||||
alphaBuild.cornerTCodes, alphaBuild.sideTCodes, alphaBuild.roadRCodes);
|
||||
|
|
@ -410,6 +435,7 @@ public sealed unsafe class TerrainAtlas : IDisposable
|
|||
gl,
|
||||
bindless,
|
||||
tex, new Dictionary<uint, uint> { [0] = 0u }, 1,
|
||||
TerrainTextureTilingTable.Build(Array.Empty<(uint Layer, uint RepeatCount)>()),
|
||||
alphaTex, 1,
|
||||
Array.Empty<byte>(), Array.Empty<byte>(), Array.Empty<byte>(),
|
||||
Array.Empty<uint>(), Array.Empty<uint>(), Array.Empty<uint>());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue