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 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-11 08:53:22 -05:00
co-authored by Claude Fable 5
parent 8431e69b1a
commit 96b8892e7c
8 changed files with 136 additions and 41 deletions
+58 -1
View File
@@ -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