Container type representing an imported source animation file. Stores a Skeleton in centimeters, a list of resampled Clips, import unit scale, axis metadata from the source GlobalSettings, optional authored role mapping, and import notes.
using System;
using System.Collections.Generic;
using HumanoidRetargeter.Mapping;
namespace HumanoidRetargeter.Skeleton;
/// <summary>
/// The result of ingesting a source animation file: a skeleton with its rest pose plus the
/// file's clips resampled on a fixed fps grid.
/// </summary>
/// <remarks>
/// Unit policy: all translations are converted to <b>centimeters</b> at import time
/// (<see cref="UnitScaleCm"/> records the applied source-unit→cm factor for diagnostics).
/// Axis policy: the file's native axes are <b>preserved</b> — no axis conversion is performed.
/// The original FBX <c>GlobalSettings</c> axes are recorded so later pipeline stages can
/// interpret directions (axis indices: 0 = X, 1 = Y, 2 = Z).
/// </remarks>
public sealed class SourceScene
{
/// <summary>Source skeleton with rest pose, in centimeters, native axes.</summary>
public Skeleton Skeleton { get; }
/// <summary>Clips resampled at a fixed fps; locals indexed in skeleton bone order.</summary>
public IReadOnlyList<Clip> Clips { get; }
/// <summary>Source-unit → centimeter factor that was applied to all translations at import.</summary>
public float UnitScaleCm { get; }
/// <summary>Up axis index from GlobalSettings (0 = X, 1 = Y, 2 = Z; FBX default 1).</summary>
public int UpAxis { get; }
/// <summary>Sign of the up axis (+1 or -1).</summary>
public int UpAxisSign { get; }
/// <summary>Front axis index from GlobalSettings (FBX default 2 = Z).</summary>
public int FrontAxis { get; }
/// <summary>Sign of the front axis (+1 or -1).</summary>
public int FrontAxisSign { get; }
/// <summary>Coordinate (right) axis index from GlobalSettings (FBX default 0 = X).</summary>
public int CoordAxis { get; }
/// <summary>Sign of the coordinate axis (+1 or -1).</summary>
public int CoordAxisSign { get; }
/// <summary>OriginalUpAxis from GlobalSettings (-1 when the exporter did not record one).</summary>
public int OriginalUpAxis { get; }
/// <summary>
/// Human-readable import diagnostics (e.g. cross-stack static-translation disagreements).
/// Empty when the import was unambiguous.
/// </summary>
public IReadOnlyList<string> Notes { get; }
/// <summary>
/// A role mapping AUTHORED inside the source file itself, when the format carries one —
/// a VRM's <c>humanoid.humanBones</c> block (set by the glTF importer,
/// <see cref="MappingSource.Authored"/>, confidence 1.0). Null for formats/files without
/// authored role data. <see cref="Retargeter.ResolveMapping"/> consults this before user
/// presets and shipped-profile detection — it is ground truth from the file.
/// </summary>
public MappingResult? AuthoredMapping { get; set; }
/// <summary>Creates a source scene container.</summary>
public SourceScene(
Skeleton skeleton,
IReadOnlyList<Clip> clips,
float unitScaleCm,
int upAxis = 1, int upAxisSign = 1,
int frontAxis = 2, int frontAxisSign = 1,
int coordAxis = 0, int coordAxisSign = 1,
int originalUpAxis = -1,
IReadOnlyList<string>? notes = null)
{
Skeleton = skeleton ?? throw new ArgumentNullException(nameof(skeleton));
Clips = clips ?? throw new ArgumentNullException(nameof(clips));
UnitScaleCm = unitScaleCm;
UpAxis = upAxis;
UpAxisSign = upAxisSign;
FrontAxis = frontAxis;
FrontAxisSign = frontAxisSign;
CoordAxis = coordAxis;
CoordAxisSign = coordAxisSign;
OriginalUpAxis = originalUpAxis;
Notes = notes ?? Array.Empty<string>();
}
}