test(render) Campaign FW1: pose-aware oracle trace parser
WalkOracleTrace decodes the P lines of the pose-stamped capture round (raw IEEE-754 dwords from Render::viewer_pos @0x0081ef00: camera cell, world origin, the four Frame quaternion components in storage order) into WalkOraclePose on each frame. Poseless FW0 fixtures parse as before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
17c57bbd1d
commit
f289366700
1 changed files with 46 additions and 2 deletions
|
|
@ -22,6 +22,7 @@ public static class WalkOracleTrace
|
||||||
var frames = new List<WalkOracleFrame>();
|
var frames = new List<WalkOracleFrame>();
|
||||||
List<WalkOracleEvent>? current = null;
|
List<WalkOracleEvent>? current = null;
|
||||||
int currentNumber = 0;
|
int currentNumber = 0;
|
||||||
|
WalkOraclePose? currentPose = null;
|
||||||
|
|
||||||
foreach (string line in lines)
|
foreach (string line in lines)
|
||||||
{
|
{
|
||||||
|
|
@ -29,15 +30,39 @@ public static class WalkOracleTrace
|
||||||
if (frameMatch.Success)
|
if (frameMatch.Success)
|
||||||
{
|
{
|
||||||
if (current is not null)
|
if (current is not null)
|
||||||
frames.Add(new WalkOracleFrame(currentNumber, current));
|
frames.Add(new WalkOracleFrame(currentNumber, current, currentPose));
|
||||||
currentNumber = int.Parse(
|
currentNumber = int.Parse(
|
||||||
frameMatch.Groups[1].Value, CultureInfo.InvariantCulture);
|
frameMatch.Groups[1].Value, CultureInfo.InvariantCulture);
|
||||||
current = new List<WalkOracleEvent>();
|
current = new List<WalkOracleEvent>();
|
||||||
|
currentPose = null;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (current is null)
|
if (current is null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
Match poseMatch = PosePattern.Match(line);
|
||||||
|
if (poseMatch.Success)
|
||||||
|
{
|
||||||
|
// P <objcell_id> <origin xyz> <quat q0..q3> — raw IEEE-754 dwords
|
||||||
|
// dumped from Render::viewer_pos @0x0081ef00 at the frame marker.
|
||||||
|
uint[] raw = new uint[8];
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
raw[i] = uint.Parse(
|
||||||
|
poseMatch.Groups[i + 1].Value,
|
||||||
|
NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
||||||
|
currentPose = new WalkOraclePose(
|
||||||
|
raw[0],
|
||||||
|
new System.Numerics.Vector3(
|
||||||
|
BitConverter.Int32BitsToSingle((int)raw[1]),
|
||||||
|
BitConverter.Int32BitsToSingle((int)raw[2]),
|
||||||
|
BitConverter.Int32BitsToSingle((int)raw[3])),
|
||||||
|
BitConverter.Int32BitsToSingle((int)raw[4]),
|
||||||
|
BitConverter.Int32BitsToSingle((int)raw[5]),
|
||||||
|
BitConverter.Int32BitsToSingle((int)raw[6]),
|
||||||
|
BitConverter.Int32BitsToSingle((int)raw[7]));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (line == "LS")
|
if (line == "LS")
|
||||||
{
|
{
|
||||||
current.Add(WalkOracleEvent.Landscape());
|
current.Add(WalkOracleEvent.Landscape());
|
||||||
|
|
@ -102,13 +127,32 @@ public static class WalkOracleTrace
|
||||||
=> uint.Parse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
=> uint.Parse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
private static readonly Regex FramePattern = new(@"^F (\d+)\s*$", RegexOptions.Compiled);
|
private static readonly Regex FramePattern = new(@"^F (\d+)\s*$", RegexOptions.Compiled);
|
||||||
|
private static readonly Regex PosePattern = new(
|
||||||
|
@"^P ([0-9a-f]{8}) ([0-9a-f]{8}) ([0-9a-f]{8}) ([0-9a-f]{8}) ([0-9a-f]{8}) ([0-9a-f]{8}) ([0-9a-f]{8}) ([0-9a-f]{8})\s*$",
|
||||||
|
RegexOptions.Compiled);
|
||||||
private static readonly Regex BuildingPattern = new(@"^BLD ([0-9a-f]{8})\s*$", RegexOptions.Compiled);
|
private static readonly Regex BuildingPattern = new(@"^BLD ([0-9a-f]{8})\s*$", RegexOptions.Compiled);
|
||||||
private static readonly Regex DrawInsidePattern = new(@"^DI ([0-9a-f]{8})\s*$", RegexOptions.Compiled);
|
private static readonly Regex DrawInsidePattern = new(@"^DI ([0-9a-f]{8})\s*$", RegexOptions.Compiled);
|
||||||
private static readonly Regex DrawCellsPattern = new(
|
private static readonly Regex DrawCellsPattern = new(
|
||||||
@"^DC pv=[0-9a-f]{8} ov=(\d+) n=(\d+):((?: [0-9a-f]{8})*)\s*$", RegexOptions.Compiled);
|
@"^DC pv=[0-9a-f]{8} ov=(\d+) n=(\d+):((?: [0-9a-f]{8})*)\s*$", RegexOptions.Compiled);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed record WalkOracleFrame(int Number, IReadOnlyList<WalkOracleEvent> Events)
|
/// <summary>The camera pose dumped at the frame marker (raw dwords from
|
||||||
|
/// <c>Render::viewer_pos</c> @0x0081ef00): the camera's cell id, world
|
||||||
|
/// origin, and the Frame quaternion's four raw components (q0..q3 in
|
||||||
|
/// storage order — axis convention resolved by the replay runner).
|
||||||
|
/// Present only in the pose-stamped capture round.</summary>
|
||||||
|
public sealed record WalkOraclePose(
|
||||||
|
uint CellId,
|
||||||
|
System.Numerics.Vector3 Origin,
|
||||||
|
float Q0,
|
||||||
|
float Q1,
|
||||||
|
float Q2,
|
||||||
|
float Q3);
|
||||||
|
|
||||||
|
public sealed record WalkOracleFrame(
|
||||||
|
int Number,
|
||||||
|
IReadOnlyList<WalkOracleEvent> Events,
|
||||||
|
WalkOraclePose? Pose = null)
|
||||||
{
|
{
|
||||||
/// <summary>The frame's root: the first DrawInside cell, or null when outdoor-rooted.</summary>
|
/// <summary>The frame's root: the first DrawInside cell, or null when outdoor-rooted.</summary>
|
||||||
public uint? InteriorRootCell
|
public uint? InteriorRootCell
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue