From bf934d98c3d7bc809fa8115d97c40cfbb3c9b384 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 17 Jul 2026 21:31:48 +0200 Subject: [PATCH] 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 --- docs/research/2026-07-10-detail-texturing.md | 59 ++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 docs/research/2026-07-10-detail-texturing.md diff --git a/docs/research/2026-07-10-detail-texturing.md b/docs/research/2026-07-10-detail-texturing.md new file mode 100644 index 00000000..d2b16e2e --- /dev/null +++ b/docs/research/2026-07-10-detail-texturing.md @@ -0,0 +1,59 @@ +# 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 + (1−detail.a))`; terrain: +`lerp(base, detail, detail.a)` (vestigial in 2013). One option gates buildings + EnvCells together.