/* ** 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 . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : WWPhys * * * * $Archive:: /Commando/Code/wwphys/phys3.h $* * * * Author:: Greg Hjelstrom * * * * $Modtime:: 10/24/01 11:15a $* * * * $Revision:: 46 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #if defined(_MSC_VER) #pragma once #endif #ifndef PHYS3_H #define PHYS3_H #include "vector3.h" #include "movephys.h" #include "ode.h" class Phys3DefClass; class Phys3HistoryClass; /** ** Phys3Class ** 3 Degree of Freedom Physics ** This object can translate in X,Y,and Z. It will be represented ** in the world by an axis-aligned box. */ class Phys3Class : public MoveablePhysClass { public: Phys3Class(void); virtual ~Phys3Class(void); virtual Phys3Class * As_Phys3Class(void) { return this; } void Init(const Phys3DefClass & def); virtual const AABoxClass & Get_Bounding_Box(void) const; virtual const Matrix3D & Get_Transform(void) const; virtual void Set_Transform(const Matrix3D & m); virtual const AABoxClass & Get_Collision_Box(void) const { return CollisionBox; } 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); virtual void Set_Model(RenderObjClass * model); virtual void Get_Velocity(Vector3 * set_vel) const; virtual void Set_Velocity(const Vector3 & newvel); virtual void Apply_Impulse(const Vector3 & imp); virtual void Apply_Impulse(const Vector3 & imp, const Vector3 & wpos); virtual void Timestep(float dt); virtual bool Is_In_Contact(void) const { return OnGround; } // Set_In_Contact needed for network state updates so we don't have to wait for Check_Ground virtual void Set_In_Contact( bool onoff ) { OnGround = onoff; } virtual int Get_Contact_Surface_Type(void) { return GroundSurface; } virtual void Invalidate_Ground_State(void); PhysClass * Peek_Ground_Object(void) { return GroundState.GroundObject; } void Assert_State_Valid(void); /* ** 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); virtual bool Find_Teleport_Location(const Vector3 &start, float radius, Vector3 *out); virtual bool Can_Move_To(const Matrix3D &new_tm); /* ** Phys3 movement controls */ virtual void Set_Position(const Vector3 & position); virtual const Vector3 & Get_Position(void) const; virtual void Set_Heading(float heading); virtual float Get_Heading(void) const; virtual void Set_Slide_Angle(float angle); virtual float Get_Slide_Angle(void) const; virtual void Set_Normalized_Speed(float val) { NormSpeed = val; } virtual float Get_Normalized_Speed(void) const { return NormSpeed; } void Add_Animation_Move(const Vector3 & move) { AnimationMove += move; } void Get_Animation_Move(Vector3 * set_move) { *set_move = AnimationMove; } void Reset_Animation_Move(void) { AnimationMove.Set(0,0,0); } /* ** Shadow support */ virtual void Get_Shadow_Blob_Box(AABoxClass * set_obj_space_box); void Get_Collision_Box(AABoxClass * set_box); /* ** MoveablePhysClass Push interface. Phys3's try to move when they are pushed. */ virtual bool Push(const Vector3 & move); virtual bool Collide(const Vector3 & move); /* ** Network state updates */ void Network_State_Update( const Vector3 & pos, const Vector3 & vel); void Network_Latency_State_Update( const Vector3 & pos, const Vector3 & vel); static void Set_Correction_Time(float time) { _CorrectionTime = time; } static void Set_Allowable_Error(float err) { _AllowableError = err; } static void Set_Pop_Error(float err) { _PopError = err; } static float Get_Correction_Time(void) { return _CorrectionTime; } static float Get_Allowable_Error(void) { return _AllowableError; } static float Get_Pop_Error(void) { return _PopError; } /* ** 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: /* ** GroundStateStruct status of the object's contact with the ground */ struct GroundStateStruct { GroundStateStruct(void); void Reset(void); void Init_From_Collision_Result(PhysAABoxCollisionTestClass & test,float height); bool IsDirty; // data contained within is invalid bool OnGround; // indicates whether the object is "on the ground" bool OnDynamicObj; // must "dirty" the groundstate at end of frame if we're on a dyn obj int SurfaceType; // surface type the object is resting on float Height; // our height above the ground Vector3 Normal; // normal for the surface Vector3 Down; // slide direction for the surface PhysClass * GroundObject; // pointer to the object we are on RenderObjClass * GroundRenderObject; }; /* ** State of a Phys3 object */ struct StateStruct { StateStruct(void); StateStruct(const StateStruct & that); StateStruct & operator = (const StateStruct & that); Vector3 Position; Vector3 Velocity; }; /* ** Phys3 Movement algorithm */ virtual GroundStateStruct & Get_Ground_State(void); virtual void Check_Ground(const AABoxClass & box,GroundStateStruct * gs,float check_dist); virtual bool User_Move(float dt); virtual bool Ballistic_Move(float dt); virtual bool Slide_Move(const GroundStateStruct & gs,float dt); virtual bool Normal_Move(const GroundStateStruct & gs,float dt); virtual bool Collide_Move(const Vector3 & requested_move,float dt); bool Apply_Move(const Vector3 & move,float dt,bool allow_sliding = true,bool allow_stepping = false,bool stop_on_walkable = false); void Snap_To_Ground(const Vector3 & actual_move,bool was_stepping); void Clip_Move(const Vector3 * contacts,int contact_count,Vector3 * move); void Attach_To_Ground_Object(void); /* ** Internal functions */ void Update_Cached_Model_Parameters(void); void Update_Transform(bool position_only = false); void Compute_WS_Collision_Box(const StateStruct & state,AABoxClass * set_box); bool Debug_Verify_Position(void); void Network_Teleport_Correction(void); enum MoveModeType { USER_OVERRIDE = 0, BALLISTIC_MOVE, SLIDE_MOVE, NORMAL_MOVE, COLLIDE_MOVE }; /* ** Members */ AABoxClass CollisionBox; // object space collision box bool OnGround; // flag indicates whether object is resting on something bool InCollision; // this object is already participating in a collision bool HeadingChanged; // If the heading changes, transform will be updated on next timestep int GroundSurface; // surface type id of the ground we're standing on. StateStruct State; // state vector float Heading; // heading, a move of 1,0,0 will move in this direction. float NormSpeed; // speed to move when controller is 1.0 float SlideAngle; // slope angle at which this object slides off float SlideNormalZ; // cos(SlideAngle) float SlideAngleTan; // tan(SlideAngle) float StepHeight; // step side that this object will hop over MoveModeType MoveMode; // current movement mode PhysClass * GroundObject; // object that we are standing on GroundStateStruct GroundState; // info on the surface we're standing on (if any) Vector3 AnimationMove; // how far this object moved for animation purposes Phys3HistoryClass * History; // history of our state for smarter network updating Vector3 LatencyError; // remaining latency error Vector3 LastKnownPosition;// last position received from server Vector3 LastKnownVelocity;// last velocity received from server static float _CorrectionTime; // Network correction handling constants static float _AllowableError; static float _PopError; private: // not implemented Phys3Class(const Phys3Class &); Phys3Class & operator = (const Phys3Class &); }; inline void Phys3Class::Get_Velocity(Vector3 * set_vel) const { *set_vel = State.Velocity; } inline void Phys3Class::Set_Velocity(const Vector3 & newvel) { State.Velocity = newvel; } inline void Phys3Class::Compute_WS_Collision_Box(const StateStruct & state,AABoxClass * set_box) { set_box->Center = CollisionBox.Center + state.Position; set_box->Extent = CollisionBox.Extent; } inline Phys3Class::StateStruct::StateStruct(void) : Position(0,0,0), Velocity(0,0,0) { } inline Phys3Class::StateStruct::StateStruct(const StateStruct & that) { *this = that; } inline Phys3Class::StateStruct & Phys3Class::StateStruct::operator = (const StateStruct & that) { Position = that.Position; Velocity = that.Velocity; return *this; } /** ** Phys3DefClass ** Initialization/Game-Database support for Phys3Class */ class Phys3DefClass : public MoveablePhysDefClass { public: Phys3DefClass(void); // From Definition virtual uint32 Get_Class_ID (void) const; virtual PersistClass * Create(void) const; // From PhysDefClass virtual const char * Get_Type_Name(void) { return "Phys3Def"; } 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); // Editable interface requirements DECLARE_EDITABLE(Phys3DefClass,MoveablePhysDefClass); protected: float NormSpeed; // speed to move when controller is 1.0 float SlideAngle; // slope angle at which this object slides off float StepHeight; // step side that this object will hop over friend class Phys3Class; }; #endif