checkpoint(render): preserve pre-overhaul investigation state
This commit is contained in:
parent
e880860291
commit
b3b7d922f1
45 changed files with 3168 additions and 619 deletions
|
|
@ -43,6 +43,16 @@ else if (args.Length > 0 && string.Equals(args[0], "gfxobj", StringComparison.Or
|
|||
foreach (var gfxObjId in ids)
|
||||
DumpGfxObj(dats, gfxObjId);
|
||||
}
|
||||
else if (args.Length > 0 && string.Equals(args[0], "scan-drawing-spheres", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return AuditDrawingSpheres(dats);
|
||||
}
|
||||
else if (args.Length > 0 && string.Equals(args[0], "setup", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var ids = args.Skip(1).Select(ParseHex).ToArray();
|
||||
foreach (var setupId in ids)
|
||||
DumpSetup(dats, setupId);
|
||||
}
|
||||
else
|
||||
{
|
||||
var ids = args.Length == 0
|
||||
|
|
@ -57,6 +67,76 @@ else
|
|||
|
||||
return 0;
|
||||
|
||||
static int AuditDrawingSpheres(DatCollection dats)
|
||||
{
|
||||
const float absoluteTolerance = 1e-4f;
|
||||
long objects = 0;
|
||||
long withDrawingSphere = 0;
|
||||
long withoutRenderableVertices = 0;
|
||||
long invalid = 0;
|
||||
var failures = new List<(uint Id, int RenderVertices, float Radius, float RequiredRadius, Vector3 Center)>();
|
||||
|
||||
foreach (uint gfxObjId in dats.GetAllIdsOfType<GfxObj>().OrderBy(id => id))
|
||||
{
|
||||
GfxObj? gfxObj = dats.Get<GfxObj>(gfxObjId);
|
||||
if (gfxObj is null)
|
||||
continue;
|
||||
|
||||
objects++;
|
||||
if (gfxObj.DrawingBSP?.Root?.BoundingSphere is not { } sphere)
|
||||
continue;
|
||||
|
||||
withDrawingSphere++;
|
||||
var renderVertexIds = gfxObj.Polygons.Values
|
||||
.SelectMany(poly => poly.VertexIds)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
if (renderVertexIds.Length == 0)
|
||||
{
|
||||
withoutRenderableVertices++;
|
||||
continue;
|
||||
}
|
||||
|
||||
float requiredRadius = 0f;
|
||||
foreach (var vertexId in renderVertexIds)
|
||||
{
|
||||
if (!gfxObj.VertexArray.Vertices.TryGetValue((ushort)vertexId, out var vertex))
|
||||
continue;
|
||||
requiredRadius = MathF.Max(requiredRadius, Vector3.Distance(sphere.Origin, vertex.Origin));
|
||||
}
|
||||
|
||||
float tolerance = MathF.Max(absoluteTolerance, MathF.Abs(sphere.Radius) * 1e-5f);
|
||||
if (!float.IsFinite(sphere.Radius)
|
||||
|| sphere.Radius < 0f
|
||||
|| requiredRadius > sphere.Radius + tolerance)
|
||||
{
|
||||
invalid++;
|
||||
failures.Add((gfxObjId, renderVertexIds.Length, sphere.Radius, requiredRadius, sphere.Origin));
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine(
|
||||
$"gfxobjs={objects} withDrawingSphere={withDrawingSphere} "
|
||||
+ $"withoutRenderableVertices={withoutRenderableVertices} invalid={invalid}");
|
||||
foreach (var failure in failures
|
||||
.OrderByDescending(entry => entry.Radius > 0f
|
||||
? entry.RequiredRadius / entry.Radius
|
||||
: float.PositiveInfinity)
|
||||
.ThenBy(entry => entry.Id)
|
||||
.Take(100))
|
||||
{
|
||||
float ratio = failure.Radius > 0f
|
||||
? failure.RequiredRadius / failure.Radius
|
||||
: float.PositiveInfinity;
|
||||
Console.WriteLine(
|
||||
$"0x{failure.Id:X8} renderVerts={failure.RenderVertices} "
|
||||
+ $"sphere=({failure.Center.X:R},{failure.Center.Y:R},{failure.Center.Z:R};r={failure.Radius:R}) "
|
||||
+ $"required={failure.RequiredRadius:R} ratio={ratio:R}");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int AuditCellWindingCatalog(DatCollection dats)
|
||||
{
|
||||
long environments = 0;
|
||||
|
|
@ -213,7 +293,22 @@ static void DumpCell(DatCollection dats, uint envCellId)
|
|||
|
||||
Console.WriteLine(
|
||||
$"environment=0x{envId:X8} cellStruct={envCell.CellStructure} " +
|
||||
$"surfaces={envCell.Surfaces.Count} verts={cellStruct.VertexArray.Vertices.Count} polys={cellStruct.Polygons.Count}");
|
||||
$"surfaces={envCell.Surfaces.Count} verts={cellStruct.VertexArray.Vertices.Count} polys={cellStruct.Polygons.Count} " +
|
||||
$"pos=({envCell.Position.Origin.X:R},{envCell.Position.Origin.Y:R},{envCell.Position.Origin.Z:R}) " +
|
||||
$"quat=({envCell.Position.Orientation.W:R},{envCell.Position.Orientation.X:R}," +
|
||||
$"{envCell.Position.Orientation.Y:R},{envCell.Position.Orientation.Z:R})");
|
||||
Console.WriteLine(
|
||||
"visible=[" + string.Join(",", envCell.VisibleCells.Select(
|
||||
id => $"0x{((envCellId & 0xFFFF0000u) | id):X8}")) + "]");
|
||||
for (int staticIndex = 0; staticIndex < envCell.StaticObjects.Count; staticIndex++)
|
||||
{
|
||||
var staticObject = envCell.StaticObjects[staticIndex];
|
||||
Console.WriteLine(
|
||||
$"static[{staticIndex}] model=0x{staticObject.Id:X8} " +
|
||||
$"pos=({staticObject.Frame.Origin.X:R},{staticObject.Frame.Origin.Y:R},{staticObject.Frame.Origin.Z:R}) " +
|
||||
$"quat=({staticObject.Frame.Orientation.W:R},{staticObject.Frame.Orientation.X:R}," +
|
||||
$"{staticObject.Frame.Orientation.Y:R},{staticObject.Frame.Orientation.Z:R})");
|
||||
}
|
||||
|
||||
int posSides = 0;
|
||||
int negSides = 0;
|
||||
|
|
@ -240,6 +335,22 @@ static void DumpCell(DatCollection dats, uint envCellId)
|
|||
|
||||
var normal = ComputeNormal(cellStruct, poly);
|
||||
var uvRange = UvRange(cellStruct, poly);
|
||||
var localMin = new Vector3(float.MaxValue);
|
||||
var localMax = new Vector3(float.MinValue);
|
||||
foreach (int vertexId in poly.VertexIds)
|
||||
{
|
||||
if (!TryGetOrigin(cellStruct, checked((ushort)vertexId), out Vector3 vertex))
|
||||
continue;
|
||||
localMin = Vector3.Min(localMin, vertex);
|
||||
localMax = Vector3.Max(localMax, vertex);
|
||||
}
|
||||
Matrix4x4 cellTransform =
|
||||
Matrix4x4.CreateFromQuaternion(envCell.Position.Orientation)
|
||||
* Matrix4x4.CreateTranslation(envCell.Position.Origin);
|
||||
Vector3 worldA = Vector3.Transform(localMin, cellTransform);
|
||||
Vector3 worldB = Vector3.Transform(localMax, cellTransform);
|
||||
Vector3 worldMin = Vector3.Min(worldA, worldB);
|
||||
Vector3 worldMax = Vector3.Max(worldA, worldB);
|
||||
string planeHint = Math.Abs(normal.Z) > 0.9f
|
||||
? normal.Z > 0 ? "floor/up" : "ceiling/down"
|
||||
: Math.Abs(normal.Z) > 0.15f ? "slope" : "wall";
|
||||
|
|
@ -253,7 +364,9 @@ static void DumpCell(DatCollection dats, uint envCellId)
|
|||
$"poly=0x{polyId:X4} pts={poly.VertexIds.Count} n=({normal.X:F3},{normal.Y:F3},{normal.Z:F3}) {planeHint,-12} " +
|
||||
$"stip={poly.Stippling} sides={poly.SidesType} pos={poly.PosSurface}->{posSurf} neg={poly.NegSurface}->{negSurf} " +
|
||||
$"emitPos={emitPos} emitNeg={emitNeg} posUv={poly.PosUVIndices?.Count ?? 0} negUv={poly.NegUVIndices?.Count ?? 0} " +
|
||||
$"uv=({uvRange.Min.X:F3},{uvRange.Min.Y:F3})..({uvRange.Max.X:F3},{uvRange.Max.Y:F3})");
|
||||
$"uv=({uvRange.Min.X:F3},{uvRange.Min.Y:F3})..({uvRange.Max.X:F3},{uvRange.Max.Y:F3}) " +
|
||||
$"local=({localMin.X:F3},{localMin.Y:F3},{localMin.Z:F3})..({localMax.X:F3},{localMax.Y:F3},{localMax.Z:F3}) " +
|
||||
$"world=({worldMin.X:F3},{worldMin.Y:F3},{worldMin.Z:F3})..({worldMax.X:F3},{worldMax.Y:F3},{worldMax.Z:F3})");
|
||||
}
|
||||
|
||||
Console.WriteLine(
|
||||
|
|
@ -568,6 +681,46 @@ static void DumpGfxObj(DatCollection dats, uint gfxObjId)
|
|||
Console.WriteLine(
|
||||
$"bbox min=({min.X:F2},{min.Y:F2},{min.Z:F2}) max=({max.X:F2},{max.Y:F2},{max.Z:F2}) " +
|
||||
$"size=({max.X - min.X:F2},{max.Y - min.Y:F2},{max.Z - min.Z:F2})");
|
||||
Console.WriteLine(
|
||||
$"bboxExact min=({min.X:R},{min.Y:R},{min.Z:R}) " +
|
||||
$"max=({max.X:R},{max.Y:R},{max.Z:R})");
|
||||
if (g.DrawingBSP?.Root?.BoundingSphere is { } drawingSphere)
|
||||
{
|
||||
float requiredRadius = 0f;
|
||||
foreach (var vertexId in g.Polygons.Values.SelectMany(poly => poly.VertexIds).Distinct())
|
||||
{
|
||||
if (g.VertexArray.Vertices.TryGetValue((ushort)vertexId, out var vertex))
|
||||
requiredRadius = MathF.Max(requiredRadius, Vector3.Distance(drawingSphere.Origin, vertex.Origin));
|
||||
}
|
||||
Console.WriteLine(
|
||||
$"drawingSphere=({drawingSphere.Origin.X:R},{drawingSphere.Origin.Y:R}," +
|
||||
$"{drawingSphere.Origin.Z:R};r={drawingSphere.Radius:R}) " +
|
||||
$"requiredForRenderVertices={requiredRadius:R} " +
|
||||
$"ratio={(drawingSphere.Radius > 0f ? requiredRadius / drawingSphere.Radius : float.PositiveInfinity):R}");
|
||||
DumpDrawingBsp(g.DrawingBSP.Root, depth: 0);
|
||||
}
|
||||
if (g.PhysicsBSP?.Root?.BoundingSphere is { } physicsSphere)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"physicsSphere=({physicsSphere.Origin.X:R},{physicsSphere.Origin.Y:R}," +
|
||||
$"{physicsSphere.Origin.Z:R};r={physicsSphere.Radius:R})");
|
||||
}
|
||||
if (g.Flags.HasFlag(GfxObjFlags.HasDIDDegrade) && g.DIDDegrade != 0)
|
||||
{
|
||||
GfxObjDegradeInfo? degrade = dats.Get<GfxObjDegradeInfo>(g.DIDDegrade);
|
||||
Console.WriteLine(
|
||||
$"degrade=0x{g.DIDDegrade:X8} entries={degrade?.Degrades.Count ?? 0}");
|
||||
if (degrade is not null)
|
||||
{
|
||||
for (int i = 0; i < degrade.Degrades.Count; i++)
|
||||
{
|
||||
var level = degrade.Degrades[i];
|
||||
Console.WriteLine(
|
||||
$" level[{i}] gfx=0x{(uint)level.Id:X8} min={level.MinDist:R} " +
|
||||
$"ideal={level.IdealDist:R} max={level.MaxDist:R} mode={level.DegradeMode}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Console.WriteLine(
|
||||
$"classify: walls={walls} (outwardFacing={outwardWalls} inwardFacing={inwardWalls}) " +
|
||||
$"floors={floors} ceilings={ceilings} slopes={slopes}");
|
||||
|
|
@ -595,6 +748,76 @@ static void DumpGfxObj(DatCollection dats, uint gfxObjId)
|
|||
Console.WriteLine();
|
||||
}
|
||||
|
||||
static void DumpDrawingBsp(
|
||||
DatReaderWriter.Types.DrawingBSPNode? node,
|
||||
int depth)
|
||||
{
|
||||
if (node is null)
|
||||
return;
|
||||
|
||||
string indent = new(' ', depth * 2);
|
||||
var sphere = node.BoundingSphere;
|
||||
string polygons = node.Polygons is null
|
||||
? "[]"
|
||||
: "[" + string.Join(",", node.Polygons.Select(id => $"0x{id:X4}")) + "]";
|
||||
Console.WriteLine(
|
||||
$"{indent}drawingNode type={node.GetType().Name} "
|
||||
+ $"sphere=({sphere.Origin.X:R},{sphere.Origin.Y:R},{sphere.Origin.Z:R};r={sphere.Radius:R}) "
|
||||
+ $"polys={polygons} portals={node.Portals?.Count ?? 0}");
|
||||
DumpDrawingBsp(node.PosNode, depth + 1);
|
||||
DumpDrawingBsp(node.NegNode, depth + 1);
|
||||
}
|
||||
|
||||
static void DumpSetup(DatCollection dats, uint setupId)
|
||||
{
|
||||
Console.WriteLine($"=== Setup 0x{setupId:X8} ===");
|
||||
var setup = dats.Get<Setup>(setupId);
|
||||
if (setup is null)
|
||||
{
|
||||
Console.WriteLine("missing Setup");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine(
|
||||
$"flags={setup.Flags} radius={setup.Radius:R} height={setup.Height:R} " +
|
||||
$"parts={setup.Parts.Count} cylspheres={setup.CylSpheres.Count} spheres={setup.Spheres.Count}");
|
||||
for (int i = 0; i < setup.CylSpheres.Count; i++)
|
||||
{
|
||||
var cylinder = setup.CylSpheres[i];
|
||||
Console.WriteLine(
|
||||
$"cyl[{i}] origin=({cylinder.Origin.X:R},{cylinder.Origin.Y:R},{cylinder.Origin.Z:R}) " +
|
||||
$"radius={cylinder.Radius:R} height={cylinder.Height:R}");
|
||||
}
|
||||
for (int i = 0; i < setup.Spheres.Count; i++)
|
||||
{
|
||||
var sphere = setup.Spheres[i];
|
||||
Console.WriteLine(
|
||||
$"sphere[{i}] origin=({sphere.Origin.X:R},{sphere.Origin.Y:R},{sphere.Origin.Z:R}) " +
|
||||
$"radius={sphere.Radius:R}");
|
||||
}
|
||||
for (int i = 0; i < setup.Parts.Count; i++)
|
||||
{
|
||||
uint partId = setup.Parts[i];
|
||||
GfxObj? part = dats.Get<GfxObj>(partId);
|
||||
Console.WriteLine(
|
||||
$"part[{i}] gfx=0x{partId:X8} flags={(part is null ? "missing" : part.Flags)} " +
|
||||
$"physics={(part?.PhysicsBSP?.Root is null ? 0 : 1)} " +
|
||||
$"visualVerts={part?.VertexArray?.Vertices.Count ?? 0} visualPolys={part?.Polygons?.Count ?? 0}");
|
||||
}
|
||||
foreach (var (placement, frames) in setup.PlacementFrames)
|
||||
{
|
||||
Console.WriteLine($"placement={placement} frames={frames.Frames.Count}");
|
||||
for (int i = 0; i < frames.Frames.Count; i++)
|
||||
{
|
||||
var frame = frames.Frames[i];
|
||||
Console.WriteLine(
|
||||
$" frame[{i}] pos=({frame.Origin.X:R},{frame.Origin.Y:R},{frame.Origin.Z:R}) " +
|
||||
$"quat=({frame.Orientation.W:R},{frame.Orientation.X:R}," +
|
||||
$"{frame.Orientation.Y:R},{frame.Orientation.Z:R})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Vector3 ComputeNormalG(GfxObj g, DatReaderWriter.Types.Polygon poly)
|
||||
{
|
||||
if (poly.VertexIds.Count < 3) return Vector3.Zero;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue