| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 |
- /*
- ** 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/>.
- */
- /***********************************************************************************************
- *** 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/trackedvehicle.cpp $*
- * *
- * Original Author:: Greg Hjelstrom *
- * *
- * $Author:: Byon_g $*
- * *
- * $Modtime:: 3/15/02 1:44p $*
- * *
- * $Revision:: 12 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "trackedvehicle.h"
- #include "rendobj.h"
- #include "lineseg.h"
- #include "lookuptable.h"
- #include "physcoltest.h"
- #include "pscene.h"
- #include "physcontrol.h"
- #include "wwphysids.h"
- #include "persistfactory.h"
- #include "simpledefinitionfactory.h"
- #include "wwhack.h"
- #include "wwprofile.h"
- #include "wheel.h"
- #include "octbox.h"
- #include "mesh.h"
- #include "meshmdl.h"
- #include "matinfo.h"
- #include "vertmaterial.h"
- #include "mapper.h"
- #include <string.h>
- DECLARE_FORCE_LINK(trackedvehicle);
- static bool _is_left_track_name(const char * name)
- {
- const char * LEFT_TRACK_NAME0 = "V_TRACK-L";
- const char * LEFT_TRACK_NAME1 = "V_TREAD-L";
- const char * LEFT_TRACK_NAME2 = "V_TRACK_L";
- const char * LEFT_TRACK_NAME3 = "V_TREAD_L";
-
- /*
- ** Track skins can only be sub-objects of a hierarchy so check the name
- ** after the hierarchy name.
- */
- const char * sub_name = strchr(name,'.');
- if (sub_name != NULL) {
- sub_name++;
- if ( (strnicmp(sub_name,LEFT_TRACK_NAME0,strlen(LEFT_TRACK_NAME0)) == 0) ||
- (strnicmp(sub_name,LEFT_TRACK_NAME1,strlen(LEFT_TRACK_NAME1)) == 0) ||
- (strnicmp(sub_name,LEFT_TRACK_NAME2,strlen(LEFT_TRACK_NAME2)) == 0) ||
- (strnicmp(sub_name,LEFT_TRACK_NAME3,strlen(LEFT_TRACK_NAME3)) == 0))
- {
- return true;
- }
- }
- return false;
- }
- static bool _is_right_track_name(const char * name)
- {
- const char * RIGHT_TRACK_NAME0 = "V_TRACK-R";
- const char * RIGHT_TRACK_NAME1 = "V_TREAD-R";
- const char * RIGHT_TRACK_NAME2 = "V_TRACK_R";
- const char * RIGHT_TRACK_NAME3 = "V_TREAD_R";
- /*
- ** Track skins can only be sub-objects of a hierarchy so check the name
- ** after the hierarchy name.
- */
- const char * sub_name = strchr(name,'.');
- if (sub_name != NULL) {
- sub_name++;
- if ( (strnicmp(sub_name,RIGHT_TRACK_NAME0,strlen(RIGHT_TRACK_NAME0)) == 0) ||
- (strnicmp(sub_name,RIGHT_TRACK_NAME1,strlen(RIGHT_TRACK_NAME1)) == 0) ||
- (strnicmp(sub_name,RIGHT_TRACK_NAME2,strlen(RIGHT_TRACK_NAME2)) == 0) ||
- (strnicmp(sub_name,RIGHT_TRACK_NAME3,strlen(RIGHT_TRACK_NAME3)) == 0))
- {
- return true;
- }
- }
- return false;
- }
- /**************************************************************************************
- **
- ** TrackedVehicleClass Implementation
- **
- **************************************************************************************/
-
- /*
- ** Declare a PersistFactory for TrackedVehicleClasses
- */
- SimplePersistFactoryClass<TrackedVehicleClass,PHYSICS_CHUNKID_TRACKEDVEHICLE> _TrackedVehicleFactory;
- /*
- ** Chunk-ID's used by tracked vehicle class
- */
- enum
- {
- TRACKEDVEHICLE_CHUNK_VEHICLEPHYS = 0x00119801,
- TRACKEDVEHICLE_CHUNK_VARIABLES,
- };
- // Debugging colors
- const Vector3 SPRING_COLOR(1.0f,0.5f,0.0f);
- const Vector3 SUSPENSION_FORCE_COLOR(1.0f,0.0f,0.0f);
- TrackedVehicleClass::TrackedVehicleClass(void) :
- LeftTrackMovement(0),
- RightTrackMovement(0),
- LeftTrackLastPosition(0,0,0),
- RightTrackLastPosition(0,0,0)
- {
- }
-
- void TrackedVehicleClass::Init(const TrackedVehicleDefClass & def)
- {
- VehiclePhysClass::Init(def);
- }
- TrackedVehicleClass::~TrackedVehicleClass(void)
- {
- }
- void TrackedVehicleClass::Render(RenderInfoClass & rinfo)
- {
- /*
- ** Compute the track movement
- */
- const Matrix3D & tm = Get_Transform();
- float extent_y = ContactBox->InnerBox.Extent.Y;
- float extent_z = ContactBox->InnerBox.Extent.Z;
- Vector3 left_track_position = tm * Vector3(0,extent_y,-extent_z);
- Vector3 right_track_position = tm * Vector3(0,-extent_y,-extent_z);
- Vector3 forward;
- tm.Get_X_Vector(&forward);
- Vector3 move;
- Vector3::Subtract(left_track_position,LeftTrackLastPosition,&move);
- LeftTrackMovement = Vector3::Dot_Product(move,forward);
- Vector3::Subtract(right_track_position,RightTrackLastPosition,&move);
- RightTrackMovement = Vector3::Dot_Product(move,forward);
- LeftTrackLastPosition = left_track_position;
- RightTrackLastPosition = right_track_position;
-
- /*
- ** Update the mappers
- */
- const TrackedVehicleDefClass * def = Get_TrackedVehicleDef();
- for (int i=0; i<TrackMappers.Count(); i++) {
- float movement = 0.0f;
- if (TrackMappers[i].TrackType == LEFT_TRACK) {
- movement = LeftTrackMovement;
- } else {
- movement = RightTrackMovement;
- }
- TrackMappers[i].Mapper->Set_UV_Offset_Delta(
- Vector2(def->TrackUScaleFactor * movement,def->TrackVScaleFactor * movement) );
- }
- /*
- ** Parent class render
- */
- VehiclePhysClass::Render(rinfo);
- }
- void TrackedVehicleClass::Set_Model(RenderObjClass * model)
- {
- VehiclePhysClass::Set_Model(model);
- Update_Cached_Model_Parameters();
- }
- void TrackedVehicleClass::Update_Cached_Model_Parameters(void)
- {
- /*
- ** Reset our array of mapper pointers
- */
- TrackMappers.Delete_All(false);
-
- /*
- ** Make sure that this model has unique meshes for its tracks
- ** and grab pointers to the mappers.
- */
- if (Model != NULL) {
- Grab_Track_Mappers(Model);
- }
- }
- void TrackedVehicleClass::Grab_Track_Mappers(RenderObjClass * model)
- {
- for (int i=0; i<model->Get_Num_Sub_Objects(); i++) {
- RenderObjClass * sub_obj = model->Get_Sub_Object(i);
- if (sub_obj && (sub_obj->Class_ID() == RenderObjClass::CLASSID_MESH)) {
- const char * name = sub_obj->Get_Name();
- if (_is_left_track_name(name)) {
- Add_Track_Mappers((MeshClass*)sub_obj,LEFT_TRACK);
- }
- if (_is_right_track_name(name)) {
- Add_Track_Mappers((MeshClass*)sub_obj,RIGHT_TRACK);
- }
- }
-
- Grab_Track_Mappers(sub_obj);
- REF_PTR_RELEASE(sub_obj);
- }
- }
- void TrackedVehicleClass::Add_Track_Mappers(MeshClass * mesh,int track_type)
- {
- /*
- ** First check if this model has a linear offset mapper in any of its vertex materials
- */
- bool has_mapper = false;
- MaterialInfoClass * matinfo = mesh->Get_Material_Info();
- if (matinfo != NULL) {
- for (int i=0; i<matinfo->Vertex_Material_Count(); i++) {
- VertexMaterialClass * vmtl = matinfo->Peek_Vertex_Material(i);
- if (vmtl != NULL) {
- TextureMapperClass * mapper = vmtl->Get_Mapper(0);
- if ((mapper != NULL) && (mapper->Mapper_ID() == TextureMapperClass::MAPPER_ID_LINEAR_OFFSET)) {
- has_mapper = true;
- }
- REF_PTR_RELEASE(mapper);
- }
- }
- REF_PTR_RELEASE(matinfo);
- }
- /*
- ** If it does, then make the mesh unique, re-dig out the mapper, and hang onto its pointer
- */
- if (has_mapper) {
- mesh->Make_Unique();
-
- MaterialInfoClass * matinfo = mesh->Get_Material_Info();
- if (matinfo != NULL) {
- for (int i=0; i<matinfo->Vertex_Material_Count(); i++) {
- VertexMaterialClass * vmtl = matinfo->Peek_Vertex_Material(i);
- if (vmtl != NULL) {
- TextureMapperClass * mapper = vmtl->Get_Mapper(0);
- if ((mapper != NULL) && (mapper->Mapper_ID() == TextureMapperClass::MAPPER_ID_LINEAR_OFFSET)) {
- TrackMapperStruct ts;
- ts.Mapper = (LinearOffsetTextureMapperClass*)mapper;
- ts.TrackType = track_type;
- TrackMappers.Add(ts);
- #if 0 //Paranoid debug logging
- WWDEBUG_SAY(("Grabbing Track Mesh! \r\n"));
- WWDEBUG_SAY((" container: 0x%X mesh: 0x%X vmtl: 0x%X mapper 0x%X\r\n",
- (unsigned int)mesh->Get_Container(),
- (unsigned int)mesh,
- (unsigned int)vmtl,
- (unsigned int)mapper));
- WWDEBUG_SAY((" tracked vehicle: 0x%X\r\n",(unsigned int)this));
- WWDEBUG_SAY((" Name = %s\r\n",mesh->Get_Name()));
- #endif
- }
- REF_PTR_RELEASE(mapper);
- }
- }
- REF_PTR_RELEASE(matinfo);
- }
- }
- }
- void TrackedVehicleClass::Compute_Force_And_Torque(Vector3 * force,Vector3 * torque)
- {
- {
- WWPROFILE("TrackedVehicleClass::Compute_Force_And_Torque");
- const TrackedVehicleDefClass * def = Get_TrackedVehicleDef();
- WWASSERT(def != NULL);
- /*
- ** Compute the left and right track torque
- ** Accept either strafe or turn as a turn command
- */
- LeftTrackTorque = RightTrackTorque = 0.0f;
- if (Controller) {
- float forward = Controller->Get_Move_Forward();
- float left = 0.0f;
- if (WWMath::Fabs(Controller->Get_Turn_Left()) > WWMath::Fabs(Controller->Get_Move_Left())) {
- left = Controller->Get_Turn_Left();
- } else {
- left = Controller->Get_Move_Left();
- }
- float turn_scale = 1.0f - WWMath::Fabs(left) * (1.0f - def->TurnTorqueScaleFactor);
- #if 0
- if (forward != 0.0f) {
- turn_scale = 1.0f;
- }
- LeftTrackTorque = WWMath::Clamp((2.12f * forward - left),-1.0f,1.0f);
- RightTrackTorque = WWMath::Clamp((2.12f * forward + left),-1.0f,1.0f);
- LeftTrackTorque *= def->MaxEngineTorque * turn_scale;
- RightTrackTorque *= def->MaxEngineTorque * turn_scale;
- #else
- LeftTrackTorque = (forward - left) * def->MaxEngineTorque * turn_scale;
- RightTrackTorque = (forward + left) * def->MaxEngineTorque * turn_scale;
- #endif
- }
-
- /*
- ** Update each wheel's torque.
- */
- for (int iwheel = 0; iwheel<Wheels.Length(); iwheel++) {
- if (Wheels[iwheel]->Get_Flag(WheelClass::LEFT_TRACK)) {
- ((TrackWheelClass *)Wheels[iwheel])->Set_Axle_Torque(LeftTrackTorque);
- }
- if (Wheels[iwheel]->Get_Flag(WheelClass::RIGHT_TRACK)) {
- ((TrackWheelClass *)Wheels[iwheel])->Set_Axle_Torque(RightTrackTorque);
- }
- }
- }
- /*
- ** Pass on to the base class
- */
- VehiclePhysClass::Compute_Force_And_Torque(force,torque);
- }
- SuspensionElementClass * TrackedVehicleClass::Alloc_Suspension_Element(void)
- {
- return new TrackWheelClass;
- }
- /*
- ** Save-Load System
- */
- const PersistFactoryClass & TrackedVehicleClass::Get_Factory (void) const
- {
- return _TrackedVehicleFactory;
- }
- bool TrackedVehicleClass::Save (ChunkSaveClass &csave)
- {
- csave.Begin_Chunk(TRACKEDVEHICLE_CHUNK_VEHICLEPHYS);
- VehiclePhysClass::Save(csave);
- csave.End_Chunk();
- return true;
- }
- bool TrackedVehicleClass::Load (ChunkLoadClass &cload)
- {
- while (cload.Open_Chunk()) {
-
- switch(cload.Cur_Chunk_ID())
- {
- case TRACKEDVEHICLE_CHUNK_VEHICLEPHYS:
- VehiclePhysClass::Load(cload);
- break;
- default:
- WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
- break;
- }
- cload.Close_Chunk();
- }
- SaveLoadSystemClass::Register_Post_Load_Callback(this);
- return true;
- }
- void TrackedVehicleClass::On_Post_Load (void)
- {
- VehiclePhysClass::On_Post_Load();
- }
- /***********************************************************************************************
- **
- ** TrackedVehicleDefClass Implementation
- **
- ***********************************************************************************************/
- SimplePersistFactoryClass<TrackedVehicleDefClass,PHYSICS_CHUNKID_TRACKEDVEHICLEDEF> _TrackedVehicleDefFactory;
- DECLARE_DEFINITION_FACTORY(TrackedVehicleDefClass, CLASSID_TRACKEDVEHICLEDEF, "TrackedVehicle") _TrackedVehicleDefDefFactory;
- /*
- ** Chunk ID's used by TrackedVehicleDefClass
- */
- enum
- {
- TRACKEDVEHICLEDEF_CHUNK_VEHICLEPHYSDEF = 0406001454, // (parent class)
- TRACKEDVEHICLEDEF_CHUNK_VARIABLES,
- TRACKEDVEHICLEDEF_VARIABLE_MAXENGINETORQUE = 0x00,
- TRACKEDVEHICLEDEF_VARIABLE_TRACKUSCALEFACTOR,
- TRACKEDVEHICLEDEF_VARIABLE_TRACKVSCALEFACTOR,
- TRACKEDVEHICLEDEF_VARIABLE_TURNTORQUESCALEFACTOR,
-
- };
- TrackedVehicleDefClass::TrackedVehicleDefClass(void) :
- MaxEngineTorque(0.0f),
- TrackUScaleFactor(25.0f),
- TrackVScaleFactor(0.0f),
- TurnTorqueScaleFactor(1.0f)
- {
- // make our parameters editable
- FLOAT_EDITABLE_PARAM(TrackedVehicleDefClass, MaxEngineTorque, 0.0f, 100000.0f);
- FLOAT_EDITABLE_PARAM(TrackedVehicleDefClass, TrackUScaleFactor, -1000.0f, 1000.0f);
- FLOAT_EDITABLE_PARAM(TrackedVehicleDefClass, TrackVScaleFactor, -1000.0f, 1000.0f);
- FLOAT_EDITABLE_PARAM(TrackedVehicleDefClass, TurnTorqueScaleFactor, 0.0f, 1.0f);
- }
- uint32 TrackedVehicleDefClass::Get_Class_ID (void) const
- {
- return CLASSID_TRACKEDVEHICLEDEF;
- }
- const PersistFactoryClass & TrackedVehicleDefClass::Get_Factory (void) const
- {
- return _TrackedVehicleDefFactory;
- }
- PersistClass * TrackedVehicleDefClass::Create(void) const
- {
- TrackedVehicleClass * obj = NEW_REF(TrackedVehicleClass,());
- obj->Init(*this);
- return obj;
- }
- bool TrackedVehicleDefClass::Save(ChunkSaveClass &csave)
- {
- csave.Begin_Chunk(TRACKEDVEHICLEDEF_CHUNK_VEHICLEPHYSDEF);
- VehiclePhysDefClass::Save(csave);
- csave.End_Chunk();
- csave.Begin_Chunk(TRACKEDVEHICLEDEF_CHUNK_VARIABLES);
- WRITE_MICRO_CHUNK(csave,TRACKEDVEHICLEDEF_VARIABLE_MAXENGINETORQUE,MaxEngineTorque);
- WRITE_MICRO_CHUNK(csave,TRACKEDVEHICLEDEF_VARIABLE_TRACKUSCALEFACTOR,TrackUScaleFactor);
- WRITE_MICRO_CHUNK(csave,TRACKEDVEHICLEDEF_VARIABLE_TRACKVSCALEFACTOR,TrackVScaleFactor);
- WRITE_MICRO_CHUNK(csave,TRACKEDVEHICLEDEF_VARIABLE_TURNTORQUESCALEFACTOR,TurnTorqueScaleFactor);
- csave.End_Chunk();
- return true;
- }
- bool TrackedVehicleDefClass::Load(ChunkLoadClass &cload)
- {
- while (cload.Open_Chunk()) {
- switch(cload.Cur_Chunk_ID()) {
- case TRACKEDVEHICLEDEF_CHUNK_VEHICLEPHYSDEF:
- VehiclePhysDefClass::Load(cload);
- break;
- case TRACKEDVEHICLEDEF_CHUNK_VARIABLES:
- while (cload.Open_Micro_Chunk()) {
- switch(cload.Cur_Micro_Chunk_ID()) {
- READ_MICRO_CHUNK(cload,TRACKEDVEHICLEDEF_VARIABLE_MAXENGINETORQUE,MaxEngineTorque);
- READ_MICRO_CHUNK(cload,TRACKEDVEHICLEDEF_VARIABLE_TRACKUSCALEFACTOR,TrackUScaleFactor);
- READ_MICRO_CHUNK(cload,TRACKEDVEHICLEDEF_VARIABLE_TRACKVSCALEFACTOR,TrackVScaleFactor);
- READ_MICRO_CHUNK(cload,TRACKEDVEHICLEDEF_VARIABLE_TURNTORQUESCALEFACTOR,TurnTorqueScaleFactor);
- }
- cload.Close_Micro_Chunk();
- }
- break;
- default:
- WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
- break;
- }
- cload.Close_Chunk();
- }
- return true;
- }
- bool TrackedVehicleDefClass::Is_Type(const char * type_name)
- {
- if (stricmp(type_name,TrackedVehicleDefClass::Get_Type_Name()) == 0) {
- return true;
- } else {
- return VehiclePhysDefClass::Is_Type(type_name);
- }
- }
|