# Retail terrain texture tiling ## Question Why do acdream's grass, dirt, and road textures look lower-detail than the September 2013 retail client even though the modern terrain atlas loads 512 x 512 source images, generates mipmaps, and enables anisotropic filtering? ## Retail oracle Named retail symbols in `docs/research/named-retail/acclient_2013_pseudo_c.txt`: - `TexMerge::CopyAndTile` at `0x00503580` - `TexMerge::Merge` at `0x005038C0` - `ImgTex::TileCSI` at `0x0053E740` - `ImgTex::GetSurfaceDID` at `0x0053F0E0` - `Render::ShouldDropHighDetail` at `0x0054C700` The verbatim `TerrainTex` declaration in `docs/research/named-retail/acclient.h` contains `unsigned int tex_tiling`. ## Readable pseudocode ```text CopyAndTile(destination, destinationSize, terrainTexture): baseTexture = terrainTexture.base_texture if baseTexture is null: if terrainTexture.tex_gid is valid: terrainTexture.base_texture = load ImgTex(terrainTexture.tex_gid) baseTexture = terrainTexture.base_texture if baseTexture is null: CopyCSI(destination, destinationSize, destinationSize, null, 1) return false CopyCSI( destination, destinationSize, destinationSize, baseTexture, terrainTexture.tex_tiling) return true Merge(destination, destinationSize, alphaTexture, rotation, terrainTexture): if alphaTexture is null: return false if terrainTexture.base_texture is null: if not terrainTexture.InitEnd(): return false MergeTexture( destination, destinationSize, destinationSize, terrainTexture.base_texture, terrainTexture.tex_tiling, alphaTexture, rotation) return true GetSurfaceDID(surfaceTexture): if surfaceTexture has one source level: return sourceLevels[0] if surfaceTexture has two source levels: if ShouldDropHighDetail(): return sourceLevels[1] return sourceLevels[0] report invalid source-level count ``` `ImgTex::TileCSI` repeats the source image `tex_tiling` times in both axes. `TexMerge::Merge` applies the same repeat count to every terrain layer before the cell-scale alpha mask is merged. Therefore the modern shader must multiply the terrain UV independently for the base layer, each overlay layer, and each road layer. The alpha-map UV must not be multiplied. The source image selection is a separate policy. Retail uses source level zero unless its quality policy explicitly drops high detail, so changing acdream's atlas from `SurfaceTexture.Textures[0]` would invert the verified retail rule. ## Cross-references - Extracted WorldBuilder lineage: `LandSurfaceManager` stores a 36-entry layer-indexed tiling table populated from `TerrainTex.TexTiling`, and its terrain shader multiplies each texture layer's UV by that value. The pinned WorldBuilder change introducing the path is commit `0d1405af65`. - ACE: `ACE.Server/Physics/Common/TexMerge.cs` forwards `TerrainTex.TexTiling` from both `CopyAndTile` and `Merge`; `ImgTex.cs` resolves the normal source as `Textures[0]`. - ACME-derived `tests/AcDream.Core.Tests/Terrain/ClientReference.cs` covers terrain split, pal/road codes, and blend selection, but not image tiling or source-level selection. It supplies no competing behavior for this path. Retail remains the oracle where a reference differs: the pinned WorldBuilder reader selects the last surface source, while retail's `GetSurfaceDID` proves that the normal/high-detail source is index zero. ## acdream port shape 1. Capture `TerrainTex.TexTiling` while `TerrainAtlas` assigns each terrain type to an array layer. 2. Convert the type-keyed values into the renderer's 36-entry layer-indexed uniform table. Unused layers default to `1.0`; mapped values are preserved verbatim. 3. Upload the table after binding `terrain_modern.frag`. 4. Sample base, overlay, and road textures with `cellUv * uTexTiling[layer]`; sample alpha masks with their original UV.