This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/wwphys/rbody.h

361 lines
No EOL
11 KiB
C++

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RBODY_H
#define RBODY_H
#include "always.h"
#include "movephys.h"
#include "ode.h"
#include "aabox.h"
#include "quat.h"
#include "physcon.h"
#include "wwdebug.h"
class RigidBodyDefClass;
class OBBoxRenderObjClass;
class PaddedBoxClass;
class OctBoxClass;
class RBodyHistoryClass;
struct CastResultStruct;
const int MAX_CONTACT_POINTS = 10;
const float RBODY_SLEEP_DELAY = 0.5f; // if still for this many seconds, shut off simulation
/**
** RigidBodyStateStruct
** This is the state vector for a RigidBodyClass.
*/
struct RigidBodyStateStruct
{
RigidBodyStateStruct(void) {}
RigidBodyStateStruct(const RigidBodyStateStruct & that);
RigidBodyStateStruct & operator = (const RigidBodyStateStruct & that);
void Reset(void);
void To_Vector(StateVectorClass & vec);
int From_Vector(const StateVectorClass & vec,int index);
static void Lerp(const RigidBodyStateStruct & s0,const RigidBodyStateStruct & s1,float fraction,RigidBodyStateStruct * res);
bool Is_Valid(void) { return (Position.Is_Valid() && Orientation.Is_Valid() && LMomentum.Is_Valid() && AMomentum.Is_Valid()); }
Vector3 Position;
Quaternion Orientation;
Vector3 LMomentum;
Vector3 AMomentum;
};
/**
** RigidBodyClass
** Simulation of a rigid body. The shape is limited to be an oriented box.
*/
class RigidBodyClass : public MoveablePhysClass , public ODESystemClass
{
public:
RigidBodyClass(void);
virtual ~RigidBodyClass(void);
virtual RigidBodyClass * As_RigidBodyClass(void) { return this; }
RigidBodyDefClass * Get_RigidBodyDef(void) { return (RigidBodyDefClass *)Definition; }
void Init(const RigidBodyDefClass & definition);
virtual const AABoxClass & Get_Bounding_Box(void) const;
virtual const Matrix3D & Get_Transform(void) const;
virtual void Set_Transform(const Matrix3D & m);
virtual bool Cast_Ray(PhysRayCollisionTestClass & raytest);
virtual bool Cast_AABox(PhysAABoxCollisionTestClass & boxtest);
virtual bool Cast_OBBox(PhysOBBoxCollisionTestClass & boxtest);
virtual bool Intersection_Test(PhysAABoxIntersectionTestClass & test);
virtual bool Intersection_Test(PhysOBBoxIntersectionTestClass & test);
virtual bool Intersection_Test(PhysMeshIntersectionTestClass & test);
/*
** Teleport support
*/
virtual bool Can_Teleport(const Matrix3D &new_tm, bool check_dyn_only = false,NonRefPhysListClass * result_list = NULL);
virtual bool Can_Teleport_And_Stand(const Matrix3D &new_tm, Matrix3D *out);
/*
** State
*/
void Get_Orientation(Quaternion * set_q) const { *set_q = State.Orientation; }
virtual void Get_Velocity(Vector3 * set_vel) const;
virtual void Get_Angular_Velocity(Vector3 * set_avel) const;
virtual void Set_Velocity(const Vector3 & newvel);
virtual void Set_Angular_Velocity(const Vector3 & newavel);
virtual void Apply_Impulse(const Vector3 & imp);
virtual void Apply_Impulse(const Vector3 & imp, const Vector3 & wpos);
virtual void Timestep(float dt);
void Compute_Point_Velocity(const Vector3 & p,Vector3 * pdot);
float Get_Last_Timestep(void) { return LastTimestep; }
/*
** Networking code.
** Network_Interpolate_State_Update - interpolate towards the given state
** Network_Latency_State_Update - client player update, interpolate, considering latency.
*/
void Network_Interpolate_State_Update( const Vector3 & new_pos,
const Quaternion & new_orientation,
const Vector3 & new_vel,
const Vector3 & new_avel,
float blend_fraction);
void Network_Latency_State_Update( const Vector3 & new_pos,
const Quaternion & new_orientation,
const Vector3 & new_vel,
const Vector3 & new_avel);
static void Set_Correction_Time(float time) { _CorrectionTime = time; }
static float Get_Correction_Time(void) { return _CorrectionTime; }
/*
** Properties
*/
virtual void Set_Model(RenderObjClass * model);
virtual void Set_Mass(float mass);
virtual void Get_Inertia_Inv(Matrix3 * set_I_inv);
void Set_Inertia(const Matrix3 & I);
void Get_Inertia(Matrix3 * I);
void Set_Contact_Parameters(float length);
void Get_Contact_Parameters(float * stiffness,float * damping,float * length);
float Get_Weight(void) { return GravScale * Mass * (-PhysicsConstants::GravityAcceleration.Z); }
/*
** Shadow support
*/
virtual void Get_Shadow_Blob_Box(AABoxClass * set_obj_space_box);
/*
** MoveablePhysClass Push interface. RigidBody's try to move when they are pushed.
*/
virtual bool Push(const Vector3 & move);
/*
** Save-Load System
*/
virtual const PersistFactoryClass & Get_Factory (void) const;
virtual bool Save (ChunkSaveClass &csave);
virtual bool Load (ChunkLoadClass &cload);
virtual void On_Post_Load(void);
protected:
/*
** Integration system
*/
virtual void Get_State(StateVectorClass & set_state);
virtual int Set_State(const StateVectorClass & new_state,int start_index);
void Set_State(const RigidBodyStateStruct & new_state);
virtual int Compute_Derivatives(float t,StateVectorClass * test_state,StateVectorClass * set_derivs,int start_index);
void Integrate(float time);
/*
** Internal functions
*/
void Update_Cached_Model_Parameters(void);
virtual void Compute_Inertia(void);
void Update_Auxiliary_State(void);
virtual void Compute_Force_And_Torque(Vector3 * force,Vector3 * torque);
void Compute_Impact(const CastResultStruct & result,Vector3 * impulse);
void Compute_Impact(const Vector3 & point,const Vector3 & normal,Vector3 * impulse);
bool Is_Colliding(const Vector3 & point, const Vector3 & normal);
void Set_Moving_Collision_Region(float dt);
void Set_Stationary_Collision_Region(void);
virtual bool Can_Go_To_Sleep(float dt);
bool Find_State_In_Contact_Zone(const RigidBodyStateStruct & oldstate);
bool Push_Phys3_Object_Away(Phys3Class * p3obj,const CastResultStruct & contact);
void Network_Latency_Error_Correction(float dt);
void Assert_State_Valid(void) const;
void Assert_Not_Intersecting(void);
void Dump_State(void) const;
/*
** Physical Description:
*/
OBBoxRenderObjClass * Box; // World-Space Box
Matrix3 IBody; // Body space inertia tensor
Matrix3 IBodyInv; // Inverse of the body space inertia tensor
OctBoxClass * ContactBox; // datastructure for finding contact points
float ContactThickness; // Dimension of the contact region
/*
** State vector
*/
RigidBodyStateStruct State; // current state vector
/*
** Quantities derived from (dependent on) the current state
*/
Matrix3 Rotation;
Matrix3 IInv;
Vector3 Velocity;
Vector3 AngularVelocity;
/*
** Other Member variables
*/
bool IsInContact;
int ContactCount;
Vector3 ContactPoint[MAX_CONTACT_POINTS];
Vector3 ContactNormal;
int StickCount;
float LastTimestep;
float GoToSleepTimer;
/*
** Network history for latency handling
*/
RBodyHistoryClass * History;
RigidBodyStateStruct LatencyError;
RigidBodyStateStruct LastKnownState;
static float _CorrectionTime;
private:
// not implemented
RigidBodyClass(const RigidBodyClass &);
RigidBodyClass & operator = (const RigidBodyClass &);
};
inline RigidBodyStateStruct::RigidBodyStateStruct(const RigidBodyStateStruct & that)
{
*this = that;
}
inline RigidBodyStateStruct & RigidBodyStateStruct::operator = (const RigidBodyStateStruct & that)
{
Position = that.Position;
Orientation = that.Orientation;
LMomentum = that.LMomentum;
AMomentum = that.AMomentum;
return *this;
}
inline void RigidBodyStateStruct::Reset(void)
{
Position.Set(0,0,0);
Orientation.Make_Identity();
LMomentum.Set(0,0,0);
AMomentum.Set(0,0,0);
}
inline void RigidBodyStateStruct::To_Vector(StateVectorClass & vec)
{
vec.Add(Position[0]);
vec.Add(Position[1]);
vec.Add(Position[2]);
vec.Add(Orientation[0]);
vec.Add(Orientation[1]);
vec.Add(Orientation[2]);
vec.Add(Orientation[3]);
vec.Add(LMomentum[0]);
vec.Add(LMomentum[1]);
vec.Add(LMomentum[2]);
vec.Add(AMomentum[0]);
vec.Add(AMomentum[1]);
vec.Add(AMomentum[2]);
}
inline int RigidBodyStateStruct::From_Vector(const StateVectorClass & vec,int index)
{
Position[0] = vec[index++];
Position[1] = vec[index++];
Position[2] = vec[index++];
Orientation[0] = vec[index++];
Orientation[1] = vec[index++];
Orientation[2] = vec[index++];
Orientation[3] = vec[index++];
LMomentum[0] = vec[index++];
LMomentum[1] = vec[index++];
LMomentum[2] = vec[index++];
AMomentum[0] = vec[index++];
AMomentum[1] = vec[index++];
AMomentum[2] = vec[index++];
return index;
}
inline void RigidBodyStateStruct::Lerp
(
const RigidBodyStateStruct & s0,
const RigidBodyStateStruct & s1,
float fraction,
RigidBodyStateStruct * res
)
{
Vector3::Lerp(s0.Position,s1.Position,fraction,&(res->Position));
Vector3::Lerp(s0.LMomentum,s1.LMomentum,fraction,&(res->LMomentum));
Vector3::Lerp(s0.AMomentum,s1.AMomentum,fraction,&(res->AMomentum));
::Fast_Slerp(res->Orientation,s0.Orientation,s1.Orientation,fraction);
}
/**
** RigidBodyDefClass
** Initialization data structure for RigidBodyClass
*/
class RigidBodyDefClass : public MoveablePhysDefClass
{
public:
RigidBodyDefClass(void);
// From DefinitionClass
virtual uint32 Get_Class_ID (void) const;
virtual PersistClass * Create(void) const;
// From PhysDefClass
virtual const char * Get_Type_Name(void) { return "RigidBodyDef"; }
virtual bool Is_Type(const char *);
// From PersistClass
virtual const PersistFactoryClass & Get_Factory (void) const;
virtual bool Save(ChunkSaveClass &csave);
virtual bool Load(ChunkLoadClass &cload);
// In-Game Editing (DEBUGGING/TESTING ONLY)
float Get_Aerodynamic_Drag(void) { return AerodynamicDragCoefficient; }
void Set_Aerodynamic_Drag(float new_drag) { AerodynamicDragCoefficient = new_drag; }
// Editable interface requirements
DECLARE_EDITABLE(RigidBodyDefClass,MoveablePhysDefClass);
protected:
// Variables
float AerodynamicDragCoefficient;
bool CollisionDisabled;
friend class RigidBodyClass;
};
#endif