namespace AcDream.App.Rendering; /// /// Builds the layer-indexed adapter table consumed by /// terrain_modern.frag. Retail passes TerrainTex::tex_tiling /// directly to ImgTex::TileCSI / ImgTex::MergeTexture /// (`TexMerge::CopyAndTile` 0x00503580, `TexMerge::Merge` 0x005038C0). /// The table is the modern texture-array equivalent of that per-texture /// argument. /// internal static class TerrainTextureTilingTable { // WorldBuilder's extracted terrain-array path uses the same 36-layer // contract. Packed terrain layer indices are validated against this // capacity before the shader table is built. internal const int LayerCapacity = 36; internal static float[] Build(IEnumerable<(uint Layer, uint RepeatCount)> entries) { ArgumentNullException.ThrowIfNull(entries); var table = new float[LayerCapacity]; Array.Fill(table, 1f); foreach (var (layer, repeatCount) in entries) { if (layer >= LayerCapacity) { throw new InvalidOperationException( $"Terrain atlas layer {layer} exceeds the shader capacity of {LayerCapacity} layers."); } // Preserve the dat value exactly. Retail forwards the unsigned // field without normalizing it in both CopyAndTile and Merge. table[layer] = repeatCount; } return table; } }