Fire VISUALS wave: the authored firesmoke sheet, vertex-alpha effect cards, the case-4 wreck dressing
The "fireballs like the demo vids" arc, decomp/content-grounded end to end,
plus the live-play UX batch verified over the same sessions:
FIRESMOKE SHEET (the PFX fireball fix): every firesmokeN_scr_tex in BTFX.VMF
maps the SAME 64x64 tileable noise image bintA (variants differ only in SCROLL
rate) and firesmoke1_mtl colours it through the "fiery" ramp (0.3,0.1,0.1)->
(0.9,0.7,0.3). The particle layer now bakes ramp(lum(bintA)) as its sprite
colour (noise detail in alpha) and SCROLLS it at firesmoke1's authored rate
via a texture-transform; the port's radial soft-edge mask moved to a second
CLAMPed stage so the WRAPPED scroll rolls flame through the sprite without
scrolling the edge away. Old grit x radial bake kept as the no-BINTA fallback.
Impact hits, damage-band smoke and death booms all ride this layer.
AUTHORED TEXTURE SCROLL in the model path: the BMF TEXTURE records carry
SPECIAL " SCROLL u0 v0 du dv" (tag 0x2037); the draw path always supported
per-op scrolling (SetTextureScrolling) but the BGF loader never parsed it, so
every scrolling material rendered frozen. Wired TexRef -> MatInfo -> batch ->
L4TEXOP.doScroll: the flame cards (flamebig/fire5) now roll fire noise.
VERTEX-ALPHA EFFECT CARDS (the "twisted drill bit of fire" fix): FLAMEBIG's
verts carry authored float RGBA -- white-hot base (1.0,0.99,0.97) -> dark-red
tip fading to alpha -0.2 (the DPL clamp convention). The loader kept a flat
batch colour and drew it OPAQUE = a solid orange spike. Corpus sweep: exactly
14 shipped BGFs carry vertex alpha, ALL effect cards (flames, MUZFLASH,
EXDISK_A/B/C, TMST_A/B/C, beam models, DECLOUDS). Such batches now keep the
authored per-vertex gradient and route to the alpha-blend pass, unlit,
colour = texture x gradient, alpha = the vertex fade; sky objects excluded
(drawAsSky + alphaTest passes NEITHER pass filter -- DECLOUDS stays in the
sky pass). MUZFLASH/EXDISK render correctly for free when the muzzle-model
work lands.
WRECK DRESSING (the 1996 ExplosionScripts case-4 transcription): pieces spawn
HIDDEN and reveal 0.25s after the boom (the InstanceSwitch delay, behind the
dnboom flash); flamebig hangs over the pile, Y-BILLBOARDED at the camera
(SetOffsetYaw + a camera-pos getter -- the dpl_SetDCSReorientAxes analog);
the MakeDCSFall settle arms at the reveal with the two authored rates (hulk/
debris -0.025 t^2, fires -0.01 t^2 -- the flames ride above the sinking pile
and die with it at burial). EMPTY-PLACEHOLDER hulk guard: THRDBR.BGF is a
153-byte zero-geometry stub that "loads fine" -- vertex-count check now routes
it to the gendbr fallback (a Thor wreck was invisible). Hulk content census
recorded: AVADBR==MADDBR==VULDBR geometry (palette-only prefix diffs),
RAPDBR==SNDDBR==STIDBR byte-identical -- wreck variety is materials + the
dressing, not unique piles.
LIVE-PLAY BATCH: muzzle resolve uses the named segmentIndex (raw +0xdc read
was layout garbage); forward launch frame (authored MuzzleVelocity +Z vs the
mech's -Z facing); dock-bottom single window (gauge strip appended below the
world viewport, 1100x600 default, BT_DEV_GAUGES_WINDOW=1 restores the separate
window); portrait sec surface unrotated CW; ammo counters live via typed
bridges (BTAmmoBinCountPtr/BTAmmoBinFeeding/BTWeaponAmmoBin -- raw bin+0x180
and a hand-rolled link walk were garbage); fourth fire key ('4' = Pinky);
panel/arc probes de-aliased (%61 prime).
KB: rendering.md (vertex-alpha card family + scroll), combat-damage.md (hulk
census + THRDBR stub), gauges-hud.md (ammo bridges).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
bb795e2805
commit
48c9c8444f
@@ -423,7 +423,14 @@ d3d_OBJECT* d3d_OBJECT::LoadObjectBGF(LPDIRECT3DDEVICE9 device, char *fileName)
|
||||
m.Diffuse.a = 1.0f;
|
||||
m.Ambient = m.Diffuse; // matches the .x path; lit by scene ambient even w/o direct lights
|
||||
|
||||
object->mDrawOps[i].alphaTest = object->mIsShadow != 0; // shadow -> blend pass
|
||||
// shadow -> blend pass; vertex-alpha effect cards (flame fans) too.
|
||||
// SKY objects are excluded: a drawAsSky op with alphaTest set passes
|
||||
// NEITHER pass filter (sky pass rejects alphaTest, blend pass rejects
|
||||
// drawAsSky) and vanishes -- DECLOUDS carries vertex alpha but must
|
||||
// stay in the sky pass.
|
||||
const bool vtxAlphaOp = data.batches[i].vertexAlpha && !isSkyObj;
|
||||
object->mDrawOps[i].alphaTest = (object->mIsShadow != 0) || vtxAlphaOp;
|
||||
object->mDrawOps[i].vertexAlphaBlend = vtxAlphaOp;
|
||||
object->mDrawOps[i].drawAsDecal = false;
|
||||
object->mDrawOps[i].drawAsSky = isSkyObj; // sky dome -> PASS_SKY (fullbright)
|
||||
// PUNCH (dpl_Punchize; BT_PUNCH=0 disables): cutout batch -- black texels
|
||||
@@ -435,7 +442,12 @@ d3d_OBJECT* d3d_OBJECT::LoadObjectBGF(LPDIRECT3DDEVICE9 device, char *fileName)
|
||||
object->mDrawOps[i].texture.texture = NULL;
|
||||
object->mDrawOps[i].texture.wrap_u = L4TEXOP::REPEAT;
|
||||
object->mDrawOps[i].texture.wrap_v = L4TEXOP::REPEAT;
|
||||
object->mDrawOps[i].texture.doScroll = false;
|
||||
// Authored TEXTURE SCROLL (BMF SPECIAL " SCROLL u0 v0 du dv"): the
|
||||
// firesmoke family (flamebig/fire5 flame cards) rolls its fire noise.
|
||||
// SetTextureScrolling in the draw path honours these per-op.
|
||||
object->mDrawOps[i].texture.doScroll = data.batches[i].texScroll;
|
||||
object->mDrawOps[i].texture.scrollUDelta = data.batches[i].texScrollU;
|
||||
object->mDrawOps[i].texture.scrollVDelta = data.batches[i].texScrollV;
|
||||
|
||||
const std::string &tp = data.batches[i].texPath;
|
||||
if (!tp.empty())
|
||||
@@ -863,6 +875,15 @@ void d3d_OBJECT::SetCameraPosition(float x, float y, float z)
|
||||
gCamPos.x = x; gCamPos.y = y; gCamPos.z = z;
|
||||
}
|
||||
|
||||
// The camera's world position (set once per frame above) -- the wreck flame
|
||||
// billboard (dpl_SetDCSReorientAxes analog) yaws its card toward this.
|
||||
void d3d_OBJECT::GetCameraPosition(float *x, float *y, float *z)
|
||||
{
|
||||
if (x) *x = gCamPos.x;
|
||||
if (y) *y = gCamPos.y;
|
||||
if (z) *z = gCamPos.z;
|
||||
}
|
||||
|
||||
void d3d_OBJECT::SetCullFrustum(const D3DXMATRIX *viewProj)
|
||||
{
|
||||
if (viewProj == NULL) { gCullValid = 0; return; }
|
||||
@@ -1203,6 +1224,34 @@ void d3d_OBJECT::DrawMesh(int pass, const D3DXMATRIX *viewTransform, Time target
|
||||
// 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.
|
||||
// VERTEX-ALPHA effect card (the FLAMEBIG flame fan): unlit -- the
|
||||
// authored per-vertex gradient (white-hot base -> dark faded tip) IS
|
||||
// the shading -- colour = texture x gradient, alpha = the vertex fade
|
||||
// (SRCALPHA/INVSRCALPHA). Runs only in the blend pass (the op filter
|
||||
// above routed it there; ALPHABLEND is on and z-write off pass-wide).
|
||||
DWORD sVLight = 0, sVSrc = 0, sVDst = 0, sVCop = 0, sVCa1 = 0, sVCa2 = 0, sVAop = 0, sVAa2 = 0;
|
||||
const bool vtxAlphaCard = (drawOp->vertexAlphaBlend && pass == PASS_ALPHABLEND);
|
||||
if (vtxAlphaCard)
|
||||
{
|
||||
mDevice->GetRenderState(D3DRS_LIGHTING, &sVLight);
|
||||
mDevice->GetRenderState(D3DRS_SRCBLEND, &sVSrc);
|
||||
mDevice->GetRenderState(D3DRS_DESTBLEND, &sVDst);
|
||||
mDevice->GetTextureStageState(0, D3DTSS_COLOROP, &sVCop);
|
||||
mDevice->GetTextureStageState(0, D3DTSS_COLORARG1, &sVCa1);
|
||||
mDevice->GetTextureStageState(0, D3DTSS_COLORARG2, &sVCa2);
|
||||
mDevice->GetTextureStageState(0, D3DTSS_ALPHAOP, &sVAop);
|
||||
mDevice->GetTextureStageState(0, D3DTSS_ALPHAARG2, &sVAa2);
|
||||
mDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
|
||||
mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||
mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_COLOROP,
|
||||
drawOp->texture.texture != NULL ? D3DTOP_MODULATE : D3DTOP_SELECTARG2);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
}
|
||||
|
||||
const bool copCut = (drawOp->copRole == 2 && iOp > 0
|
||||
&& mDrawOps[iOp - 1].copRole == 1
|
||||
&& mDrawOps[iOp - 1].bgfPrimCount > 0
|
||||
@@ -1266,6 +1315,17 @@ void d3d_OBJECT::DrawMesh(int pass, const D3DXMATRIX *viewTransform, Time target
|
||||
mDevice->SetRenderState(D3DRS_ALPHAREF, sARef);
|
||||
mDevice->SetRenderState(D3DRS_ALPHAFUNC, sAFunc);
|
||||
}
|
||||
if (vtxAlphaCard)
|
||||
{
|
||||
mDevice->SetRenderState(D3DRS_LIGHTING, sVLight);
|
||||
mDevice->SetRenderState(D3DRS_SRCBLEND, sVSrc);
|
||||
mDevice->SetRenderState(D3DRS_DESTBLEND, sVDst);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_COLOROP, sVCop);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, sVCa1);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_COLORARG2, sVCa2);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, sVAop);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, sVAa2);
|
||||
}
|
||||
if (drawOp->lodDepthBias != 0.0f)
|
||||
mDevice->SetRenderState(D3DRS_DEPTHBIAS, sDB);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user