--- id: rendering title: "Rendering — the D3D9 pipeline, materials, sky, beams, performance" status: established source_sections: "PROGRESS_LOG.md §10 (render-fidelity notes); docs/BGF_FORMAT.md" related_topics: [bgf-format, asset-formats, wintesla-port, locomotion, pod-hardware, cockpit-view] key_terms: [L4D3D, material-ramp, BSL, LOD, DPL, beam] open_questions: - "Replacement-LOD for NON-additive multi-LOD models; day/night material path priority (BT_MATPRI)" --- # Rendering The port renders via the WinTesla `L4D3D`/`L4VIDEO` Direct3D9 path ([[wintesla-port]]), carrying our BT loader (`bgfload.cpp`) + fidelity work. The goal: match the authentic pod footage. Geometry/LOD mechanics are in [[bgf-format]]; this topic covers the D3D9 draw path + the fidelity fixes. Full detail: `docs/PROGRESS_LOG.md §10`. ## The IG-board shading model (from libDPL DPLTYPES.H) Shading is selected PER-GEOMETRY by vertex type: **no-normal geometry** (terrain/mesas/sky/buildings/ mech — WHITE baked verts) is UNLIT, colorized by the material's 2-endpoint **[[material-ramp]]** (`dpl_SetMaterialRamp` — texture luminance indexes a low→high gradient); **normal-bearing geometry** (~150 vehicle/missile files) is LIT by the map light. Applying the ramp to lit geometry = the "dusty white blobs" bug (gate on `hasNormals`). [T2] Exception: cockpit-frame (`*_cop`) batches are pure-emissive constant colour (0.13,0.12,0.15), `BT_COP_FRAME` overrides — see [[cockpit-view]] (task #55; the old `BT_COP_RAMP_L` ramp-index approach is retired). [T2] ## The big render-fidelity fixes (dbase/desert matched to pod footage) - **Geometry:** CONN is a flat trilist (not fan); CONN+PCONN coexist — see [[bgf-format]]. Malformed fan-garbage was the "faceted mountains" bug. [T2] - **RAMP colorize** (default-on `BT_RAMP`) + **day/night material priority** (default-on `BT_MATPRI` for the ramps): the `mat\day` libs carry the warm ramps; the generic GEO libs are gray. Terrain/mesas render warm tan; the sky's `dsky_mtl` ramp (0→0.99) gives bright clouds. `hasNormals` gate keeps vehicles LIT (colored trucks). Ramp tint rule: explicit diffuse + NEUTRAL ramp ⇒ tint; coloured ramp ⇒ white. [T2] - **Sky:** a `*sky.bgf` dome/plane drawn in a dedicated fullbright **PASS_SKY** (LIGHTING off, extended far=9000 + world fog); tagged `drawAsSky` at load (the `.x` sidecar path doesn't exist). [T2] - **The env pipeline** (`DPLReadEnvironment`→`DPLReadINIPage`, reads **`content/BTDPL.INI`** via `L4DPLCFG`): resolves map+time → clip/fog/ambient + a directional sun. Bring-up stubs (EnsureValidProjection / per-frame ambient / uninit cloud colours) had clobbered it — now they RE-ASSERT the env values. Debug: copy BTDPL.INI → *DBG.INI with `debug=True`. [T2] - **Projection / stencil (task #55):** the BTDPL.INI `viewangle=60` is the **HORIZONTAL** FOV — authentic 60×47 frustum at 4:3; fovY derived via `BTFovYFromHorizontal` (L4VIDEO.cpp), applied at all 5 projection sites (it was mis-applied as vertical). The device depth-stencil is now **`D3DFMT_D24S8`** for the cockpit punch stencil-cut (L4VIDEO.cpp:2799; sequence L4D3D.cpp:1199-1248) — see [[cockpit-view]]. [T2] ## Backface culling (default CW, `BT_CULL`) The bring-up `D3DCULL_NONE` drew interior/back faces (the "dark wedge" shapes = mesh insides). CW is correct for the BGF quad triangulation `[a b c][a c d]`. [T2] Exception: cockpit `*_cop` batches default DOUBLE-SIDED (`BT_COP_SINGLE=1` restores single-siding, diag) — see [[cockpit-view]]. [T2] ## LODs (default: shipping-engine first-LOD + ADDITIVE_LODS; `BT_ADDLOD`/`BT_LOD_SCALE`/`BT_PUNCH`) See [[bgf-format]] for the √3 range decode, the ADDITIVE_LODS cumulative rule, PUNCH cutouts, and the coplanar-shell submission-order depth bias. Replacement LOD selection for NON-additive multi-LOD models is deferred (needs the board's hot-spot semantics). [T2] ## Mech skins (BSL bit-slice — the rainbow-mech fix) `.BSL` is a bit-sliced container (6 grayscale sub-images per file); the BMF `0x18 BITSLICE` tag picks the slice. Reading it as RGB overlaid 2-3 gray sheets = the "rainbow/graffiti" bug. Fixed: `image.cpp decodeBSL` slice-decodes; `bgfload` threads the 0x18 channel; a cross-library RAMP registry resolves the mech-skin `softer` ramp (defined in OTHER libs). Every mech renders authentic gray-metal paint now. See [[asset-formats]]. [T2] ## Weapon beams (the unported dpl_* layer) The `dpl_*` beam renderable was never ported → beams are drawn by `BTPushBeam`/`BTDrawBeams` (L4VIDEO). The real look is the `ermlaser.bgf` TUBE (native Z 0..−2000, UVs tiled) with the scrolling `bexp` grit texture (from the `.VMF` `SCROLL`). ER lasers red, PPC blue, standard yellow. The beam origin re-anchors to the live muzzle every frame (can't run out from under your own beam). See [[combat-damage]] for fire-rate/muzzle. [T2] ## Translocation warp (the respawn vortex) — see [[translocation-warp]] The death/respawn "blue whirlwind" is `tsphere.bgf` (a 12-facet bicone) spun on-axis with the `bintA` cloud through a wide lavender ramp, drawn as SKY. Full geometry/material/lifecycle/env in [[translocation-warp]]. ⚠ **Rendering-wide fix that came out of it:** `L4D3D::SetTextureScrolling` computed its texture-matrix offset as `scrollDelta × absolute_time`, which grew unbounded and collapsed UV float precision → grainy/spoked scrolled textures the longer a session ran. Wrapped with `fmodf(…, 1.0f)`. This also cleans up the scrolling `bexp` beam grit and any other `SCROLL` material. [T2] (Bug class: [[reconstruction-gotchas]] §13.) ## Performance — the 10fps→60fps fix (~50-80× render speedup) The 10fps baseline had THREE stacked causes, all fixed (engine tree): (1) **`D3DCREATE_SOFTWARE_ VERTEXPROCESSING`** — every vertex transformed+lit on the CPU → HARDWARE first; (2) D3DX `DrawSubset` attribute-table scan (our double-sided tris broke OptimizeInplace) → explicit `SetAttributeTable` + direct `DrawIndexedPrimitive`; (3) no frustum culling → bounding-sphere culling per frame. ⚠ LESSON: the user plays the DEBUG build, but the 10fps was NOT the debug build (RelWithDebInfo identical) — split draw-vs-present + check the DEVICE flags before blaming the compiler. Diagnostics kept: `[spike]/[loadobj]/[rstat]`. [T2] ## Key Relationships - Geometry/LOD: [[bgf-format]]. Base: [[wintesla-port]] (L4D3D). Shadow/visual-conform: [[locomotion]]. - Renders on: [[pod-hardware]] (main 3D view).