using System.Numerics;
using AcDream.Content;
using DatReaderWriter;
using DatReaderWriter.DBObjs;
namespace AcDream.App.Rendering;
///
/// Shared primitives behind retail's "resolve a rest-pose DID via master-map
/// slot 7, load its Animation, hold the final frame" algorithm — the
/// mechanism (paperdoll,
/// gmPaperDollUI::RedressCreature @ 0x004A3C22) and
/// (chargen preview,
/// gmCG3DView::StopAnimation @ 0x004EE640) both implement. Extracted
/// per the CC6a review's F11/F12 note ("before adding a FOURTH consumer... a
/// shared RetailHeldPose helper is worth extracting before a fourth
/// held-pose consumer exists") — CC6b's own idle-loop work makes chargen's
/// implementation grow enough that mechanically sharing the two primitives
/// BOTH sites already had byte-identical (DID resolution, final-frame
/// transform composition) is a clean win without forcing the two sites'
/// slightly different per-index LOOP shapes (paperdoll walks an
/// already-built, already-filtered WorldEntity.MeshRefs; chargen
/// walks the pre-filter, Setup-part-indexed scratch list) into one method
/// they don't actually share.
///
internal static class RetailHeldPose
{
///
/// DBCache::GetDIDFromEnumStatic(poseEnum, 7) equivalent: master
/// map → slot 7's sub-map → 's Animation DID.
/// Returns 0 if any link in the chain is missing. MUST be called under
/// the caller's dat lock (see 's
/// datLock doc — DatCollection is not thread-safe).
///
public static uint ResolvePoseDid(IDatReaderWriter dats, uint poseEnum)
{
uint masterDid = (uint)dats.Portal.Db.Header.MasterMapId;
if (masterDid == 0
|| !dats.Portal.TryGet(masterDid, out var master)
|| !master.ClientEnumToID.TryGetValue(7u, out uint subDid)
|| !dats.Portal.TryGet(subDid, out var sub))
{
return 0u;
}
return sub.ClientEnumToID.TryGetValue(poseEnum, out uint did) ? did : 0u;
}
///
/// Retail's per-part pose transform: Scale(defaultScale) *
/// Rotate(orientation) * Translate(origin) — the SAME composition
/// both RetailPaperdollPoseApplicator.Apply and
/// 's pose steps use, whether
/// the (origin, orientation) pair comes from a held final frame or an
/// interpolated idle-cycle frame.
///
public static Matrix4x4 ComposePartTransform(Vector3 defaultScale, Vector3 origin, Quaternion orientation) =>
Matrix4x4.CreateScale(defaultScale)
* Matrix4x4.CreateFromQuaternion(orientation)
* Matrix4x4.CreateTranslation(origin);
}