refactor(render): move root-cell dynamics onto walk turns
This commit is contained in:
parent
f9a80fbc44
commit
474b05e7dc
4 changed files with 54 additions and 29 deletions
|
|
@ -1354,7 +1354,9 @@ internal sealed class RenderScenePViewFrameBuilder
|
||||||
RenderProjectionRecord record = _dynamics[i];
|
RenderProjectionRecord record = _dynamics[i];
|
||||||
uint? parentCellId = ParentCell(in record);
|
uint? parentCellId = ParentCell(in record);
|
||||||
if (parentCellId is uint parentCell
|
if (parentCellId is uint parentCell
|
||||||
&& _lookInCellScratch.Contains(parentCell))
|
&& (_lookInCellScratch.Contains(parentCell)
|
||||||
|
|| (input.WalkLookInViews is not null
|
||||||
|
&& input.RootFloodCells.Contains(parentCell))))
|
||||||
continue;
|
continue;
|
||||||
Sphere(in record, out Vector3 center, out float radius);
|
Sphere(in record, out Vector3 center, out float radius);
|
||||||
bool outside = RetailPViewRenderer.DynamicDrawsInOutsideStage(
|
bool outside = RetailPViewRenderer.DynamicDrawsInOutsideStage(
|
||||||
|
|
@ -1427,6 +1429,17 @@ internal sealed class RenderScenePViewFrameBuilder
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FW4: an active walk draws every root-flood cell's complete
|
||||||
|
// object list at that cell's own PView::DrawCells turn. The
|
||||||
|
// packed last pass must not duplicate those live objects after
|
||||||
|
// the walk has already established their correct wall depth.
|
||||||
|
if (indoor
|
||||||
|
&& input.WalkLookInViews is not null
|
||||||
|
&& input.RootFloodCells.Contains(parentCellId!.Value))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// The stage-set split (synthesis plan step 4, [dyn-route]-pinned
|
// The stage-set split (synthesis plan step 4, [dyn-route]-pinned
|
||||||
// 2026-08-30): an interior-parented dynamic rides the LAST pass
|
// 2026-08-30): an interior-parented dynamic rides the LAST pass
|
||||||
// ONLY when its parent cell is in THE WALK'S OWN ROOT FLOOD.
|
// ONLY when its parent cell is in THE WALK'S OWN ROOT FLOOD.
|
||||||
|
|
|
||||||
|
|
@ -518,7 +518,7 @@ internal sealed class WalkFrameDriver : IWalkEventSink, IWalkLookInViewSource
|
||||||
private bool _skyDrawnThisFrame;
|
private bool _skyDrawnThisFrame;
|
||||||
private WalkDrawStage? _currentDcStage;
|
private WalkDrawStage? _currentDcStage;
|
||||||
private bool _readyToReplay;
|
private bool _readyToReplay;
|
||||||
private int _lookInRouteIndex;
|
private int _cellViewRouteIndex;
|
||||||
|
|
||||||
internal WalkFrameDriver(
|
internal WalkFrameDriver(
|
||||||
WbDrawDispatcher dispatcher,
|
WbDrawDispatcher dispatcher,
|
||||||
|
|
@ -626,7 +626,7 @@ internal sealed class WalkFrameDriver : IWalkEventSink, IWalkLookInViewSource
|
||||||
VisitedBuildings.Clear();
|
VisitedBuildings.Clear();
|
||||||
VisitedLandscapeCellIds.Clear();
|
VisitedLandscapeCellIds.Clear();
|
||||||
InteriorFloodCells.Clear();
|
InteriorFloodCells.Clear();
|
||||||
_lookInRouteIndex = 0;
|
_cellViewRouteIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Records the final segment mark (plan §FW3.2b-1's "at frame
|
/// <summary>Records the final segment mark (plan §FW3.2b-1's "at frame
|
||||||
|
|
@ -981,36 +981,35 @@ internal sealed class WalkFrameDriver : IWalkEventSink, IWalkLookInViewSource
|
||||||
_stream, stage, cellId, records.Records, records.TupleLandblockId,
|
_stream, stage, cellId, records.Records, records.TupleLandblockId,
|
||||||
_cameraWorldPosition, _viewProjection);
|
_cameraWorldPosition, _viewProjection);
|
||||||
MarkIfGrown();
|
MarkIfGrown();
|
||||||
|
|
||||||
|
// PView::DrawObjCellForDummies draws this cell's live objects at the
|
||||||
|
// same turn as its statics. Capture the currently installed portal
|
||||||
|
// views before the walk pops them, then apply retail's per-GfxObj
|
||||||
|
// drawing-sphere viewcone check in the walk classifier.
|
||||||
|
int viewRouteIndex = _cellViewRouteIndex++;
|
||||||
|
CaptureCellViews(cellId);
|
||||||
if (stage == WalkDrawStage.LookInStatic)
|
if (stage == WalkDrawStage.LookInStatic)
|
||||||
{
|
{
|
||||||
// Retail draws a look-in cell's complete object list at this
|
|
||||||
// re-entrant DrawCells turn. The packed dynamic route used to run
|
|
||||||
// much later at the pre-clear boundary, after nearer building
|
|
||||||
// shells, which let the cathedral's 0x112 remote player overpaint
|
|
||||||
// opaque walls. Keep animation/fade in the packed route, but replay
|
|
||||||
// it here between this cell's content and the building shell.
|
|
||||||
int routeIndex = _lookInRouteIndex++;
|
|
||||||
LookInCellTurns.Add(cellId);
|
LookInCellTurns.Add(cellId);
|
||||||
LookInCells.Add(cellId);
|
LookInCells.Add(cellId);
|
||||||
CaptureLookInViews(cellId);
|
|
||||||
|
|
||||||
WalkFrameStaticRecords dynamics = _worldData.GetCellDynamics(cellId);
|
|
||||||
_populator.PopulateCellDynamics(
|
|
||||||
_stream,
|
|
||||||
cellId,
|
|
||||||
dynamics.Records,
|
|
||||||
dynamics.TupleLandblockId,
|
|
||||||
_cameraWorldPosition,
|
|
||||||
_viewProjection,
|
|
||||||
this,
|
|
||||||
routeIndex);
|
|
||||||
MarkIfGrown();
|
|
||||||
if (HasAnyOwner(records) || HasAnyOwner(dynamics))
|
|
||||||
_events.Add(WalkFrameEvent.CellParticles(cellId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WalkFrameStaticRecords dynamics = _worldData.GetCellDynamics(cellId);
|
||||||
|
_populator.PopulateCellDynamics(
|
||||||
|
_stream,
|
||||||
|
cellId,
|
||||||
|
dynamics.Records,
|
||||||
|
dynamics.TupleLandblockId,
|
||||||
|
_cameraWorldPosition,
|
||||||
|
_viewProjection,
|
||||||
|
this,
|
||||||
|
viewRouteIndex);
|
||||||
|
MarkIfGrown();
|
||||||
|
if (HasAnyOwner(records) || HasAnyOwner(dynamics))
|
||||||
|
_events.Add(WalkFrameEvent.CellParticles(cellId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CaptureLookInViews(uint cellId)
|
private void CaptureCellViews(uint cellId)
|
||||||
{
|
{
|
||||||
IWalkBuildingFrameContext ctx = RequireOpenFrame();
|
IWalkBuildingFrameContext ctx = RequireOpenFrame();
|
||||||
WalkCell? cell = ctx.GetVisible(cellId);
|
WalkCell? cell = ctx.GetVisible(cellId);
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,15 @@ public sealed class RenderScenePViewFrameProductTests
|
||||||
0x0100_0000_0000_0022,
|
0x0100_0000_0000_0022,
|
||||||
RenderProjectionClass.LiveDynamicRoot,
|
RenderProjectionClass.LiveDynamicRoot,
|
||||||
parentCell: lookInCell);
|
parentCell: lookInCell);
|
||||||
scene.Apply([RenderProjectionDelta.Register(Generation, 1, lookInDynamic)]);
|
RenderProjectionRecord rootDynamic = Record(
|
||||||
|
0x0100_0000_0000_0023,
|
||||||
|
RenderProjectionClass.LiveDynamicRoot,
|
||||||
|
parentCell: Cell);
|
||||||
|
scene.Apply(
|
||||||
|
[
|
||||||
|
RenderProjectionDelta.Register(Generation, 1, lookInDynamic),
|
||||||
|
RenderProjectionDelta.Register(Generation, 2, rootDynamic),
|
||||||
|
]);
|
||||||
|
|
||||||
PortalVisibilityFrame portal = Portal(Cell);
|
PortalVisibilityFrame portal = Portal(Cell);
|
||||||
ClipFrameAssembly clip = FullScreenClip(Cell);
|
ClipFrameAssembly clip = FullScreenClip(Cell);
|
||||||
|
|
@ -298,6 +306,9 @@ public sealed class RenderScenePViewFrameProductTests
|
||||||
Assert.DoesNotContain(
|
Assert.DoesNotContain(
|
||||||
frame.RouteRanges.ToArray(),
|
frame.RouteRanges.ToArray(),
|
||||||
candidate => candidate.Route == RenderFrameCandidateRoute.LookInObject);
|
candidate => candidate.Route == RenderFrameCandidateRoute.LookInObject);
|
||||||
|
Assert.DoesNotContain(
|
||||||
|
frame.RouteCandidates.ToArray(),
|
||||||
|
candidate => candidate.Id == rootDynamic.Id);
|
||||||
Assert.NotNull(frame.WalkLookInViews);
|
Assert.NotNull(frame.WalkLookInViews);
|
||||||
Assert.False(frame.WalkLookInViews!.SphereVisibleInLookInTurn(
|
Assert.False(frame.WalkLookInViews!.SphereVisibleInLookInTurn(
|
||||||
routeIndex: 0,
|
routeIndex: 0,
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,8 @@ public sealed class WalkFrameDriverTests
|
||||||
{
|
{
|
||||||
"SKY", "TERRAIN:0", "CLEAR", "SEALS",
|
"SKY", "TERRAIN:0", "CLEAR", "SEALS",
|
||||||
"SHELL:00000101", "SHELL:00000100",
|
"SHELL:00000101", "SHELL:00000100",
|
||||||
"FLUSH:1:CellStatic", "FLUSH:1:CellStatic",
|
"FLUSH:1:CellStatic", "CELL-PARTICLES:00000101:66",
|
||||||
|
"FLUSH:1:CellStatic", "CELL-PARTICLES:00000100:65",
|
||||||
},
|
},
|
||||||
log);
|
log);
|
||||||
|
|
||||||
|
|
@ -336,7 +337,8 @@ public sealed class WalkFrameDriverTests
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
"CLEAR", "SEALS", "SHELL:00000101", "SHELL:00000100",
|
"CLEAR", "SEALS", "SHELL:00000101", "SHELL:00000100",
|
||||||
"FLUSH:1:CellStatic", "FLUSH:1:CellStatic",
|
"FLUSH:1:CellStatic", "CELL-PARTICLES:00000101:66",
|
||||||
|
"FLUSH:1:CellStatic", "CELL-PARTICLES:00000100:65",
|
||||||
},
|
},
|
||||||
log);
|
log);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue