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

59 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.