refactor(render): Phase U.1 — delete two-pipe inside-out machinery

Remove IndoorCellStencilPipeline + portal_stencil shaders, RenderInsideOutAcdream,
RenderOutsideInAcdream, the A8-perf instrumentation, the cameraInsideBuilding /
ACDREAM_A8_INDOOR_BRANCH branch, and the dead EntitySet partition values. Collapse
the render branch to the default Draw(All) path (U.4a replaces it with the gated
unified pass). Keep all audited EnvCellRenderer / BuildingLoader / CellVisibility /
camera-collision fixes.

Also deleted with the partition: the two test-only walk helpers
(WbDrawDispatcher.WalkEntitiesForTest / WalkEntitiesForTestByCellIds) and their
test files (WbDrawDispatcherEntitySetTests, WbDrawDispatcherCellIdsOverloadTests),
which existed solely to exercise the removed IndoorPass/OutdoorScenery/
BuildingShells/LiveDynamic partition. EntityMatchesSet / IsShellScopedSet collapse
to the All-path constants; the set: parameter is retained as a seam for the
unified pass.

Note: the depth-clear-if-inside default-path workaround was removed per the
U.1 task list — any current indoor-wall degradation persists until a later
Phase U task lands the unified pass (expected, not a regression introduced here).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-30 16:05:19 +02:00
parent 0f7b395be1
commit 3fc77be5de
8 changed files with 37 additions and 2612 deletions

View file

@ -1,92 +0,0 @@
// Phase A8 RR5 — verify WbDrawDispatcher.WalkEntitiesForTestByCellIds,
// the pure-data companion to the new Draw(cellIds:) production overload.
//
// Semantics: indoor entities (ParentCellId.HasValue) are gated by explicit
// membership in cellIds. Building shells (IsBuildingShell) pass only when their
// BuildingShellAnchorCellId belongs to the same cell set.
// Outdoor scenery (no ParentCellId, not a shell) is excluded by EntitySet.IndoorPass.
using System.Collections.Generic;
using System.Numerics;
using AcDream.App.Rendering.Wb;
using AcDream.Core.World;
using Xunit;
namespace AcDream.Core.Tests.Rendering.Wb;
public class WbDrawDispatcherCellIdsOverloadTests
{
private static WorldEntity CellEnt(uint id, uint cellId) => new()
{
Id = id,
SourceGfxObjOrSetupId = 0x01000001u,
ParentCellId = cellId,
MeshRefs = new List<MeshRef> { new(0x01000001u, Matrix4x4.Identity) },
Position = Vector3.Zero,
Rotation = Quaternion.Identity,
};
private static WorldEntity OutdoorScenery(uint id) => new()
{
Id = id,
SourceGfxObjOrSetupId = 0x01000001u,
ParentCellId = null,
IsBuildingShell = false,
MeshRefs = new List<MeshRef> { new(0x01000001u, Matrix4x4.Identity) },
Position = Vector3.Zero,
Rotation = Quaternion.Identity,
};
private static WorldEntity BuildingShell(uint id, uint? anchorCellId) => new()
{
Id = id,
SourceGfxObjOrSetupId = 0x02000001u,
ParentCellId = null,
IsBuildingShell = true,
BuildingShellAnchorCellId = anchorCellId,
MeshRefs = new List<MeshRef> { new(0x01000001u, Matrix4x4.Identity) },
Position = Vector3.Zero,
Rotation = Quaternion.Identity,
};
[Fact]
public void WalkEntitiesByCellIds_IncludesOnlyEntitiesInListedCells()
{
var entities = new List<WorldEntity>
{
CellEnt(0x40000001u, 0xA9B40150u), // in listed cells
CellEnt(0x40000002u, 0xA9B40151u), // in listed cells
CellEnt(0x40000003u, 0xA9B40999u), // OUT — not in list
BuildingShell(0xC0000001u, 0xA9B40150u), // in listed building cells
BuildingShell(0xC0000003u, 0xA9B40999u), // OUT — another building shell
OutdoorScenery(0xC0000002u), // OUT — not a shell, not in cell list
};
var cellIds = new HashSet<uint> { 0xA9B40150u, 0xA9B40151u };
var result = WbDrawDispatcher.WalkEntitiesForTestByCellIds(
entities, cellIds, set: WbDrawDispatcher.EntitySet.IndoorPass);
Assert.Equal(3, result.Count);
Assert.Contains(0x40000001u, result);
Assert.Contains(0x40000002u, result);
Assert.Contains(0xC0000001u, result);
Assert.DoesNotContain(0x40000003u, result);
Assert.DoesNotContain(0xC0000003u, result);
Assert.DoesNotContain(0xC0000002u, result);
}
[Fact]
public void WalkEntitiesByCellIds_EmptyCellList_ExcludesBuildingShells()
{
var entities = new List<WorldEntity>
{
CellEnt(0x40000001u, 0xA9B40150u),
BuildingShell(0xC0000001u, 0xA9B40150u),
};
var result = WbDrawDispatcher.WalkEntitiesForTestByCellIds(
entities, new HashSet<uint>(), set: WbDrawDispatcher.EntitySet.IndoorPass);
Assert.Empty(result);
}
}

