using System.Numerics; using AcDream.Core.World; using DatReaderWriter.DBObjs; using DatReaderWriter.Enums; using DatReaderWriter.Types; namespace AcDream.Core.Meshing; public static class SetupMesh { /// /// Flatten a Setup into a list of (GfxObjId, PartTransform) refs. /// Uses the default placement frame and DefaultScale per part. /// Does NOT walk ParentIndex — each part's transform is local to the setup root. /// This is simplification for Phase 2; complex hierarchical rigs are Phase 3. /// public static IReadOnlyList Flatten(Setup setup) { AnimationFrame? defaultAnim = null; if (setup.PlacementFrames.TryGetValue(Placement.Default, out var af)) defaultAnim = af; var result = new List(setup.Parts.Count); for (int i = 0; i < setup.Parts.Count; i++) { uint gfxObjId = (uint)setup.Parts[i]; Frame frame; if (defaultAnim is not null && i < defaultAnim.Frames.Count) frame = defaultAnim.Frames[i]; else frame = new Frame { Origin = Vector3.Zero, Orientation = Quaternion.Identity }; Vector3 scale = i < setup.DefaultScale.Count ? setup.DefaultScale[i] : Vector3.One; var transform = Matrix4x4.CreateScale(scale) * Matrix4x4.CreateFromQuaternion(frame.Orientation) * Matrix4x4.CreateTranslation(frame.Origin); result.Add(new MeshRef(gfxObjId, transform)); } return result; } }