using System.Numerics;
namespace AcDream.Core.Physics;
///
/// One collision-bearing shape attached to a logical PhysicsObj.
/// The set is a DISPATCH, not a union (AP-152): a BSP door emits one shape
/// per physics-BSP part and no primitive; a primitive-only object emits its
/// CylSpheres, else its Spheres; a simple item zero. Positions and rotations are
/// LOCAL to the entity's origin so
/// can re-transform them when the entity moves.
///
///
/// Retail anchor: CPhysicsPart + CPhysicsPart::find_obj_collisions
/// at acclient_2013_pseudo_c.txt:275045-275055. Each part stores its
/// own transform and dispatches per-part collision to its GfxObj.
///
///
///
/// Center of the shape's bounding sphere IN THE SHAPE'S OWN LOCAL FRAME —
/// the frame rotates out of and
/// is measured in — already multiplied by the entity
/// scale, like and .
/// Zero for Cylinder/Sphere shapes, whose
/// already IS their center.
///
///
/// BSP shapes need it because a GfxObj's physics BSP is authored in the
/// GfxObj's own coordinates and its root bounding sphere is frequently NOT
/// centered on that origin (376 of the 973 physics-BSP parts in the
/// installed client_portal.dat sit further from it than half their
/// own radius; worst 20.762 m on a 27.708 m sphere, gfx 0x010036DD).
/// 's flood needs the
/// sphere's real position, not the part origin's.
///
///
///
/// Retail anchor: CGfxObj::physics_sphere ([gfxobj+0x74]) is
/// assigned BSPTREE::GetSphere(physics_bsp) @0x005397e0
/// (mov eax,[ecx]; add eax,4 — the root BSPNODE's
/// CSphere sphere, past its 4-byte vftable), so retail's per-part
/// flood sphere IS the BSP root bounding sphere, origin included.
/// CEnvCell::find_transit_cells @0x0052cae0 — the part-array overload
/// reached from CPhysicsObj::find_bbox_cell_list @0x00510fc0 via
/// CPartArray::calc_cross_cells_static @0x00518160's
/// [vtbl+0x7c] dispatch — loads that sphere at
/// 0x0052cb36 mov esi,[ecx+0x74], transforms its CENTER through the
/// part's own Position at [part+0x30]
/// (0x0052cb4c add eax,0x30 / 0x0052cb5a call Position::localtolocal),
/// and only then reads the radius at 0x0052cb65 fadd [esi+0xc].
///
///
public readonly record struct ShadowShape(
uint GfxObjId,
Vector3 LocalPosition,
Quaternion LocalRotation,
float Scale,
ShadowCollisionType CollisionType,
float Radius,
float CylHeight,
Vector3 BoundsCenter = default);