refactor(render): require the production frame walk
This commit is contained in:
parent
cd08cd2ae8
commit
1be4889c1c
1 changed files with 51 additions and 303 deletions
|
|
@ -162,75 +162,39 @@ public sealed class RetailPViewRenderer
|
||||||
ArgumentNullException.ThrowIfNull(ctx);
|
ArgumentNullException.ThrowIfNull(ctx);
|
||||||
ArgumentNullException.ThrowIfNull(passes);
|
ArgumentNullException.ThrowIfNull(passes);
|
||||||
passes.BeginFrame();
|
passes.BeginFrame();
|
||||||
RecycleLookInFrames();
|
// Campaign FW4: there is one production renderer and one visibility
|
||||||
ResetBuildingGroups();
|
// owner. The fake/legacy executor path was useful during the cutover,
|
||||||
|
// but retaining it here kept the retired PortalVisibilityBuilder and
|
||||||
// Campaign FW4 production cutover: decide the walk route before any
|
// look-in seed machinery alive. Fail loudly if composition ever tries
|
||||||
// old PView construction. A concrete production executor must have all
|
// to reintroduce that split.
|
||||||
// walk registries; otherwise the frame is miswired and fails loud.
|
RetailPViewPassExecutor walkExecutor = passes as RetailPViewPassExecutor
|
||||||
RetailPViewPassExecutor? walkExecutor = passes as RetailPViewPassExecutor;
|
?? throw new InvalidOperationException(
|
||||||
bool walkRegistriesReady =
|
"The retail frame walk requires RetailPViewPassExecutor.");
|
||||||
_walkBuildings is not null
|
if (_renderSceneShadow is null
|
||||||
&& _walkLandscape is not null
|
|| _walkBuildings is null
|
||||||
&& _walkCellRegistry is not null
|
|| _walkLandscape is null
|
||||||
&& _walkWorldData is not null;
|
|| _walkCellRegistry is null
|
||||||
if (walkExecutor is not null
|
|| _walkWorldData is null)
|
||||||
&& _renderSceneShadow is not null
|
|
||||||
&& !walkRegistriesReady)
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"RetailPViewRenderer has a concrete pass executor and a "
|
"The retail frame walk requires the retained scene and all "
|
||||||
+ "RenderSceneShadowRuntime but the walk registries "
|
+ "committed walk registries.");
|
||||||
+ "(WalkBuildingRegistry/WalkLandscapeAssembler/CellVisibility) are "
|
|
||||||
+ "not all wired — the Campaign FW3.2b-2 static cutover requires "
|
|
||||||
+ "every piece together; see FrameRootComposition's "
|
|
||||||
+ "RetailPViewRenderer construction.");
|
|
||||||
}
|
}
|
||||||
bool walkActive =
|
|
||||||
walkExecutor is not null
|
|
||||||
&& _renderSceneShadow is not null
|
|
||||||
&& walkRegistriesReady;
|
|
||||||
|
|
||||||
PortalVisibilityFrame pvFrame;
|
// Compatibility carrier only. Production visibility is populated
|
||||||
if (walkActive)
|
// exclusively by RetailFrameWalk below; this frame supplies the clip
|
||||||
|
// assembler's outdoor full-screen seed until that carrier is removed.
|
||||||
|
PortalVisibilityFrame pvFrame = _mainPortalFrameScratch;
|
||||||
|
pvFrame.ResetForBuild();
|
||||||
|
if (ctx.RootCell.IsOutdoorNode)
|
||||||
{
|
{
|
||||||
// Compatibility carrier only. Production visibility is populated
|
pvFrame.OutsideView.SetFullScreen();
|
||||||
// exclusively by RetailFrameWalk below; this frame supplies the
|
pvFrame.OrderedVisibleCells.Add(ctx.RootCell.CellId);
|
||||||
// clip assembler's outdoor full-screen seed until that remaining
|
|
||||||
// shell is deleted later in FW4.
|
|
||||||
pvFrame = _mainPortalFrameScratch;
|
|
||||||
pvFrame.ResetForBuild();
|
|
||||||
if (ctx.RootCell.IsOutdoorNode)
|
|
||||||
{
|
|
||||||
pvFrame.OutsideView.SetFullScreen();
|
|
||||||
pvFrame.OrderedVisibleCells.Add(ctx.RootCell.CellId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Standalone/fake executor compatibility. Production never calls
|
|
||||||
// PortalVisibilityBuilder after the FW4 cutover above.
|
|
||||||
pvFrame = PortalVisibilityBuilder.Build(
|
|
||||||
ctx.RootCell,
|
|
||||||
ctx.ViewerEyePos,
|
|
||||||
ctx.Cells.Find,
|
|
||||||
ctx.ViewProjection,
|
|
||||||
buildingMembership: null,
|
|
||||||
reuseFrame: _mainPortalFrameScratch);
|
|
||||||
|
|
||||||
if (ctx.RootCell.IsOutdoorNode && ctx.NearbyBuildingCells is not null)
|
|
||||||
MergeNearbyBuildingFloods(ctx, pvFrame);
|
|
||||||
if (!ctx.RootCell.IsOutdoorNode
|
|
||||||
&& ctx.NearbyBuildingCells is not null
|
|
||||||
&& pvFrame.OutsideView.Polygons.Count > 0)
|
|
||||||
BuildInteriorRootLookIns(ctx, pvFrame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var clipAssembly = passes.AssembleClipFrame(
|
var clipAssembly = passes.AssembleClipFrame(
|
||||||
pvFrame,
|
pvFrame,
|
||||||
_clipAssemblyScratch);
|
_clipAssemblyScratch);
|
||||||
if (!walkActive)
|
|
||||||
passes.AppendLookInClipFrames(_lookInFrames, clipAssembly);
|
|
||||||
// FW4 slice 1: PrepareClipFrame (the one clip-region publication)
|
// FW4 slice 1: PrepareClipFrame (the one clip-region publication)
|
||||||
// moved BELOW the walk block — an interior-rooted walk frame
|
// moved BELOW the walk block — an interior-rooted walk frame
|
||||||
// re-derives the outside-view slices from the walk's own views
|
// re-derives the outside-view slices from the walk's own views
|
||||||
|
|
@ -262,8 +226,7 @@ public sealed class RetailPViewRenderer
|
||||||
// runs at append time, not at Replay time), so the world data must
|
// runs at append time, not at Replay time), so the world data must
|
||||||
// already be rebuilt for this frame before the walk starts.
|
// already be rebuilt for this frame before the walk starts.
|
||||||
Walk.WalkFrameDriver? walkDriver = null;
|
Walk.WalkFrameDriver? walkDriver = null;
|
||||||
WalkProductionLeafRenderer? walkLeafRenderer = null;
|
WalkProductionLeafRenderer walkLeafRenderer;
|
||||||
if (walkActive)
|
|
||||||
{
|
{
|
||||||
Matrix4x4 view = ctx.CameraView;
|
Matrix4x4 view = ctx.CameraView;
|
||||||
var forward = Vector3.Normalize(new Vector3(-view.M13, -view.M23, -view.M33));
|
var forward = Vector3.Normalize(new Vector3(-view.M13, -view.M23, -view.M33));
|
||||||
|
|
@ -441,31 +404,8 @@ public sealed class RetailPViewRenderer
|
||||||
int terrainUploadCount = checked(1 + clipAssembly.OutsideViewSlices.Length * 2);
|
int terrainUploadCount = checked(1 + clipAssembly.OutsideViewSlices.Length * 2);
|
||||||
passes.PrepareClipFrame(terrainUploadCount);
|
passes.PrepareClipFrame(terrainUploadCount);
|
||||||
|
|
||||||
// Production prepares exactly the walk's visited-cell set. The
|
// Production prepares exactly the one walk's visited-cell set.
|
||||||
// legacy builder's main-flood/look-in union survives only for
|
HashSet<uint> prepareCells = drawableCells;
|
||||||
// standalone fake executors until the shell-deletion slice.
|
|
||||||
var prepareCells = drawableCells;
|
|
||||||
_lookInCellIds.Clear();
|
|
||||||
if (walkActive)
|
|
||||||
{
|
|
||||||
_lookInPrepareScratch.Clear();
|
|
||||||
_lookInPrepareScratch.UnionWith(walkDriver!.VisitedCells);
|
|
||||||
prepareCells = _lookInPrepareScratch;
|
|
||||||
}
|
|
||||||
else if (_lookInFrames.Count > 0)
|
|
||||||
{
|
|
||||||
_lookInPrepareScratch.Clear();
|
|
||||||
_lookInPrepareScratch.UnionWith(drawableCells);
|
|
||||||
foreach (var f in _lookInFrames)
|
|
||||||
{
|
|
||||||
foreach (uint c in f.OrderedVisibleCells)
|
|
||||||
{
|
|
||||||
_lookInPrepareScratch.Add(c);
|
|
||||||
_lookInCellIds.Add(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prepareCells = _lookInPrepareScratch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (#176 correction, 2026-07-06: the flood-scoped light-pool rebuild that ran
|
// (#176 correction, 2026-07-06: the flood-scoped light-pool rebuild that ran
|
||||||
// here was the seam-floor flicker mechanism — retail's visible_cell_table is
|
// here was the seam-floor flicker mechanism — retail's visible_cell_table is
|
||||||
|
|
@ -474,80 +414,12 @@ public sealed class RetailPViewRenderer
|
||||||
|
|
||||||
passes.PrepareCellBatches(ctx, prepareCells);
|
passes.PrepareCellBatches(ctx, prepareCells);
|
||||||
|
|
||||||
// T1 (fused BR-2/3): retail's frame order — static world, then the
|
|
||||||
// aperture depth writes, then interior cells WHOLE far→near, then
|
|
||||||
// per-cell statics, then ALL dynamics last (retail draws objects after
|
|
||||||
// cells: PView::DrawCells Ghidra 0x005a4840; DrawBuilding 0x0059f2a0).
|
|
||||||
// The geometric shell chop (gl_ClipDistance crop, 927fd8f/9ce335e) is
|
|
||||||
// DELETED — retail never clips cell geometry; aperture exactness comes
|
|
||||||
// from the punch/seal depth writes + the z-buffer, and the dynamics-
|
|
||||||
// last order is what makes the punch safe (the first BR-2 attempt
|
|
||||||
// punched after dynamics and erased the player, reverted 88be519).
|
|
||||||
// T3 (BR-5): retail viewconeCheck — meshes are sphere-CULLED per view,
|
|
||||||
// never clipped (Ghidra 0x0054c250). Built once per frame from the
|
|
||||||
// assembled slices + this frame's view-projection.
|
|
||||||
var viewcone = ViewconeCuller.Build(
|
|
||||||
clipAssembly,
|
|
||||||
ctx.ViewProjection,
|
|
||||||
_viewconeScratch);
|
|
||||||
|
|
||||||
// Packed frame routes no longer participate in production. These
|
|
||||||
// placeholders keep the standalone legacy/fake path self-contained
|
|
||||||
// until FW4 removes that shell completely.
|
|
||||||
IRenderFrameEntityPassExecutor? frameEntityPasses = null;
|
|
||||||
RenderFrameView frameView = default;
|
|
||||||
_candidateObserver?.BeginPViewFrame();
|
_candidateObserver?.BeginPViewFrame();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// FW4 slice 3: the outside-stage predicate's flood-membership set
|
RenderProjectionCounts retainedCounts = _renderSceneShadow.Counts;
|
||||||
// is THE WALK'S visited cells on walk frames (root flood +
|
RenderFrameDiagnosticCounts counts = WalkDiagnosticCounts(retainedCounts);
|
||||||
// look-in floods — retail draws all of their objects inside
|
RenderProjectionCounts sourceCounts = retainedCounts;
|
||||||
// LScape::draw, pre-clear). The old apparatus's drawableCells
|
|
||||||
// misses cells at the #456 seam band, dropping interior-parented
|
|
||||||
// outdoor emitters (the cathedral falls weenies) to the
|
|
||||||
// post-clear last pass, where the cleared depth lets them splat
|
|
||||||
// across terrain and water. drawableCells keeps its other roles
|
|
||||||
// (prepare filter, frame result) unchanged.
|
|
||||||
HashSet<uint> outsideStageFlood =
|
|
||||||
walkActive ? walkDriver!.VisitedCells : drawableCells;
|
|
||||||
|
|
||||||
// The stage-set split: the walk's TRUE root flood (never the
|
|
||||||
// visited union) keys which interior-parented dynamics may ride
|
|
||||||
// the last pass — see BuildOutsideDynamicRoutes' sibling gate.
|
|
||||||
_rootFloodSetScratch.Clear();
|
|
||||||
if (walkActive)
|
|
||||||
{
|
|
||||||
foreach (uint cellId in walkDriver!.InteriorFloodCells)
|
|
||||||
_rootFloodSetScratch.Add(cellId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The walk reads the retained scene directly. Rebuild the former
|
|
||||||
// WorldEntity partition only for the standalone fallback and
|
|
||||||
// explicitly enabled comparison/probe paths.
|
|
||||||
InteriorEntityPartition.Result? partition = null;
|
|
||||||
if (!walkActive || LegacyPartitionDiagnosticsEnabled)
|
|
||||||
{
|
|
||||||
InteriorEntityPartition.Partition(
|
|
||||||
_partitionResult,
|
|
||||||
prepareCells,
|
|
||||||
ctx.LandblockEntries,
|
|
||||||
_partitionObserver,
|
|
||||||
ctx.Frustum,
|
|
||||||
ctx.PlayerLandblockId ?? 0u);
|
|
||||||
partition = _partitionResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderProjectionCounts retainedCounts = walkActive
|
|
||||||
? _renderSceneShadow!.Counts
|
|
||||||
: default;
|
|
||||||
RenderFrameDiagnosticCounts counts = walkActive
|
|
||||||
? WalkDiagnosticCounts(retainedCounts)
|
|
||||||
: LegacyDiagnosticCounts(partition!);
|
|
||||||
RenderProjectionCounts sourceCounts = walkActive
|
|
||||||
? retainedCounts
|
|
||||||
: LegacySourceCounts(partition!);
|
|
||||||
// prepareCells is exactly "main flood ∪ look-in cells" — the cells
|
|
||||||
// this traversal actually reached, i.e. retail's in-view set.
|
|
||||||
RetailPViewFrameResult result = _frameResultScratch.Reset(
|
RetailPViewFrameResult result = _frameResultScratch.Reset(
|
||||||
pvFrame,
|
pvFrame,
|
||||||
clipAssembly,
|
clipAssembly,
|
||||||
|
|
@ -555,164 +427,40 @@ public sealed class RetailPViewRenderer
|
||||||
prepareCells,
|
prepareCells,
|
||||||
counts,
|
counts,
|
||||||
sourceCounts,
|
sourceCounts,
|
||||||
partition);
|
diagnosticPartition: null);
|
||||||
passes.EmitDiagnostics(ctx, result);
|
passes.EmitDiagnostics(ctx, result);
|
||||||
|
|
||||||
// Campaign FW3.2b-2 flip apparatus (ACDREAM_PROBE_WALK_SHADOW=1,
|
// The one collected walk owns terrain, cell shells, buildings,
|
||||||
// throwaway — dies with the flip commit): run the PRODUCTION
|
// statics, dynamics, particles, punches, and alpha barriers at
|
||||||
// retail frame walk in shadow and report set divergence vs this
|
// their retail turns. Interior-root landscape services run at the
|
||||||
// frame's old-path visibility. No draws change.
|
// pre-clear callback; outdoor roots have no clear and run after
|
||||||
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbeWalkShadowEnabled)
|
// replay.
|
||||||
RunWalkShadowProbe(ctx, prepareCells);
|
Walk.WalkFrameDriver capturedDriver = walkDriver!;
|
||||||
|
_walkPreClearDynamics = () =>
|
||||||
// #118: stage assignment for dynamics under an INTERIOR root. Retail
|
|
||||||
// draws the OUTSIDE world's objects inside the landscape stage —
|
|
||||||
// PView::DrawCells runs LScape::draw FIRST (pc:432719), then the gated
|
|
||||||
// full depth clear (pc:432731-432732) and the exit-portal SEALS
|
|
||||||
// (pc:432785-432786); DrawBlock draws every landcell's objects via
|
|
||||||
// DrawSortCell (0x005a17c0, pc:430124). A dynamic deferred to our
|
|
||||||
// single last pass instead z-fails against the seal's true-depth stamp
|
|
||||||
// the moment it stands beyond the door plane — the house-exit
|
|
||||||
// clip+vanish (pinned by HouseExitWalkReplayTests). So under an
|
|
||||||
// interior root: outdoor-classified dynamics draw in the outside
|
|
||||||
// stage; an indoor dynamic whose sphere STRADDLES an exit portal
|
|
||||||
// draws in BOTH stages (retail's per-overlapped-cell shadow-part
|
|
||||||
// draw, DrawBlock pc:430056-430064) so neither body half clips at the
|
|
||||||
// plane. Outdoor roots keep ALL dynamics in the last pass — our
|
|
||||||
// z-buffered equivalent of retail's painter-ordered outdoor pass (the
|
|
||||||
// BR-2 punch-after-dynamics lesson, reverted 88be519).
|
|
||||||
_outsideStageDynamics.Clear();
|
|
||||||
if (partition is not null && !ctx.RootCell.IsOutdoorNode)
|
|
||||||
{
|
{
|
||||||
foreach (var e in partition.Dynamics)
|
passes.UseIndoorMembershipOnlyRouting();
|
||||||
{
|
DrawLandscapeDynamicsPhase(
|
||||||
EntitySphere(e, out var c, out float r);
|
ctx,
|
||||||
// FW4 slice 3: same walk-flood membership set as the
|
passes,
|
||||||
// frame product's BuildOutsideDynamicRoutes — the two
|
clipAssembly,
|
||||||
// predicate call sites must agree or routed and drawn
|
capturedDriver);
|
||||||
// stages diverge.
|
};
|
||||||
if (DynamicDrawsInOutsideStage(e.ParentCellId, c, r, outsideStageFlood, ctx.Cells))
|
try
|
||||||
_outsideStageDynamics.Add(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (walkActive)
|
|
||||||
{
|
{
|
||||||
// Campaign FW3.2b-2: the walk owns every static draw —
|
DrawWalkDrivenStatics(ctx, walkExecutor, walkDriver!);
|
||||||
// terrain/sky, building shells + punches + look-in cell
|
passes.UseIndoorMembershipOnlyRouting();
|
||||||
// statics, and the interior root's own flood shells +
|
if (ctx.RootCell.IsOutdoorNode)
|
||||||
// statics (with the depth clear + exit seals at their real
|
|
||||||
// retail turn). The OLD visibility (pvFrame/clipAssembly/
|
|
||||||
// viewcone, already built above) keeps running unchanged to
|
|
||||||
// feed the surviving dynamic routes only (plan §FW3 item 1's
|
|
||||||
// dual-compute split). Campaign FW3.4a: the walk itself
|
|
||||||
// already ran (Collect, above) — this is Replay only.
|
|
||||||
//
|
|
||||||
// FW3 visual-gate fix: for an INTERIOR root the dynamics
|
|
||||||
// phase (outside dynamics + look-in dynamics + outdoor
|
|
||||||
// particles + weather) must draw at the walk's PRE-CLEAR
|
|
||||||
// boundary — retail draws them inside LScape::draw, before
|
|
||||||
// the clear+seals — so the driver's clearInteriorDepth
|
|
||||||
// closure invokes it via _walkPreClearDynamics. For an
|
|
||||||
// OUTDOOR root there is no clear (retail has none) and the
|
|
||||||
// phase runs after the driver, matching the old order.
|
|
||||||
Walk.WalkFrameDriver capturedDriver = walkDriver!;
|
|
||||||
_walkPreClearDynamics = () =>
|
|
||||||
{
|
{
|
||||||
// Static-owner emitters now submit AT THEIR OWN WALK
|
|
||||||
// TURNS during Replay (WalkFrameEventKind.StaticParticles
|
|
||||||
// — the #132 positional invariant), so the pre-clear
|
|
||||||
// closure carries only the dynamics phase.
|
|
||||||
passes.UseIndoorMembershipOnlyRouting();
|
|
||||||
DrawLandscapeDynamicsPhase(
|
DrawLandscapeDynamicsPhase(
|
||||||
ctx,
|
ctx,
|
||||||
passes,
|
passes,
|
||||||
clipAssembly,
|
clipAssembly,
|
||||||
capturedDriver);
|
walkDriver!);
|
||||||
};
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DrawWalkDrivenStatics(ctx, walkExecutor!, walkDriver!);
|
|
||||||
passes.UseIndoorMembershipOnlyRouting();
|
|
||||||
if (ctx.RootCell.IsOutdoorNode)
|
|
||||||
{
|
|
||||||
DrawLandscapeDynamicsPhase(
|
|
||||||
ctx,
|
|
||||||
passes,
|
|
||||||
clipAssembly,
|
|
||||||
walkDriver!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_walkPreClearDynamics = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
finally
|
||||||
{
|
{
|
||||||
DrawLandscapeThroughOutsideView(
|
_walkPreClearDynamics = null;
|
||||||
ctx,
|
|
||||||
passes,
|
|
||||||
clipAssembly,
|
|
||||||
partition,
|
|
||||||
viewcone,
|
|
||||||
frameEntityPasses,
|
|
||||||
in frameView);
|
|
||||||
passes.UseIndoorMembershipOnlyRouting();
|
|
||||||
|
|
||||||
// Retail DrawBuilding @0x0059F2A0 runs FlushAlphaList(0f) BEFORE
|
|
||||||
// its portal-only far-Z pass. In retail's strict far→near walk
|
|
||||||
// everything queued at that instant is FARTHER than the structure
|
|
||||||
// being punched, so no already-drained poly can meet a punched
|
|
||||||
// aperture's falsified depth, and everything drained later is
|
|
||||||
// NEARER than the punched structure and legitimately composites in
|
|
||||||
// front of it. The batched outdoor frame reproduces that invariant
|
|
||||||
// here: drain the far prefix — every entry at or beyond the
|
|
||||||
// nearest cell whose exit-portal mask is about to punch far-Z —
|
|
||||||
// against still-true landscape depth. Without this, an exterior
|
|
||||||
// waterfall beyond the cathedral drains after the punches and
|
|
||||||
// z-passes across every aperture pixel whose true depth the punch
|
|
||||||
// erased (#132 regression found at the 2026-08-29 cathedral gate).
|
|
||||||
// Interior roots keep their pre-clear stage-boundary drain.
|
|
||||||
if (ctx.RootCell.IsOutdoorNode)
|
|
||||||
{
|
|
||||||
passes.FlushLandscapeAlphaFartherThan(
|
|
||||||
ExitPortalMaskBarrierDistance(
|
|
||||||
pvFrame,
|
|
||||||
drawableCells,
|
|
||||||
ctx.Cells,
|
|
||||||
ctx.CameraWorldPosition));
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawExitPortalMasks(ctx, passes, pvFrame, clipAssembly, drawableCells);
|
|
||||||
DrawEnvCellShells(passes, pvFrame);
|
|
||||||
DrawCellObjectLists(
|
|
||||||
ctx,
|
|
||||||
passes,
|
|
||||||
pvFrame,
|
|
||||||
clipAssembly,
|
|
||||||
drawableCells,
|
|
||||||
partition,
|
|
||||||
viewcone,
|
|
||||||
frameEntityPasses,
|
|
||||||
in frameView);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Campaign FW4: the retail walk now owns live objects at their
|
|
||||||
// exact DrawObjCell turns (outdoor cells, look-ins, and the root
|
|
||||||
// flood). The packed DynamicLast route is a legacy duplicate and
|
|
||||||
// must not run on a walk frame. Standalone/fake executors retain
|
|
||||||
// the old path only until the FW4 shell-deletion slice removes it.
|
|
||||||
if (!walkActive)
|
|
||||||
{
|
|
||||||
DrawDynamicsLast(
|
|
||||||
ctx,
|
|
||||||
passes,
|
|
||||||
partition,
|
|
||||||
viewcone,
|
|
||||||
ctx.RootCell.IsOutdoorNode,
|
|
||||||
frameEntityPasses,
|
|
||||||
in frameView);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OUTDOOR root: the LScape-boundary alpha drain deferred from the
|
// OUTDOOR root: the LScape-boundary alpha drain deferred from the
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue