feat(render) Campaign FW3.2b-2 step 1: the production leaf adapter
Additive, nothing invokes it yet (the cutover flip is step 2): - WalkProductionLeafRenderer + RetailPViewPassExecutor.WalkLeaf: the walk driver's leaf turns over the SAME executor renderers the packed path uses today - DrawWalkSky (the per-slice sky block looped under one driver turn), DrawWalkTerrainSlice (the terrain block of DrawLandscapeSlice), per-cell shells via EnvCellRenderer, DrawWalkPunchFan (PortalDepthMaskRenderer far-Z, +ShellDrawLiftZ matching today's DrawPortalDepthWrite until FW3.3 retires it), the alpha barrier via FlushLandscapeAlphaFartherThan, and caller-supplied clear/seal actions (the renderer owns the pass scope). The cutover changes ORDER, never leaf mechanics. - Punch fans now carry the ACTIVE VIEW INDEX end to end (retail pins building_view = Render::portal_view_num @0x0059f3bf for the whole two-pass walk; the fan clips by that view's slice planes): PortalPassSink.ActiveViewIndex -> IWalkEventSink.OnPunchGeometry -> IWalkFrameLeafRenderer.DrawPunchFan. - The FW3.2b-2 rooting design is recorded in the plan (dual-compute split, LookInObject route filtered to dynamics, consumer re-pointing, gate list). Suites: full Release build 0 warnings; Walk lane green; hermetic green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
035d7b0148
commit
1b59eae428
6 changed files with 234 additions and 10 deletions
|
|
@ -212,6 +212,10 @@ public sealed class RetailFrameWalk
|
|||
Vector3 viewpoint = ctx.ViewpointInBuilding(building);
|
||||
for (int v = 0; v < viewCount; v++)
|
||||
{
|
||||
// Retail pins building_view = the CURRENT view for the whole
|
||||
// two-pass walk (DrawMeshInternal @0x0059f3bf) — the punch fans
|
||||
// it emits clip against THAT view, so the sink carries the index.
|
||||
passSink.ActiveViewIndex = v;
|
||||
ctx.SetActiveView(activeViews, v);
|
||||
WalkBuildingPortals.BuildDrawPortalsOnly(
|
||||
bsp, 1, viewpoint,
|
||||
|
|
@ -257,6 +261,11 @@ public sealed class RetailFrameWalk
|
|||
private sealed class PortalPassSink(WalkBuilding building, IWalkEventSink sink)
|
||||
: WalkBuildingPortals.IWalkPortalPassSink
|
||||
{
|
||||
/// <summary>The view the two-pass walk is currently pinned to
|
||||
/// (retail <c>building_view = Render::portal_view_num</c>
|
||||
/// @0x0059f3bf) — punch fans clip against THIS view's slice.</summary>
|
||||
public int ActiveViewIndex;
|
||||
|
||||
public void OnPunch(WalkPolygon polygon)
|
||||
{
|
||||
// The far-Z punch is a depth-only GPU submission (FW2's ordered
|
||||
|
|
@ -264,7 +273,7 @@ public sealed class RetailFrameWalk
|
|||
// FW3.2b-1): forward to the richer sink so a driver can flush +
|
||||
// draw the punch fan — building-local space, world transform is
|
||||
// the driver's job (WalkProductionFrameContext-style lookup).
|
||||
sink.OnPunchGeometry(building, polygon);
|
||||
sink.OnPunchGeometry(building, polygon, ActiveViewIndex);
|
||||
}
|
||||
|
||||
public void OnDrawCells(WalkPView pview)
|
||||
|
|
|
|||
|
|
@ -124,7 +124,15 @@ public interface IWalkEventSink
|
|||
/// stayed a no-op through FW1/FW2 for exactly that reason). Default
|
||||
/// no-op.
|
||||
/// </summary>
|
||||
void OnPunchGeometry(WalkBuilding building, WalkPolygon polygon) { }
|
||||
/// <param name="building">The building whose portal walk emitted the
|
||||
/// punch.</param>
|
||||
/// <param name="polygon">The portal polygon, building-local.</param>
|
||||
/// <param name="activeViewIndex">The active-view index the two-pass walk
|
||||
/// is pinned to (retail <c>building_view</c> @0x0059f3bf) — the punch
|
||||
/// fan clips against THIS view's slice planes in production.</param>
|
||||
void OnPunchGeometry(
|
||||
WalkBuilding building, WalkPolygon polygon, int activeViewIndex)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Fires once per interior root, at the point <c>PView::DrawCells</c>
|
||||
|
|
|
|||
|
|
@ -152,8 +152,11 @@ internal interface IWalkFrameLeafRenderer
|
|||
/// the punch (a preceding cell's/building's contents — never this
|
||||
/// building's OWN shell, which retail draws only after the whole portal
|
||||
/// walk completes; see <see cref="WalkFrameDriver"/>'s type doc comment)
|
||||
/// reaches the GPU first.</summary>
|
||||
void DrawPunchFan(WalkPolygon worldPolygon);
|
||||
/// reaches the GPU first. <paramref name="activeViewIndex"/> is the view
|
||||
/// the emitting two-pass walk was pinned to (retail
|
||||
/// <c>building_view = Render::portal_view_num</c> @0x0059f3bf) —
|
||||
/// production clips the fan by that view's slice planes.</summary>
|
||||
void DrawPunchFan(WalkPolygon worldPolygon, int activeViewIndex);
|
||||
|
||||
/// <summary><c>RetailAlphaQueue.FlushFartherThan</c>'s <c>DrawBuilding</c>
|
||||
/// barrier — retail's own call site is
|
||||
|
|
@ -424,7 +427,8 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
shell.Records, shell.TupleLandblockId, _cameraWorldPosition, _viewProjection);
|
||||
}
|
||||
|
||||
void IWalkEventSink.OnPunchGeometry(WalkBuilding building, WalkPolygon polygon)
|
||||
void IWalkEventSink.OnPunchGeometry(
|
||||
WalkBuilding building, WalkPolygon polygon, int activeViewIndex)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(building);
|
||||
ArgumentNullException.ThrowIfNull(polygon);
|
||||
|
|
@ -432,7 +436,8 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
|
||||
FlushIfNonEmpty();
|
||||
Matrix4x4 worldTransform = _worldData.GetBuildingWorldTransform(building);
|
||||
_leafRenderer.DrawPunchFan(TransformToWorld(polygon, worldTransform));
|
||||
_leafRenderer.DrawPunchFan(
|
||||
TransformToWorld(polygon, worldTransform), activeViewIndex);
|
||||
}
|
||||
|
||||
void IWalkEventSink.OnInteriorFloodDrawTurn(IReadOnlyList<uint> cells)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue