using System.Collections.Generic;
using System.Numerics;
using DatReaderWriter.DBObjs;
using DatReaderWriter.Enums;
using DatReaderWriter.Types;
namespace AcDream.Core.Meshing;
///
/// Computes retail's rigid per-part frames for attachments and effects.
/// Visual GfxObj scale is deliberately excluded.
///
///
/// Pose selection matches : an explicit motion
/// frame, then Resting, Default, then the first placement frame. Retail
/// CPartArray::UpdateParts (0x005190F0) scales only the frame
/// origin by the object's scale. CPartArray::SetScaleInternal
/// (0x00518A00) stores Setup DefaultScale separately on the visual
/// CPhysicsPart::gfxobj_scale, so it never enters this rigid frame.
///
public static class SetupPartTransforms
{
public static IReadOnlyList Compute(
Setup setup,
AnimationFrame? motionFrameOverride = null,
float objectScale = 1.0f)
{
ArgumentNullException.ThrowIfNull(setup);
AnimationFrame? source = motionFrameOverride;
if (source is null && setup.PlacementFrames.TryGetValue(Placement.Resting, out var resting))
{
source = resting;
}
else if (source is null && setup.PlacementFrames.TryGetValue(Placement.Default, out var def))
{
source = def;
}
else if (source is null)
{
foreach (var kvp in setup.PlacementFrames)
{
source = kvp.Value;
break;
}
}
if (source is null)
return 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 };
result[i] = Matrix4x4.CreateFromQuaternion(frame.Orientation)
* Matrix4x4.CreateTranslation(frame.Origin * objectScale);
}
return result;
}
}