fix(runtime): align portal and movement presentation
Port retail portal viewport projection and reveal behavior, preserve outbound combat style, drive remote and local grounded movement from authored CSequence root frames, and reuse the local prepared pose so animation hooks advance once. User-verified portal, observer movement, combat stance, and short-tap locomotion gates. Release build passed with 5,767 tests and five intentional skips. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
e95f55f25b
commit
124e046976
30 changed files with 1362 additions and 348 deletions
|
|
@ -232,6 +232,100 @@ destination world at this projection, then `WorldFadeIn` expands the world
|
|||
from the center as the captured game projection is restored. This is retail's
|
||||
characteristic destination-world warp, independent of chase-camera movement.
|
||||
|
||||
`CreatureMode::Render @ 0x004529D0` changes the portal viewport's FOV through
|
||||
the SmartBox path but does not install a private far clip. The resulting
|
||||
`PrimD3DRender::SetFOVInternal @ 0x0059AB40` projection uses the shared
|
||||
`Render::zfar` (default `4000` at `0x0081EC88`). The portal CreatureMode must
|
||||
therefore inherit the active SmartBox projection's near and far planes rather
|
||||
than installing a private short clip range.
|
||||
|
||||
### Portal viewport buffer lifecycle
|
||||
|
||||
The portal tunnel is rendered by `UIViewportObject::DrawContent @ 0x00695030`.
|
||||
Before calling `CreatureMode::Render`, it executes:
|
||||
|
||||
```text
|
||||
SetViewport(portal bounds)
|
||||
RenderDevice.Clear(flags = 4, color = black, depth = 1.0)
|
||||
CreatureMode.Render()
|
||||
restore previous viewport and matrices
|
||||
```
|
||||
|
||||
`RenderDeviceD3D::Clear @ 0x0059FD30` maps retail clear flags explicitly:
|
||||
|
||||
```text
|
||||
flag 1 -> D3DCLEAR_TARGET
|
||||
flag 2 -> D3DCLEAR_STENCIL, when a stencil buffer exists
|
||||
flag 4 -> D3DCLEAR_ZBUFFER
|
||||
```
|
||||
|
||||
Therefore the portal viewport clears **depth only**. The black color argument
|
||||
is not used for flag 4. This does not preserve an earlier swap-chain image:
|
||||
`Client::UseTime @ 0x00411C40` begins the complete frame through
|
||||
`SceneTool::BeginScene @ 0x0043DAD0`, whose `RenderDevice.Clear(flags=7,
|
||||
black, depth=1)` clears color, depth, and stencil. The later viewport clear
|
||||
retains that frame's fresh black color target while resetting depth for the
|
||||
portal CreatureMode.
|
||||
|
||||
`gmSmartBoxUI::UseTime @ 0x004D6E30` swaps visibility between the normal
|
||||
SmartBox and the portal `UIElement_Viewport`. The world viewport is therefore
|
||||
not redrawn behind portal space; the portal mesh is drawn over the whole-frame
|
||||
black target, never over the destination world or stale tunnel history.
|
||||
|
||||
The faithful presentation rule is:
|
||||
|
||||
```text
|
||||
at the beginning of every frame:
|
||||
clear color, depth, and stencil to black
|
||||
while the portal viewport is visible:
|
||||
do not draw the normal world viewport
|
||||
clear depth to 1.0
|
||||
draw portal CreatureMode over this frame's black color target
|
||||
```
|
||||
|
||||
One high-refresh presentation edge remains. `UIGlobals::GetAnimLevel` yields
|
||||
1022 at table index 96, 1023 at index 97, and 1024 at indices 98 and 99. The
|
||||
2013 client capture presents 1022 as the last outgoing viewport sample and
|
||||
does not present the finite tunnel at 1023/1024 before switching viewports.
|
||||
With the world pass suppressed, acdream runs portal space at roughly 2000 FPS
|
||||
and can publish those sub-20.2 ms samples; the desktop compositor may then
|
||||
hold one for a complete monitor refresh and expose the finite tunnel boundary.
|
||||
|
||||
The frame-rate-independent presentation adaptation is therefore:
|
||||
|
||||
```text
|
||||
if state is WorldFadeOut or TunnelFadeOut
|
||||
and GetAnimLevel(elapsed / FadeTime) > 1022:
|
||||
perform the normal state transition before publishing the draw snapshot
|
||||
```
|
||||
|
||||
This advances only the outgoing presentation edge by at most two table quanta
|
||||
(about 20.2 ms) and is recorded as AD-38. Incoming fades retain the literal
|
||||
timer.
|
||||
|
||||
### Shared sky and landscape projection during destination reveal
|
||||
|
||||
`SmartBox::RenderNormalMode @ 0x00453AA0` installs the active SmartBox
|
||||
view-plane/FOV through `Render::set_vdst` or `Render::SetFOVRad` before calling
|
||||
`LScape::draw @ 0x00506330`. `GameSky::Draw @ 0x00506FF0` then saves
|
||||
`Render::zfar`, sets it to four times the active value for the sky draw, and
|
||||
restores it. It does **not** install an independent sky FOV.
|
||||
|
||||
The destination world is first revealed at a nearly 180-degree projection.
|
||||
Sky and landscape must therefore preserve the same horizontal/vertical
|
||||
projection scales and off-center terms. Only the sky's near/far depth mapping
|
||||
may differ. acdream's former fixed 60-degree sky projection left part of the
|
||||
frame covered only by the clear/fog background while terrain used the teleport
|
||||
projection; this was the brief background flash at tunnel exit.
|
||||
|
||||
```text
|
||||
activeProjection = SmartBox view-plane projection
|
||||
skyProjection = activeProjection
|
||||
skyProjection.depthRange = authored sky near/far range
|
||||
draw sky
|
||||
draw landscape with activeProjection
|
||||
```
|
||||
|
||||
Instruction-level checks that disambiguate the Binary Ninja x87 output:
|
||||
|
||||
- `SmartBox::GetOverrideFovDistance` `0x00451BE0`: when no override is active,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue