/* ** 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/dynamicphys.cpp $* * * * Original Author:: Greg Hjelstrom * * * * $Author:: Greg_h $* * * * $Modtime:: 3/29/02 2:49p $* * * * $Revision:: 17 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "dynamicphys.h" #include "chunkio.h" #include "pscene.h" #include "wwprofile.h" #include "physcoltest.h" #if (UMBRASUPPORT) #include #endif #include "umbrasupport.h" /*********************************************************************************************** ** ** DynamicPhysClass Implementation ** Note that this is not a concrete class. It therefore does not have factories defined... ** ***********************************************************************************************/ const int MIN_VIS_UPDATE_TICK_DELAY = 250; // min number of milliseconds between dynamic vis id updates bool DynamicPhysClass::_DisableDynamicPhysSimulation = false; bool DynamicPhysClass::_DisableDynamicPhysRendering = false; /* ** Chunk ID's used by DynamicPhysClass */ enum { DYNAMICPHYS_CHUNK_PHYS = 813001100, }; DynamicPhysClass::DynamicPhysClass(void) : DirtyVisObjectID(true), VisNodeID(0), VisStatusLastUpdated(0) { } DynamicPhysClass::~DynamicPhysClass(void) { } void DynamicPhysClass::Init(const DynamicPhysDefClass & definition) { PhysClass::Init(definition); } void DynamicPhysClass::Set_Model(RenderObjClass * model) { PhysClass::Set_Model(model); #if (UMBRASUPPORT) if (model != NULL) { /* ** Create a new test-model for the bounding box of this object */ AABoxClass obj_box; model->Get_Obj_Space_Bounding_Box(obj_box); /* ** Insert it into our Umbra object */ WWASSERT(UmbraObject); UmbraObject->setTestModel(UmbraSupport::Create_Box_Model(obj_box)); UmbraObject->setCost(100000,100000,5); } #endif } void DynamicPhysClass::Update_Visibility_Status(void) { /* ** Invalidate our cached vis object ID */ DirtyVisObjectID = true; /* ** Invalidate the lighting cache. Next time this object is rendered the cache will be updated. */ Invalidate_Static_Lighting_Cache(); } int DynamicPhysClass::Get_Vis_Object_ID(void) { if (DirtyVisObjectID) { Internal_Update_Visibility_Status(); } return VisObjectID; } void DynamicPhysClass::Internal_Update_Visibility_Status(void) { /* ** Don't update our VIS-ID more often than 4 times per second */ unsigned current_time=WW3D::Get_Sync_Time(); unsigned delta = current_time - VisStatusLastUpdated; if (delta < MIN_VIS_UPDATE_TICK_DELAY) return; VisStatusLastUpdated=current_time; /* ** Update our VIS-ID */ VisObjectID = PhysicsSceneClass::Get_Instance()->Get_Dynamic_Object_Vis_ID(Model->Get_Bounding_Box(),&VisNodeID); if ((int)VisObjectID >= PhysicsSceneClass::Get_Instance()->Get_Vis_Table_Size()) { int size = PhysicsSceneClass::Get_Instance()->Get_Vis_Table_Size(); // int id = PhysicsSceneClass::Get_Instance()->Get_Dynamic_Object_Vis_ID(Model->Get_Bounding_Box(),&VisNodeID); WWDEBUG_SAY(("Invalid VisObjectID: %d for object: %s (max vis id = %d)\n",VisObjectID,Model->Get_Name(),size)); VisObjectID = 0; } /* ** Clear the dirty bit */ DirtyVisObjectID = false; /* ** Update our Umbra Object */ #if (UMBRASUPPORT) UmbraSupport::Update_Umbra_Object(this); #endif } bool DynamicPhysClass::Save(ChunkSaveClass &csave) { csave.Begin_Chunk(DYNAMICPHYS_CHUNK_PHYS); PhysClass::Save(csave); csave.End_Chunk(); return true; } bool DynamicPhysClass::Load(ChunkLoadClass &cload) { while (cload.Open_Chunk()) { switch(cload.Cur_Chunk_ID()) { case DYNAMICPHYS_CHUNK_PHYS: PhysClass::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 DynamicPhysClass::On_Post_Load(void) { PhysClass::On_Post_Load(); // update cached vis object id, vis node id, and sunlight status... Update_Cull_Box(); Update_Visibility_Status(); } /*********************************************************************************************** ** ** DynamicPhysDefClass Implementation ** This holds the description for a DynamicPhysClass. Again, this class isn't concrete ** so it doesn't have factories... ** ***********************************************************************************************/ enum { DYNAMICPHYSDEF_CHUNK_PHYSDEF = 813001104, // parent class data. }; DynamicPhysDefClass::DynamicPhysDefClass(void) { } bool DynamicPhysDefClass::Is_Valid_Config(StringClass &message) { return PhysDefClass::Is_Valid_Config(message); } bool DynamicPhysDefClass::Is_Type(const char * type_name) { if (stricmp(type_name,DynamicPhysDefClass::Get_Type_Name()) == 0) { return true; } else { return PhysDefClass::Is_Type(type_name); } } bool DynamicPhysDefClass::Save(ChunkSaveClass &csave) { csave.Begin_Chunk(DYNAMICPHYSDEF_CHUNK_PHYSDEF); PhysDefClass::Save(csave); csave.End_Chunk(); return true; } bool DynamicPhysDefClass::Load(ChunkLoadClass &cload) { while (cload.Open_Chunk()) { switch(cload.Cur_Chunk_ID()) { case DYNAMICPHYSDEF_CHUNK_PHYSDEF: PhysDefClass::Load(cload); break; } cload.Close_Chunk(); } return true; }