acdream/docs/research/2026-07-10-detail-texturing.md
Erik bf934d98c3 docs(research): retail Environment Detail Textures = overlay blend, decomp-verified
One checkbox drives building + EnvCell detail; base texture always drawn;
detail is a region-authored ImgTex with its own tiling, modulate-blended over
(single-pass multitexture or two-pass fallback). Port sketch included.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 21:31:48 +02:00

3.8 KiB
Raw Blame History

Retail "Environment Detail Textures" — mechanism (decomp-verified 2026-07-10)

Question: does the option apply a texture OVER the original, or a new texture altogether? Answer: OVERLAY — the base texture is always drawn unchanged; detail is an extra blended layer. All references are docs/research/named-retail/acclient_2013_pseudo_c.txt line:address or acclient.h:line.

Chain

  • Checkbox: RenderPrefs.EnvironmentDetailTextures (acclient.h:41674-41678) → Render::UpdateFromPreferences (344244:0054d850) → SmartBox::SetDetailTexturing (90961:00451df0) → LScape::SetDetailTexturing (268389:00506b40).
  • One checkbox drives TWO categories: building (cat 1) AND EnvCell/dungeon (cat 2). Landscape detail is force-zeroed at the options layer in this Sept-2013 build (344384:0054d9c8) — vestigial but fully wired at draw time. Object/creature detail is never enabled; DrawPartCell (429201:005a07a6) explicitly nulls curr_detail_surface.
  • Asset: per-terrain-type detail_tex_gid + detail_tex_tiling authored in the region dat (acclient.h:52986-52987; read via TexMerge::GetDetailTex 264927:005039e0). Ordinary ImgTex (QDID type 0xb). LScape::GenerateDetailSurface (267853:00506230) wraps it in a custom CSurface (makeCustomSurface(SH_CUSTOMDB) + UseTextureMap, type |= 0x20000 = SurfaceType::DETAIL) and publishes to Render::environment/building_detail_surface (setters 342321-342349:0054b7c0+) with its tiling factor.

Draw + blend (base ALWAYS stays)

Per frame RenderDeviceD3D::DrawEnvCell (427885:0059f170) / DrawBuilding (427938:0059f2a0) stash the category surface into Render::curr_detail_surface with blend src=9 D3DBLEND_DESTCOLOR / dst=6 INVSRCALPHA (427897-427900 / 427950-427953); landscape path (DrawBlock 430027:005a17c0, full-LOD side_cell_count==8 only) uses 5/6 SRCALPHA/INVSRCALPHA. Detail UVs = baseUV × tiling, written as a second texcoord set (landPolyDraw 702299:006b6525, FVF 0x242/0x252; D3DPolyRender::SetDetailTiling 424834:0059c150 caches in MeshBuffer.detailTilingFactorSet acclient.h:31954).

Two hardware paths, both compositing over the base:

  1. Single-pass multitexture (when bCanDoSinglePassDetailing, caps 428180:0059f6cf): D3DPolyRender::SetSurface (425083:0059c4d0) — stage 0 = BASE tex MODULATE diffuse + ALPHAOP PREMODULATE; stage 1 = DETAIL tex TEXOP_BLENDCURRENTALPHA on texcoord set 1 (425109-425115:0059c51c-0059c574); ACRender::SetDetailSurfaceInternal(1) (702183:006b6280) binds detail in stage 1, WRAP+LINEAR.
  2. Two-pass fallback: draw base normally, then rebind detail into stage 0 with SetBlendFunction(src,dst,ADD) + AlphaBlendEnable + DEPTHTEST_LESSEQUAL (702199-702204:006b62db) and redraw the same geometry with detail-tiled UVs (landPolyDraw 2nd pass 702352:006b6664; RenderMeshSubset 2nd pass 425604:0059cdb3).

Blend math: buildings/EnvCells → final = base × (detail.rgb + (1 detail.a)) — modulate-style tint fading to identity where detail alpha→0. Landscape → classic alpha-lerp. Detail suppressed on clip-mapped (color-keyed) base surfaces (BASE1_CLIPMAP=4 gate, 702215:006b6333).

Open ends

  • A 10→50-unit distance fade exists (get_alpha_for_z) but its noFadeDetail global inits to 1 (fade DISABLED, alpha forced 0xff) at 1105973:00820e38 with no writer found — as-shipped the detail likely renders full-strength at all distances. A cdb poke on live retail would settle it.

Port sketch for acdream (when we add the option)

Draw the base exactly as today; add detail layer = detailTex sampled at (baseUV × detail_tex_tiling); combine per category — buildings/EnvCells: base × (detail.rgb + (1detail.a)); terrain: lerp(base, detail, detail.a) (vestigial in 2013). One option gates buildings + EnvCells together.