Physics Body

// Physics body.
class RVAPI Body
{
public:
    // Body type.
    enum class Type
    {
        // Fixed object. Does not react to collisions.
        STATIC,

        // Movable object. Does not react to collisions.
        KINEMATIC,

        // Movable object. Reacts to collisions.
        DYNAMIC,

        // Does not participate in the physics simulation.
        NONE
    };

    struct Contact
    {
        // Contact state of intersected objects.
        enum class State
        {
            // Contact is new.
            NEW,

            // Contact is acitve.
            ACTIVE,

            // Contact is ending.
            ENDING
        };

        // Contact state.
        State state;

        // Normal of contact on other body.
        S3f norm;

        // Point of contact on this body.
        S3f selfPt;

        // Point of contact on other body.
        S3f otherPt;

        // Other reference.
        void *ref;

        // Contact ID.
        uint id;
    };

    // Get world space position.
    M4f GetPos() const;

    // Get angular velocity.
    S3f GetAngVel() const;

    // Get linear velocity.
    S3f GetLinVel() const;

    // Get host entity from contact.
    EntKey GetHost(const Contact &contact) const;

    // Get first contact. Initializes [index] iterator. Returns 0 if no contact.
    const Contact *GetFirstContact(int &index) const;

    // Get next contact. Updates [index] iterator. Returns 0 if no contact.
    const Contact *GetNextContact(int &index) const;

    // Add cone joint between bodies. [angle] is maximum movement angle.
    uint AddConeJoint(Body &other, float angle);

    // Add revolute (hinge) joint between this body and [other] body. [posA] is world space joint position on this body. 
    // [posB] is world space joint position on other body. [lowerAngle] is low angle limit, or zero for no limit. 
    // [upperAngle] is high angle limit, or zero for no limit. [speed] is motor speed, or zero for no motor. [maxTorque] 
    // is maximum motor torque, or zero if no motor. Returns joint ID
    uint AddRevoluteJoint(Body &other, const M4f &posA, const M4f &posB, float lowerAngle, float upperAngle, float speed, float maxTorque);

    // Add sphere joint between this body and other body. [posA] is world space joint position on this body. 
    // [posB] is world space joint position on other body. Returns joint ID.
    uint AddSphereJoint(Body &other, const S3f &posA, const S3f &posB);

    // Add weld (fixed) joint between this body and [other] body. Returns joint ID.
    uint AddWeldJoint(Body &other);

    // Add spring joint between this body and [other] body. [posA] is world space joint position on this body. 
    // [posB] is world space joint position on other body. [length] is pring length. [freq] is spring frequency. 
    // [damp] is spring damping. Set [collideConnected] to true if connected body should collide with self.
    // Returns joint ID.
    uint AddSpringJoint(Body &other, const S3f &posA, const S3f &posB, float length, float freq, float damp, bool collideConnected = true);

    // Remove joint with [id].
    void RemoveJoint(uint id);

    // Apply force. [force] is force vector in world space. Set [wake] true if force should wake body.
    void ApplyForce(const S3f &force, bool wake = true);

    // Apply force at body point. [force] is orce vector in world space.
    // [pos] is force position in world space.  Set [wake] true if force should wake body.
    void ApplyForce(const S3f &force, const S3f &pos, bool wake = true);

    // Apply torque. [torque] is torque vector in world space. Set [wake] true if force should wake body.
    void ApplyTorque(const S3f &torque, bool wake = true);

    // Apply angular impulse. [imp] is impulse vector in world space. Set [wake] true if force should wake body.
    void ApplyAngImp(const S3f &imp, bool wake = true);

    // Apply linear impulse. [imp] is impulse vector in world space. Set [wake] true if force should wake body.
    void ApplyLinImp(const S3f &imp, bool wake = true);

    // Apply linear impulse at point. [imp] is mpulse vector in world space. [pos] is impulse position in world space. 
    // Set [wake] true if force should wake body.
    void ApplyLinImp(const S3f &imp, const S3f &pos, bool wake = true);

    // Set angular damping. [damp] is damping vector.
    void SetAngDamp(const S3f &damp);

    // Set linear damping. [damp] is damping vector.
    void SetLinDamp(const S3f &damp);

    // Set angular velocity. [vel] is velocity vector.
    void SetAngVel(const S3f &vel);

    // Set linear velocity. [vel] is velocity vector.
    void SetLinVel(const S3f &vel);

    // Wake/Sleep body. Set [awake] to true to wake body, false to sleep body.
    void SetAwake(bool awake);

    // Set gravity effect. [scale] is gravity scale. Default is 1.
    void SetGravityScale(const S3f &scale);

    // Set world space position. [pos] is position matrix.
    void SetPos(const M4f &pos);

    // Add collision shape. [shape] is collision shape.
    void AddCollShape(const CollShape &shape);

    // Set physics properties. [mass] is mass value. Default is 1. [center] is center of mass. Default is (0, 0, 0).
    // [inertiaX] is x inertia tensor. Normally use (1, 0, 0). [inertiaY] is y inertia tensor. Normally use (0, 1, 0).
    // [inertiaZ] is z inertia tensor. Normally use (0, 0, 1).
    void SetProps(float mass, const S3f ¢er = S3f(0, 0, 0), const S3f &inertiaX = S3f(1, 0, 0),
        const S3f &inertiaY = S3f(0, 1, 0), const S3f &inertiaZ = S3f(0, 0, 1));

    // Internal.
    void *operator () () const { return (void *)wobj; }

    // Initialize physics body. [host] is host entity. [type] is body type. [pos] is initial body position. [collMask] 
    // is collision bit mask. Only bodies with same bits collide. 0=collide all. [rotMask] flags restrict rotation. 
    // 1=X 2=Y 4=Z. Set [wantContacts] to true if collision contacts are wanted.
    Body(EntKey host, Type type, const M4f &pos, uint collMask = 0, uint rotMask = 0, bool wantContacts = false);

    // Destructor.
    ~Body();

private:
    byte wobj[320];
};