using System.Collections.Generic;
using System.Numerics;
using DatReaderWriter.DBObjs;
using DatReaderWriter.Enums;
using DatReaderWriter.Types;
namespace AcDream.Core.Meshing;
///
/// Compute the per-part static transforms for a Setup using its
/// PlacementFrames. For each part i, the returned matrix takes a
/// point in part-local space and yields a point in setup-local space at
/// the Setup's resting pose.
///
///
/// Mirrors 's pose-source priority —
/// PlacementFrames[Resting] → [Default] → first available
/// — so that a particle anchor at part i matches the part's
/// visible rest position. If renderer and resolver ever drift on this
/// priority, particles will visibly drift relative to their parent
/// mesh; keep them in lockstep.
///
///
///
/// Returns an empty list when the Setup has no PlacementFrames. The
/// caller (e.g. ParticleHookSink.SpawnFromHook) should then fall
/// back to per part, which is the
/// pre-C.1.5b behavior.
///
///
///
/// For animated entities, per-part transforms vary per animation frame
/// and live in AnimatedEntityState; a future "animated
/// DefaultScript" path would publish those each tick via the same
/// SetEntityPartTransforms seam. Out of scope here.
///
///
public static class SetupPartTransforms
{
public static IReadOnlyList Compute(Setup setup)
{
AnimationFrame? source = null;
if (setup.PlacementFrames.TryGetValue(Placement.Resting, out var resting))
{
source = resting;
}
else if (setup.PlacementFrames.TryGetValue(Placement.Default, out var def))
{
source = def;
}
else
{
foreach (var kvp in setup.PlacementFrames)
{
source = kvp.Value;
break;
}
}
if (source is null) return System.Array.Empty();
int partCount = setup.Parts.Count;
var result = new Matrix4x4[partCount];
for (int i = 0; i < partCount; i++)
{
Frame frame = i < source.Frames.Count
? source.Frames[i]
: new Frame { Origin = Vector3.Zero, Orientation = Quaternion.Identity };
Vector3 scale = i < setup.DefaultScale.Count ? setup.DefaultScale[i] : Vector3.One;
result[i] = Matrix4x4.CreateScale(scale)
* Matrix4x4.CreateFromQuaternion(frame.Orientation)
* Matrix4x4.CreateTranslation(frame.Origin);
}
return result;
}
}