Warp: exact POVTranslocateRenderable replica (collapse/throb/reveal + world mask)

Stop approximating -- replicate POVTranslocateRenderable::Execute() behaviorally,
byte-for-byte on the constants and transitions (engine T0, L4VIDRND.cpp:1763-2076),
per the user's "replicate the effect exactly".  The five prior piecemeal attempts
each fixed one facet and broke another because they left out the WHOLE mechanism.

Full state machine (btl4vid.cpp), driven by two decoupled events (NOT the
SimulationState trigger -- that dial also drives camera/POV+targeting, the f053535
regression; SetIsDead is a separate pure-render flag, verified safe):
  - LOCAL DEATH -> InitialCollapse: scale (pct_left*100)+1 over 1.3s (world visible),
    then SetIsDead(true) + WaitForReincarnate.  (btplayer VehicleDeadMessageHandler,
    deathCount==-1, local-guarded.)
  - WaitForReincarnate: world BLACK (mask), scale 1, Lissajous throb
    (cos(t*3.33), sin(t*2.5)) x2.0 -- the "dances around playfully".
  - LOCAL RESPAWN -> ExpandReveal: SetIsDead(false) + scale (pct_used*150)+1 over
    1.0s -- blasts open, world revealed ("shoots off into the distance").  (btplayer
    DropZoneReplyMessageHandler, local-guarded.)

Draw EXACTLY as the engine (isDeathDraw -> drawAsSky): PASS_SKY, OPAQUE,
CULLMODE=CW, z-test ON (L4VIDEO.cpp:7526/7568-7570/7693).  This kills the "glitchy
funnel" -- opaque = one write/pixel (no translucent double-blend), CW = one winding
of the double-sided mesh (no coincident z-fight), z-on = the expand shell is
occluded/revealed by the returning world.  Placement = Scale * inverse(view) with
NO recenter (the mesh is authored off-origin so the eye sits inside, authentic);
dropped the wrong mCullCenter recenter and the Z-off overlay hack.  Colour is the
"sky" ramp (per prior commit); no geometry spin (myRotateY is dead) -- swirl is the
texture scroll.  SetIsDead reached via a BTSetWorldDead bridge (L4VIDRND.cpp).

STUCK-BLACK SAFETY (the one new risk of decoupling mask-on from mask-off): a 12s
WaitForReincarnate render-loop timeout un-masks if no respawn arrives, plus
BTWarpForceUnmask on the mission-ending + no-DropZones abort paths.  Smoke-verified
2-node: collapse->wait(masked=1)->expand(masked=0), ends masked=0, no crash.

The peer-observer warp stays a world-anchored translucent alpha draw (port
extension; the authentic effect is POV-only).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-10 09:43:54 -05:00
co-authored by Claude Opus 4.8
parent 062c66999e
commit a35f321ba1
4 changed files with 284 additions and 165 deletions
+4 -3
View File
@@ -7788,9 +7788,10 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte
BTDrawPfx(mDevice, &viewTransform, (float)dT);
}
// BT translocation spheres (task #52): the "blue warp" that collapses onto a
// dying mech and expands to reveal the reborn one -- one per watched player,
// keyed on its SimulationState dial. Same alpha pass as the beams/pfx.
// BT translocation spheres (task #52): the authentic POVTranslocateRenderable
// warp -- collapse onto the dying eye, throb black, then expand-reveal the reborn
// world. Drawn out-of-band here (as SKY, opaque) even while IsDead so the sphere
// survives the world mask it itself raises via BTSetWorldDead (below).
{
extern void BTDrawTranslocationSpheres(LPDIRECT3DDEVICE9 dev,
const D3DXMATRIX *view, float dt, Time frame_time);
+16
View File
@@ -1746,6 +1746,22 @@ void
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor for POVTranslocateRenderable
//
// BT (task #52): world-mask bridge for the reconstructed translocation warp. The
// authentic POVTranslocateRenderable toggles l4_application->SetIsDead around its
// collapse/expand (L4VIDRND.cpp:1947/1989) to black out the world during the death
// throb and reveal it on rebirth. Our reconstruction drives the warp from
// btl4vid.cpp (no L4Application handle there), so expose the same flag through this
// bridge. It is a PURE render-pass gate (verified: every IsDead() reader is a draw
// loop -- terrain/decal/sky/alpha/particles/reticle; no camera/input/targeting), so
// driving it directly is safe -- unlike pulsing the SimulationState trigger, which
// also drives the camera/POV + targeting (the f053535 regression).
void BTSetWorldDead(int dead)
{
L4Application *l4_application = Cast_Object(L4Application*, application);
if (l4_application != 0)
l4_application->SetIsDead(dead != 0);
}
POVTranslocateRenderable::POVTranslocateRenderable(
Entity *entity, // Entity to attach the renderable to
ExecutionType execution_type, // How/when to execute the renderable