/* ** 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/octbox.h $* * * * Original Author:: Greg Hjelstrom * * * * $Author:: Greg_h $* * * * $Modtime:: 11/21/01 2:48p $* * * * $Revision:: 14 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #if defined(_MSC_VER) #pragma once #endif #ifndef OCTBOX_H #define OCTBOX_H #include "always.h" #include "obbox.h" #include "rbody.h" /** ** OctBoxClass ** This class encapsulates the collision detection algorithms used by Renegade's "rigid-body" ** physics. It basically acts like rigid box with a contact zone around it. Contacts are detected ** when geometry is within "thickness" distance of the rigid box. */ class OctBoxClass { public: OctBoxClass(RigidBodyClass & parent,const OBBoxClass & box); ~OctBoxClass(void); void Set_Stiffness(float stiffness) { Stiffness = stiffness; } float Get_Stiffness(void) const { return Stiffness; } void Set_Damping(float damping) { Damping = damping; } float Get_Damping(void) const { return Damping; } void Set_Thickness(float thickness); float Get_Thickness(void) { return Thickness; } void Update_Contact_Parameters(void); enum CollisionResult { RESULT_NO_COLLISION = 0, // this object isn't touching anything RESULT_INTERSECTION, // this object has penetrated another, have to back up RESULT_CONTACT, // no penetration but there is contact. }; void Set_Transform(const Matrix3D & tm); void Set_Transform(const Quaternion & q,const Vector3 & p); bool Is_Intersecting(NonRefPhysListClass * result_list = NULL,bool check_static_objs = true,bool check_dyn_objs = true); bool Is_In_Contact_Zone(void); CollisionResult Compute_Contacts(bool lock_to_centroids = false); int Get_Contact_Count(void); const CastResultStruct &Get_Contact(int index); PhysClass * Peek_Contacted_Object(int index); void Get_Outer_Bounds(AABoxClass * set_bounds); void Get_Outer_Box(OBBoxClass * set_box) { *set_box = Get_World_Inner_Box(); } void Get_Inner_Box(OBBoxClass * set_box) { *set_box = Get_World_Inner_Box(); set_box->Extent += Vector3(Thickness,Thickness,Thickness); } void Get_Inner_Box(OBBoxClass * set_box, const Quaternion & q, const Vector3 & p); float Get_Extent_Length2() { return InnerBox.Extent.Length2(); } public: //protected: CollisionResult Internal_Compute_Contacts(bool lock_to_centroids); void Compute_Octant_Contact(int oi,bool lock_to_centroids); void Transform_To_World_Space(const Matrix3D & tm); void Transform_To_World_Space(const Quaternion & q,const Vector3 & p); void Reset_Contacts(void); void Add_Contact(const CastResultStruct & res,PhysClass * other_obj); const OBBoxClass & Get_World_Inner_Box(void) { return WrldInnerBox; } /* ** Properties */ RigidBodyClass & Parent; // parent object this OctBox is working for OBBoxClass InnerBox; // OBBox for the parent when parent's TM is I float Thickness; // thickness of the "squishy zone" float Stiffness; // spring stiffness to use float Damping; // damping coefficient to use Vector3 OctantCenter; // offest to center of octant0 in InnerBox's coord system Vector3 OctantExtent; // extent of the octant boxes /* ** Current State */ OBBoxClass WrldInnerBox; /* ** Contact Accumulation */ enum { MAX_CONTACTS = 16 }; int ContactCount; CastResultStruct Contacts[MAX_CONTACTS]; PhysClass * ContactedObject[MAX_CONTACTS]; }; inline void OctBoxClass::Set_Transform(const Matrix3D & tm) { Transform_To_World_Space(tm); } inline void OctBoxClass::Set_Transform(const Quaternion & q,const Vector3 & p) { Transform_To_World_Space(q,p); } inline int OctBoxClass::Get_Contact_Count(void) { return ContactCount; } inline const CastResultStruct & OctBoxClass::Get_Contact(int index) { static CastResultStruct _no_result; if ((index >= 0) && (index < ContactCount)) { return Contacts[index]; } else { return _no_result; } } inline PhysClass * OctBoxClass::Peek_Contacted_Object(int index) { if ((index >= 0) && (index < ContactCount)) { return ContactedObject[index]; } else { return NULL; } } inline void OctBoxClass::Transform_To_World_Space(const Matrix3D & tm) { OBBoxClass::Transform(tm,InnerBox,&WrldInnerBox); } inline void OctBoxClass::Transform_To_World_Space(const Quaternion & q,const Vector3 & p) { Matrix3D tm(q,p); OBBoxClass::Transform(tm,InnerBox,&WrldInnerBox); } inline void OctBoxClass::Reset_Contacts(void) { ContactCount = 0; } inline void OctBoxClass::Add_Contact(const CastResultStruct & res,PhysClass * other_obj) { WWASSERT(ContactCount < MAX_CONTACTS); Contacts[ContactCount] = res; ContactedObject[ContactCount] = other_obj; ContactCount++; } inline void OctBoxClass::Get_Inner_Box(OBBoxClass * set_box, const Quaternion & q, const Vector3 & p) { Matrix3D tm(q,p); OBBoxClass::Transform(tm,InnerBox,set_box); } #endif