From 96b8892e7c3fde3cb25e5aed6016d8ff97449c18 Mon Sep 17 00:00:00 2001 From: arcattack Date: Sat, 11 Jul 2026 08:53:22 -0500 Subject: [PATCH] Cockpit: the authentic punch STENCIL-CUT -- all 8 cockpits real (task #55) The user caught the inversion (blocked viewports, see-through frames); the answer came from the rasterizer board itself: an i860 disassembly of the VREND.MNG firmware decoded the damageize handler (@0xf040f6f8) -- cmd 0x20 (vr_damage_action) writes the dpl_Punchize token triple onto the punch geogroup's first three geometry chunks IN FILE ORDER: chunk1 = the detailed window-aperture shapes -> an invisible per-pixel MASK chunk2 = the coarse hull -> the ONLY colour-drawn geometry (where not masked) chunk3 = byte-identical hull twin -> the damage-reset record, never visible Visible canopy = hull-minus-apertures. Both earlier readings were wrong ways around the same three chunks: dropping all punch left floating fragments (no hull); hiding the duplicate pair hid the HULL and drew the MASK -- the exact inversion observed. Port: bgfload tags per punch patch {non-paired pmesh = mask (role 1), first twin = hull (role 2), second twin = skip}; L4D3D DrawMesh runs mask->stencil-1 (no colour/z-write, z-tested), hull->stencil-NOTEQUAL, mask->stencil-0; device D24X8 -> D24S8 + stencil clear. The cut never touches z, so later-drawn entities show through the apertures. BT_COP_PLATES=1 disables (diag). In-game, all 8 mechs on pure defaults: connected dark frames with clear viewports -- thor (the footage mech) shows the central viewport + surrounding frame exactly as filmed. Combat regression clean (kill + no NaN). Arena textured punch uses the same firmware kit; the black-texel alpha path there is a working approximation, flagged in the KB. Co-Authored-By: Claude Fable 5 --- context/bgf-format.md | 18 +++++------ context/cockpit-view.md | 26 +++++++++------- context/decomp-reference.md | 10 ++++++- engine/MUNGA_L4/L4D3D.cpp | 59 ++++++++++++++++++++++++++++++++++++- engine/MUNGA_L4/L4VIDEO.cpp | 4 +-- engine/MUNGA_L4/bgfload.cpp | 50 ++++++++++++++++++++----------- engine/MUNGA_L4/bgfload.h | 6 ++++ engine/MUNGA_L4/l4d3d.h | 4 +++ 8 files changed, 136 insertions(+), 41 deletions(-) diff --git a/context/bgf-format.md b/context/bgf-format.md index e3a95d1..ada59e9 100644 --- a/context/bgf-format.md +++ b/context/bgf-format.md @@ -48,15 +48,15 @@ LOD whose band contains the camera distance. sibling `dpl_Damagize` FUN_004902b0 uses the same cmd with a different triple). Two cases: [T1] - **Textured** punch (arena walls/catwalks): black texels = HOLES (alpha-test in the opaque pass). Coplanar shells inside one LOD z-fight → depth-bias by submission ordinal. [T2] - - **Texture-less** punch (the `*_cop` cockpit canopies: blakskn + `softer` ramp, NO texture tag - in the BMF — byte-verified, 238-byte BLXSKIN.BMF): **the PUNCH-tagged patches ARE the - transparent WINDOWS** (the whole tagged geogroup renders as holes); the visible frame is only - the NON-punch geometry, itself an open strut lattice rendered single-sided with per-face - INWARD winding (the l/r torso patches are MIRRORED, so no single global winding works). - Verified by rendering every shell from its mech's AUTHORED eye (SKL [jointeye]) — the punch - panes sit exactly over the window apertures in all 8 mechs; all-punch canopies - (bhk1/loki/vulture/avatar) are authentically FRAMELESS. The old "canopy windows are punch - texels" claim was WRONG — there is no texel to key. See [[cockpit-view]]. [T2 in-game, all 8] + - **FINAL mechanism (i860 VREND.MNG firmware, decoded 2026-07-11): a punch geogroup is a + THREE-CHUNK STENCIL-CUT KIT** -- in file order: aperture MASK (invisible per-pixel cutout), + visible HULL (the only colour-drawn chunk, drawn where not masked), byte-identical hull TWIN + (the damage-reset record, never visible). Visible result = hull-minus-apertures. Applies + to cockpit canopies, arena punch (AR02 etc.) and outside-torso punch (VUX_TOR) alike -- the + port's arena "black texels = holes" alpha-test path is a visual approximation that predates + this decode (works; revisit for exactness). Port: bgfload punch-kit roles + the L4D3D + stencil cut (D24S8). See [[cockpit-view]] + [[decomp-reference]] for firmware addresses. + [T1 mechanism / T2 render-verified all 8 cockpits] ## Shading model (from libDPL DPLTYPES.H) Shading is selected PER-GEOMETRY by vertex type: diff --git a/context/cockpit-view.md b/context/cockpit-view.md index 3f772f8..915c844 100644 --- a/context/cockpit-view.md +++ b/context/cockpit-view.md @@ -88,17 +88,21 @@ inverse(eyeWorld)`. No LookAt anywhere. (pos=(0.1,0.15,0.1), neg=(−0.1,−0.15,−0.1) — same for madcat AND bhk1) → the eye equilibrium is (0,0,0) and the clamps limit gyro motion to ±0.1..0.15u. The gyro is a BOUNCE/sway mechanism, NOT a large steady offset. The authentic resting eye = raw baseOffset for every mech. -- **RESOLVED (2026-07-11): the PUNCH patches are the transparent WINDOWS.** Rendering every - shell OFFLINE from its mech's AUTHORED eye (scratchpad/cop_eyeview.py, faces coloured by punch - flag) showed the punch panes sitting exactly over the window apertures in all 8 mechs, with the - visible frame = ONLY the non-punch geometry. The loader now DROPS the punch batches of `_cop` - meshes (bgfload finish(), `BT_COP_KEEPPUNCH=1` keeps them for diag). In-game sweep on pure - defaults, all 8 mechs [T2]: **madcat** = the dark dome frame (matches footage); **thor** = - floating brace remnants (authentic; its frame bits are the small non-punch patches); **owens** = - dash strip; **sunder** = two side pillars; **bhk1/loki/vulture/avatar** = authentically - FRAMELESS (all-punch canopies — the pod showed no frame for those mechs). NOTE: an - early-session in-game test "disproving" drop-punch ran with the broken pre-inverse eye — its - conclusion was wrong and cost a detour; with the authentic eye the drop is plainly right. +- **FINAL (2026-07-11, i860-firmware-decoded): PUNCH is a three-chunk STENCIL-CUT KIT.** The + VREND.MNG board firmware's 'damageize' handler (@0xf040f6f8, disassembled with a custom i860 + tool) writes the dpl_Punchize token triple {dmg_set, undmg2enbl|texture, dmg_clear} onto the + punch geogroup's first three geometry chunks IN FILE ORDER: chunk1 = the detailed + window-aperture shapes = an invisible per-pixel MASK; chunk2 = the coarse HULL = the ONLY + colour-drawn geometry, drawn where NOT masked; chunk3 = a byte-identical hull twin = the + damage-reset record, never visible. The visible canopy = hull-minus-apertures. Port: + bgfload identifies the within-patch twin pair (hull + skip) and tags the non-paired pmeshes as + masks; L4D3D draws mask (stencil 1, no colour/z-write), hull (stencil-reject), mask (stencil 0) + on a D24S8 device; the cut never touches z, so later-drawn entities show through apertures. + BT_COP_PLATES=1 disables the kit (diag). In-game, all 8 mechs on pure defaults [T2]: + connected dark frames with clear viewports; thor (the footage mech) shows the big central + viewport + surrounding frame exactly as filmed. TWO earlier readings are superseded and were + WRONG: "punch patches = windows, drop them" (left floating frame fragments) and "duplicate + pairs = plates, hide both" (hid the HULL and drew the MASK = the inversion the user caught). - **Hit-bounce: LIVE and verified [T2] (2026-07-11).** The damage→gyro fan-out **FUN_004b2980** was re-disassembled byte-exact from the raw image (capstone; scratchpad/dis_4b2980.py) and reconstructed as `Gyroscope::ApplyDamageResponse` (gyro.cpp): zero-damage + Collision(0) no-op; diff --git a/context/decomp-reference.md b/context/decomp-reference.md index f4fd1b8..e1d9938 100644 --- a/context/decomp-reference.md +++ b/context/decomp-reference.md @@ -56,7 +56,7 @@ reconciled via `CLASSMAP.md`, not the case label. [T1] | 0xBC1 | **Generator** | @4b… | power bus | | 0xBC2 | **PoweredSubsystem** | @004b0f74 | sizeof 0x31C | | 0xBC3 | **Sensor** | — | `case`=MyomersClassID | -| 0xBC4 | **Gyroscope** | @004b3778 | DEFERRED (NaN integrator; reverted to stub) | +| 0xBC4 | **Gyroscope** | @004b3778 | LIVE (task #56: byte-exact ctor/integrators/writers; hit-bounce fan-out wired) | | 0xBC5 | **Torso** | @004b6b0c | sizeof 0x280; `case`=SinkSource | | 0xBC6 | **Myomers** | @4b8fec | `case`=Actuator; INERT un-stub | | 0xBC8 | **Emitter** | @004b1d18 | sizeof 0x478; energy weapon | @@ -188,6 +188,14 @@ recoil @4bc136-4bc19c (damage>3 → (0,0.6,−1.5) × damage/16; `gyroRumbleTime ex-"clipLoadGuard"). Byte tooling: `scratchpad/dis_4b2980.py` / `dis_range.py` over `reference/decomp/section_dump.txt`. +**PUNCH firmware decode** [T1] (the definitive mechanism, 2026-07-11): cmd 0x20 = +vr_damage_action (VR_PROT.H enum); the i860 firmware content/VREND.MNG (code @0xf0400000) +handler 'damageize' @0xf040f6f8 writes the token triple onto the geogroup's first THREE +geometry-list nodes' geometry_type@+8 IN FILE ORDER (superlist appends at tail @0xf040c620); +DPL_PRIV.H names the roles: f_t_dam(0x92)/sca(0x05)/undamage(0x04)/f_t_undam(0x17)/ +damage_set(0x03). Punchize triple = mask, hull, reset-twin -- the visible surface is the HULL +with the MASK shapes stencil-cut through it. Disassembler: scratchpad/i860dis.py. + **Cockpit-eye / punch addresses** [T1] (full story: [[cockpit-view]]): eye ctor **`FUN_004579a8`** (part_007.c:9274 = DPLEyeRenderable; offset = segment `GetBaseOffset` segment+0x74, parent = parent-segment DCS; caller part_014.c:5525-66 gates on `"siteeyepoint"`); diff --git a/engine/MUNGA_L4/L4D3D.cpp b/engine/MUNGA_L4/L4D3D.cpp index 987ca8a..a75241a 100644 --- a/engine/MUNGA_L4/L4D3D.cpp +++ b/engine/MUNGA_L4/L4D3D.cpp @@ -200,6 +200,7 @@ d3d_OBJECT *d3d_OBJECT::LoadObject(LPDIRECT3DDEVICE9 device, char *fileName) } object->mDrawOps[i].drawAsSky = isSky; + object->mDrawOps[i].copRole = 0; if (isSky) { @@ -430,6 +431,7 @@ d3d_OBJECT* d3d_OBJECT::LoadObjectBGF(LPDIRECT3DDEVICE9 device, char *fileName) static int s_punch = -1; if (s_punch < 0) { const char *pv = getenv("BT_PUNCH"); s_punch = (pv == 0 || pv[0] != '0') ? 1 : 0; } object->mDrawOps[i].punchThrough = (s_punch && data.batches[i].punch); + object->mDrawOps[i].copRole = data.batches[i].copRole; // punch stencil-cut kit (task #55) object->mDrawOps[i].texture.texture = NULL; object->mDrawOps[i].texture.wrap_u = L4TEXOP::REPEAT; object->mDrawOps[i].texture.wrap_v = L4TEXOP::REPEAT; @@ -1112,6 +1114,11 @@ void d3d_OBJECT::DrawMesh(int pass, const D3DXMATRIX *viewTransform, Time target { L4DRAWOP *drawOp = &mDrawOps[iOp]; + // COCKPIT PUNCH KIT (task #55): aperture-MASK ops never draw colour -- + // they are consumed by the FOLLOWING hull op's stencil-cut sequence. + if (drawOp->copRole == 1) + continue; + if (drawOp->alphaTest != (pass == PASS_ALPHABLEND)) continue; @@ -1189,7 +1196,57 @@ void d3d_OBJECT::DrawMesh(int pass, const D3DXMATRIX *viewTransform, Time target } gNumBatches++; - if (drawOp->bgfPrimCount > 0 && mBgfVB != NULL) + // COCKPIT PUNCH STENCIL-CUT (task #55, the i860 'damageize' mechanism): + // a role-2 HULL op is preceded by its role-1 aperture-MASK op. Sequence: + // 1. draw the mask stencil-only (no colour, no z-write, z-TESTED) -> ref 1 + // 2. draw the hull with stencil-reject where ref==1 (the window cutouts) + // 3. re-draw the mask writing stencil 0 (clean up for other punch groups) + // The stencil never touches z, so entities drawn later still show through + // the apertures correctly. + const bool copCut = (drawOp->copRole == 2 && iOp > 0 + && mDrawOps[iOp - 1].copRole == 1 + && mDrawOps[iOp - 1].bgfPrimCount > 0 + && drawOp->bgfPrimCount > 0 && mBgfVB != NULL); + if (copCut) + { + L4DRAWOP *maskOp = &mDrawOps[iOp - 1]; + mDevice->SetFVF(L4VERTEX_FVF); + mDevice->SetStreamSource(0, mBgfVB, 0, mBgfStride); + mDevice->SetIndices(mBgfIB); + // 1. mask -> stencil ref 1 (colour + z-write off) + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILREF, 1); + mDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, mBgfNumVerts, + maskOp->bgfStartIndex, maskOp->bgfPrimCount); + // 2. hull, stencil-rejected under the mask + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, + D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | + D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA); + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL); + mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + mDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, mBgfNumVerts, + drawOp->bgfStartIndex, drawOp->bgfPrimCount); + // 3. mask again -> stencil ref 0 (clean) + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILREF, 0); + mDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, mBgfNumVerts, + maskOp->bgfStartIndex, maskOp->bgfPrimCount); + // restore + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, + D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | + D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA); + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + } + else if (drawOp->bgfPrimCount > 0 && mBgfVB != NULL) { // direct-draw: known contiguous range, no attribute-table scan. // (DrawSubset used to set the vertex decl itself -- assert the FVF here diff --git a/engine/MUNGA_L4/L4VIDEO.cpp b/engine/MUNGA_L4/L4VIDEO.cpp index 259beee..8eff79e 100644 --- a/engine/MUNGA_L4/L4VIDEO.cpp +++ b/engine/MUNGA_L4/L4VIDEO.cpp @@ -2779,7 +2779,7 @@ DPLRenderer::DPLRenderer( mPresentParams.PresentationInterval = D3DPRESENT_RATE_DEFAULT; mPresentParams.BackBufferFormat = D3DFMT_X8R8G8B8; mPresentParams.EnableAutoDepthStencil = TRUE; - mPresentParams.AutoDepthStencilFormat = D3DFMT_D24X8; + mPresentParams.AutoDepthStencilFormat = D3DFMT_D24S8; // S8: the cockpit punch stencil-cut (task #55) mPresentParams.Windowed = !fullscreen; if (fullscreen) { @@ -7421,7 +7421,7 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte DWORD currentFog; mDevice->GetRenderState(D3DRS_FOGCOLOR, ¤tFog); - hr = mDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, currentFog, 1.0f, 0); + hr = mDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, currentFog, 1.0f, 0); hr = mDevice->BeginScene(); diff --git a/engine/MUNGA_L4/bgfload.cpp b/engine/MUNGA_L4/bgfload.cpp index a507af1..bdf1140 100644 --- a/engine/MUNGA_L4/bgfload.cpp +++ b/engine/MUNGA_L4/bgfload.cpp @@ -504,7 +504,8 @@ struct Builder { bool currentTSphere = false; // material is tsphere_mtl (translocation warp): ramp it despite normals bool meshIsTSphere = false; // this OBJECT is the translocation warp -> smooth-tessellate the cone bool meshIsCop = false; // this OBJECT is a *_cop cockpit canopy shell (task #55) - std::set copPlateSkip; // duplicate damage-plate PMESHes to hide (see TAG_PATCH) + std::map copRoleMap; // punch-kit roles per PMESH chunk: 1=mask 2=hull 3=skip (see TAG_PATCH) + int currentCopRole = 0; // role of the pmesh being built (consumed by buildPmesh) bool currentHasEmissive = false; float currentEmissive[3] = {0,0,0}; @@ -734,6 +735,7 @@ struct Builder { batch.lodNear = currentLodNear; batch.lodFar = currentLodFar; batch.punch = currentPunch; + batch.copRole = currentCopRole; // punch stencil-kit role (task #55) batch.shadowMat = currentShadowMat; batch.hasEmissive = currentHasEmissive; for (int i = 0; i < 3; ++i) batch.emissive[i] = currentEmissive[i]; @@ -964,24 +966,24 @@ struct Builder { if (memcmp(s + i, "PUNCH", 5) == 0) currentPunch = true; if (currentPunch) break; } - // COCKPIT DAMAGE-STATE PLATES (task #55, resolved 2026-07-11): every - // *_cop PUNCH patch contains exactly one pair of BYTE-IDENTICAL - // duplicate PMESHes -- solid cover plates for the tricoder per-triangle - // damage machinery (dpl_Punchize tokens = {dmg_set, undmg2enbl|texture, - // dmg_clear}; TRICODER.H), NOT visible undamaged structure. Rendering - // them was the "solid black canopy"; hiding only whole punch patches - // instead left disconnected floating frame bits. Hide the duplicate - // pairs (both copies), render the rest of the punch lattice opaque -- - // verified from every mech's authored eye (SKL [jointeye]): all 8 - // cockpits read as CONNECTED frames with window apertures. Duplicates - // are counted WITHIN the patch (BLX repeats its whole main lattice - // ACROSS its three dz-material patches -- those must stay). - // BT_COP_PLATES=1 renders the plates (diagnostic). + // PUNCH STENCIL-CUT KIT (task #55, FINAL -- decoded from the i860 + // VREND.MNG firmware 'damageize' handler @0xf040f6f8 + the dpl_Punchize + // token triple {dmg_set, undmg2enbl|texture, dmg_clear}): a PUNCH + // patch's pmeshes are, in FILE ORDER, {aperture MASK, visible HULL, + // byte-identical hull TWIN}. The board rasterizes the MASK as an + // invisible per-pixel cutout, colour-draws ONLY the HULL where not + // masked (= the canopy frame with the window apertures cut through), + // and keeps the TWIN as the damage-reset record (never visible). + // Identify the twin pair WITHIN the patch by content hash: pair FIRST + // = the hull (role 2), pair SECOND = skipped; every non-paired pmesh + // = the aperture mask (role 1; drawn stencil-only by L4D3D). + // BT_COP_PLATES=1 disables the kit (all pmeshes draw plain, diag). if (meshIsCop && currentPunch) { static int s_plates = -1; if (s_plates < 0) { const char* e = getenv("BT_COP_PLATES"); s_plates = (e && e[0] != '0') ? 1 : 0; } if (!s_plates) { std::map, const Chunk*> seen; + bool pairFound = false; for (const Chunk& ch : c.children) { if (ch.id != TAG_PMESH) continue; uint64_t h = 1469598103934665603ull; // FNV-1a @@ -990,12 +992,19 @@ struct Builder { auto it = seen.find(key); if (it == seen.end()) seen[key] = &ch; else { - copPlateSkip.insert(&ch); copPlateSkip.insert(it->second); + copRoleMap[it->second] = 2; // hull (first twin) + copRoleMap[&ch] = 3; // reset record: never drawn + pairFound = true; if (getenv("BT_COP_DUMP")) - fprintf(stderr, "[cop] hid duplicate plate pair (pmesh len=%u)\n", + fprintf(stderr, "[cop] punch kit: hull+twin pair (pmesh len=%u)\n", (unsigned)ch.len); } } + if (pairFound) + for (const Chunk& ch : c.children) + if (ch.id == TAG_PMESH && !copRoleMap.count(&ch)) + copRoleMap[&ch] = 1; // aperture mask + // no pair -> every pmesh stays role 0 (draw plain; unexpected shape) } } for (const Chunk& ch : c.children) @@ -1067,7 +1076,14 @@ struct Builder { for (int i = 0; i < 3; ++i) { currentRampLo[i] = savedRampLo[i]; currentRampHi[i] = savedRampHi[i]; } break; } - case TAG_PMESH: if (copPlateSkip.count(&c)) break; buildPmesh(c); break; + case TAG_PMESH: { + auto rit = copRoleMap.find(&c); + currentCopRole = (rit != copRoleMap.end()) ? rit->second : 0; + if (currentCopRole == 3) { currentCopRole = 0; break; } // hull twin: never drawn + buildPmesh(c); + currentCopRole = 0; + break; + } default: for (const Chunk& ch : c.children) collect(ch); break; } } diff --git a/engine/MUNGA_L4/bgfload.h b/engine/MUNGA_L4/bgfload.h index b58818c..5dcd66a 100644 --- a/engine/MUNGA_L4/bgfload.h +++ b/engine/MUNGA_L4/bgfload.h @@ -61,6 +61,12 @@ struct BgfDrawBatch { // lattice: arena scaffold layers AR01-04, gratings). Drawn SOLID they // shingle near-coplanar over the massing = depth-shimmer "noisy surfaces". bool punch = false; + // COCKPIT PUNCH STENCIL-CUT ROLES (task #55, decoded from the i860 VREND.MNG + // firmware 'damageize' handler): a PUNCH patch's three pmeshes are, in file + // order, {aperture MASK, visible HULL, hull twin (damage-reset record)}. + // 0 = normal batch; 1 = aperture mask (stencil-only, no colour/z); + // 2 = hull (drawn stencil-rejected under the mask = the window cutouts). + int copRole = 0; // LAYER DEPTH BIAS (additive objects): the layers contain EXACTLY-COPLANAR // duplicated surfaces (flush wall patches between detail + massing). The // IG board resolved those deterministically (exact per-polygon plane diff --git a/engine/MUNGA_L4/l4d3d.h b/engine/MUNGA_L4/l4d3d.h index a2a2ec7..78376d5 100644 --- a/engine/MUNGA_L4/l4d3d.h +++ b/engine/MUNGA_L4/l4d3d.h @@ -98,6 +98,10 @@ struct L4DRAWOP // black texels were loaded with alpha 0; draw with alpha TEST in the opaque pass // (z-write preserved), rejecting hole texels. bool punchThrough; + // COCKPIT PUNCH STENCIL-CUT (task #55, i860-firmware-decoded): 0=normal, + // 1=aperture MASK (drawn stencil-only, paired with the following hull op), + // 2=HULL (drawn stencil-rejected under the mask = window cutouts). + int copRole; // LAYER DEPTH BIAS (additive-LOD coplanar resolution; see bgfload.h): finer // layers get a slightly more negative normalized-depth bias so EXACTLY- // coplanar duplicated surfaces resolve to the detail layer instead of