feat(selection): port retail polygon picking and vivid marker

Replace the projected Setup-sphere rectangle and independent physics-wall ray with retail's render-coupled picker: only visible server-object parts participate, each exact drawing sphere broad-phases the camera-eye ray, and first-in-DAT-order visual polygon hits globally outrank sphere fallbacks.

Replace the devtools-only procedural triangles with the retained gameplay VividTargetIndicator using retail client-enum surfaces 1..4, radar-blip colorization, Setup selection-sphere framing, and the exact eight-pixel viewport clamp.

Release build succeeds with zero warnings and all 5,886 tests pass with five intentional skips.

Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-17 21:32:51 +02:00
parent 0f82a08f0a
commit 146a963aeb
26 changed files with 1302 additions and 1340 deletions

View file

@ -0,0 +1,117 @@
using System.Numerics;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Selection;
using AcDream.App.UI;
using AcDream.Core.Textures;
using AcDream.Core.Selection;
using DatReaderWriter;
using DatReaderWriter.DBObjs;
using DatReaderWriter.Options;
using Xunit.Sdk;
using SysEnv = System.Environment;
namespace AcDream.App.Tests.Rendering;
public sealed class RetailSelectionAssetTests
{
[Fact]
public void InstalledDat_ResolvesAllFourVividTargetCorners()
{
string datDir = ResolveDatDir();
using var dats = new DatCollection(datDir, DatAccessType.Read);
var master = Assert.IsType<EnumIDMap>(
dats.Get<EnumIDMap>((uint)dats.Portal.Header.MasterMapId));
uint subMapDid = master.ClientEnumToID[0x10000009u];
var subMap = Assert.IsType<EnumIDMap>(dats.Get<EnumIDMap>(subMapDid));
for (uint index = 0; index < 4; index++)
{
uint enumValue = 1u + index;
uint did = RetailDataIdResolver.Resolve(dats, enumValue, 0x10000009u);
Assert.True(did != 0u,
$"enum {enumValue}; submap 0x{subMapDid:X8} keys: {string.Join(',', subMap.ClientEnumToID.Keys.Select(k => $"0x{k:X8}"))}");
Assert.True(dats.Portal.TryGet<RenderSurface>(did, out var surface)
|| dats.HighRes.TryGet<RenderSurface>(did, out surface),
$"enum 0x{enumValue:X8} resolved 0x{did:X8}");
Assert.NotNull(surface);
Assert.Equal(0x06000000u, did & 0xFF000000u);
Assert.Equal((12, 12), (surface.Width, surface.Height));
Palette? palette = surface.DefaultPaletteId != 0
? dats.Get<Palette>(surface.DefaultPaletteId)
: null;
DecodedTexture decoded = SurfaceDecoder.DecodeRenderSurface(surface, palette);
int coloredPixels = 0;
for (int pixel = 0; pixel < decoded.Rgba8.Length; pixel += 4)
{
if (decoded.Rgba8[pixel + 3] == 0)
continue;
if (decoded.Rgba8[pixel] != decoded.Rgba8[pixel + 1]
|| decoded.Rgba8[pixel] != decoded.Rgba8[pixel + 2])
coloredPixels++;
}
Assert.True(coloredPixels == 0,
$"corner {index + 1} has {coloredPixels} non-grayscale source pixels");
}
}
[Fact]
public void DoorSelectionGeometry_UsesDrawingBspRootSphereAndDatPolygonOrder()
{
const uint doorGfxObjId = 0x010044B5u;
string datDir = ResolveDatDir();
using var dats = new DatCollection(datDir, DatAccessType.Read);
var gfx = Assert.IsType<GfxObj>(dats.Get<GfxObj>(doorGfxObjId));
var cache = new RetailSelectionGeometryCache(dats, new object());
var selection = Assert.IsType<AcDream.Core.Selection.RetailSelectionMesh>(
cache.Resolve(doorGfxObjId));
var root = Assert.IsType<DatReaderWriter.Types.DrawingBSPNode>(gfx.DrawingBSP.Root);
Assert.Equal(root.BoundingSphere.Origin, selection.SphereCenter);
Assert.Equal(root.BoundingSphere.Radius, selection.SphereRadius);
Assert.Equal(gfx.Polygons.Count, selection.Polygons.Count);
var firstSource = gfx.Polygons.First().Value;
var firstSelection = selection.Polygons[0];
Assert.Equal((int)firstSource.SidesType == 0, firstSelection.SingleSided);
Assert.Equal(firstSource.VertexIds.Count, firstSelection.Vertices.Count);
}
[Fact]
public void DrawingSphereViewconeRejectsPartBehindCamera()
{
Matrix4x4 view = Matrix4x4.CreateLookAt(
Vector3.Zero, -Vector3.UnitZ, Vector3.UnitY);
Matrix4x4 projection = Matrix4x4.CreatePerspectiveFieldOfView(
MathF.PI / 3f, 4f / 3f, 0.1f, 100f);
FrustumPlanes frustum = FrustumPlanes.FromViewProjection(view * projection);
var mesh = new RetailSelectionMesh(Vector3.Zero, 1f, []);
Assert.True(RetailSelectionScene.DrawingSphereIntersectsFrustum(
mesh, Matrix4x4.CreateTranslation(0f, 0f, -5f), frustum));
Assert.False(RetailSelectionScene.DrawingSphereIntersectsFrustum(
mesh, Matrix4x4.CreateTranslation(0f, 0f, 5f), frustum));
}
private static string ResolveDatDir()
{
string? configured = SysEnv.GetEnvironmentVariable("ACDREAM_DAT_DIR");
if (!string.IsNullOrWhiteSpace(configured)
&& File.Exists(Path.Combine(configured, "client_portal.dat")))
return configured;
const string installed = @"C:\Turbine\Asheron's Call";
if (File.Exists(Path.Combine(installed, "client_portal.dat")))
return installed;
string conventional = Path.Combine(
SysEnv.GetFolderPath(SysEnv.SpecialFolder.UserProfile),
"Documents",
"Asheron's Call");
if (File.Exists(Path.Combine(conventional, "client_portal.dat")))
return conventional;
throw SkipException.ForSkip("Installed client_portal.dat is required.");
}
}