View file

@ -1,282 +0,0 @@
// Phase A8 — verify the WbDrawDispatcher EntitySet partition (taxonomy-aware).
//
// The pure-data WalkEntitiesForTest helper iterates a flat entity list and
// returns the IDs that survive the EntitySet filter + visibleCellIds gate.
//
// EntitySet.IndoorPass — ParentCellId.HasValue OR IsBuildingShell,
// and NOT live-dynamic (ServerGuid == 0).
// Building shells are gated by their dat anchor;
// live-dynamic flows through LiveDynamic instead.
// EntitySet.OutdoorScenery — ParentCellId == null AND not live-dynamic.
// Includes building shells for exterior/depth repair passes.
// EntitySet.BuildingShells — IsBuildingShell only, gated by dat anchor when
// visibleCellIds are supplied.
// EntitySet.LiveDynamic — ServerGuid != 0 (player, NPCs, dropped items,
// idle doors after animation). Drawn last with
// stencil disabled.
// EntitySet.All — pre-A8 behavior (visibleCellIds gates indoor;
// outdoor entities pass through).
using System.Collections.Generic;
using System.Numerics;
using AcDream.App.Rendering.Wb;
using AcDream.Core.World;
using Xunit;
namespace AcDream.Core.Tests.Rendering.Wb;
public class WbDrawDispatcherEntitySetTests
{
private static WorldEntity CellEnt(uint id, uint cellId) => new()
{
Id = id,
SourceGfxObjOrSetupId = 0x01000001u,
ParentCellId = cellId,
MeshRefs = new List<MeshRef> { new() { GfxObjId = 0x01000001u } },
Position = Vector3.Zero,
Rotation = Quaternion.Identity,
};
private static WorldEntity OutdoorScenery(uint id) => new()
{
Id = id,
SourceGfxObjOrSetupId = 0x01000001u,
ParentCellId = null,
IsBuildingShell = false,
MeshRefs = new List<MeshRef> { new() { GfxObjId = 0x01000001u } },
Position = Vector3.Zero,
Rotation = Quaternion.Identity,
};
private static WorldEntity BuildingShell(uint id, uint? anchorCellId = null) => new()
{
Id = id,
SourceGfxObjOrSetupId = 0x02000001u,
ParentCellId = null,
IsBuildingShell = true,
BuildingShellAnchorCellId = anchorCellId,
MeshRefs = new List<MeshRef> { new() { GfxObjId = 0x01000001u } },
Position = Vector3.Zero,
Rotation = Quaternion.Identity,
};
private static WorldEntity LiveDynamic(uint id, uint serverGuid) => new()
{
Id = id,
SourceGfxObjOrSetupId = 0x02000001u,
ServerGuid = serverGuid,
ParentCellId = null,
IsBuildingShell = false,
MeshRefs = new List<MeshRef> { new() { GfxObjId = 0x01000001u } },
Position = Vector3.Zero,
Rotation = Quaternion.Identity,
};
[Fact]
public void IndoorPass_IncludesCellEntities()
{
var entities = new List<WorldEntity>
{
CellEnt(0x10000001, 0xA9B40143),
OutdoorScenery(0x10000002),
CellEnt(0x10000003, 0xA9B40144),
};
var visible = new HashSet<uint> { 0xA9B40143u, 0xA9B40144u };
var result = WbDrawDispatcher.WalkEntitiesForTest(
entities, visibleCellIds: visible, set: WbDrawDispatcher.EntitySet.IndoorPass);
Assert.Equal(2, result.Count);
Assert.Contains(0x10000001u, result);
Assert.Contains(0x10000003u, result);
Assert.DoesNotContain(0x10000002u, result);
}
[Fact]
public void IndoorPass_IncludesBuildingShells_WhenAnchorCellIsVisible()
{
var entities = new List<WorldEntity>
{
BuildingShell(0xC0000001, 0xA9B40143u), // cottage wall
OutdoorScenery(0xC0000002), // tree
CellEnt(0x40000001, 0xA9B40143),
};
var visible = new HashSet<uint> { 0xA9B40143u };
var result = WbDrawDispatcher.WalkEntitiesForTest(
entities, visibleCellIds: visible, set: WbDrawDispatcher.EntitySet.IndoorPass);
Assert.Equal(2, result.Count);
Assert.Contains(0xC0000001u, result); // building shell included
Assert.Contains(0x40000001u, result); // cell entity included
Assert.DoesNotContain(0xC0000002u, result); // tree excluded
}
[Fact]
public void IndoorPass_WithNullCellFilter_UsesEntitySetOnly()
{
var entities = new List<WorldEntity>
{
BuildingShell(0xC0000001, 0xA9B40143u),
CellEnt(0x40000001, 0xA9B40143),
CellEnt(0x40000002, 0xA9B40199),
OutdoorScenery(0xC0000002),
LiveDynamic(0x10000001, serverGuid: 0x50000123u),
};
var result = WbDrawDispatcher.WalkEntitiesForTest(
entities, visibleCellIds: null, set: WbDrawDispatcher.EntitySet.IndoorPass);
Assert.Equal(3, result.Count);
Assert.Contains(0xC0000001u, result);
Assert.Contains(0x40000001u, result);
Assert.Contains(0x40000002u, result);
Assert.DoesNotContain(0xC0000002u, result);
Assert.DoesNotContain(0x10000001u, result);
}
[Fact]
public void IndoorPass_ExcludesBuildingShells_WhenAnchorCellIsNotVisible()
{
var entities = new List<WorldEntity>
{
BuildingShell(0xC0000001, 0xA9B40150u),
CellEnt(0x40000001, 0xA9B40143),
};
var visible = new HashSet<uint> { 0xA9B40143u };
var result = WbDrawDispatcher.WalkEntitiesForTest(
entities, visibleCellIds: visible, set: WbDrawDispatcher.EntitySet.IndoorPass);
Assert.Single(result);
Assert.Contains(0x40000001u, result);
Assert.DoesNotContain(0xC0000001u, result);
}
[Fact]
public void IndoorPass_ExcludesLiveDynamic()
{
var entities = new List<WorldEntity>
{
CellEnt(0x40000001, 0xA9B40143),
LiveDynamic(0x10000001, serverGuid: 0x50000123u),
};
var visible = new HashSet<uint> { 0xA9B40143u };
var result = WbDrawDispatcher.WalkEntitiesForTest(
entities, visibleCellIds: visible, set: WbDrawDispatcher.EntitySet.IndoorPass);
Assert.Single(result);
Assert.Contains(0x40000001u, result);
Assert.DoesNotContain(0x10000001u, result); // live-dynamic excluded
}
[Fact]
public void OutdoorScenery_IncludesBuildingShells()
{
var entities = new List<WorldEntity>
{
BuildingShell(0xC0000001), // cottage wall — included
OutdoorScenery(0xC0000002), // tree — included
CellEnt(0x40000001, 0xA9B40143), // cell — excluded
};
var result = WbDrawDispatcher.WalkEntitiesForTest(
entities, visibleCellIds: null, set: WbDrawDispatcher.EntitySet.OutdoorScenery);
Assert.Equal(2, result.Count);
Assert.Contains(0xC0000002u, result);
Assert.Contains(0xC0000001u, result);
Assert.DoesNotContain(0x40000001u, result);
}
[Fact]
public void OutdoorScenery_ExcludesLiveDynamic()
{
var entities = new List<WorldEntity>
{
OutdoorScenery(0xC0000001),
LiveDynamic(0x10000001, serverGuid: 0x50000123u),
};
var result = WbDrawDispatcher.WalkEntitiesForTest(
entities, visibleCellIds: null, set: WbDrawDispatcher.EntitySet.OutdoorScenery);
Assert.Single(result);
Assert.Contains(0xC0000001u, result);
Assert.DoesNotContain(0x10000001u, result);
}
[Fact]
public void BuildingShells_IncludesOnlyAnchoredShells()
{
var entities = new List<WorldEntity>
{
BuildingShell(0xC0000001, 0xA9B40143u),
BuildingShell(0xC0000002, 0xA9B40999u),
OutdoorScenery(0xC0000003),
CellEnt(0x40000001, 0xA9B40143),
LiveDynamic(0x10000001, serverGuid: 0x50000123u),
};
var visible = new HashSet<uint> { 0xA9B40143u };
var result = WbDrawDispatcher.WalkEntitiesForTest(
entities, visibleCellIds: visible, set: WbDrawDispatcher.EntitySet.BuildingShells);
Assert.Single(result);
Assert.Contains(0xC0000001u, result);
Assert.DoesNotContain(0xC0000002u, result);
Assert.DoesNotContain(0xC0000003u, result);
Assert.DoesNotContain(0x40000001u, result);
Assert.DoesNotContain(0x10000001u, result);
}
[Fact]
public void LiveDynamic_IncludesOnlyServerSpawned()
{
var entities = new List<WorldEntity>
{
OutdoorScenery(0xC0000001),
BuildingShell(0xC0000002),
CellEnt(0x40000001, 0xA9B40143),
LiveDynamic(0x10000001, serverGuid: 0x50000123u),
LiveDynamic(0x10000002, serverGuid: 0x50000456u),
};
var result = WbDrawDispatcher.WalkEntitiesForTest(
entities, visibleCellIds: null, set: WbDrawDispatcher.EntitySet.LiveDynamic);
Assert.Equal(2, result.Count);
Assert.Contains(0x10000001u, result);
Assert.Contains(0x10000002u, result);
Assert.DoesNotContain(0xC0000001u, result);
Assert.DoesNotContain(0xC0000002u, result);
Assert.DoesNotContain(0x40000001u, result);
}
[Fact]
public void All_MatchesPreA8Behavior()
{
var entities = new List<WorldEntity>
{
CellEnt(0x40000001, 0xA9B40143),
OutdoorScenery(0xC0000001),
BuildingShell(0xC0000002),
LiveDynamic(0x10000001, serverGuid: 0x50000123u),
CellEnt(0x40000002, 0xA9B40999), // not in visibleCellIds
};
var visible = new HashSet<uint> { 0xA9B40143u };
var result = WbDrawDispatcher.WalkEntitiesForTest(
entities, visibleCellIds: visible, set: WbDrawDispatcher.EntitySet.All);
// Pre-A8: visibleCellIds gates indoor entities only; outdoor entities
// (regardless of building/scenery/live-dynamic) pass through.
Assert.Equal(4, result.Count);
Assert.Contains(0x40000001u, result);
Assert.Contains(0xC0000001u, result);
Assert.Contains(0xC0000002u, result);
Assert.Contains(0x10000001u, result);
Assert.DoesNotContain(0x40000002u, result);
}
}