/* ** 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/pscene.cpp $* * * * Author:: Greg Hjelstrom * * * * $Modtime:: 3/28/02 6:48p $* * * * $Revision:: 218 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * PhysicsSceneClass::PhysicsSceneClass -- Constructor * * PhysicsSceneClass::~PhysicsSceneClass -- Destructor * * PhysicsSceneClass::Update -- Simulates the entire scene forward one timestep * * PhysicsSceneClass::Add_Dynamic_Object -- Adds a dynamic object to the scene * * PhysicsSceneClass::Internal_Add_Dynamic_Object -- internal function finishes adding a dyn * * PhysicsSceneClass::Add_Static_Object -- Adds a static object to the scene * * PhysicsSceneClass::Internal_Add_Static_Object -- internal add static object... * * PhysicsSceneClass::Add_Static_Light -- Adds a static light to the system * * PhysicsSceneClass::Internal_Add_Static_Light -- internal add static light... * * PhysicsSceneClass::Delayed_Remove_Object -- registers an object for removal * * PhysicsSceneClass::Process_Release_List -- Removes all objects in the ReleaseList * * PhysicsSceneClass::Remove_Object -- Remove an object from the scene * * PhysicsSceneClass::Remove_All -- Removes all objects from the scene * * PhysicsSceneClass::Contains -- Tests if the scene contains the given object * * PhysicsSceneClass::Get_Dynamic_Object_Iterator -- returns an iterator for the dynamic obj * * PhysicsSceneClass::Get_Static_Object_Iterator -- return an iterator for the static objs * * PhysicsSceneClass::Get_Static_Anim_Object_Iterator -- returns an iterator for static anim * * PhysicsSceneClass::Get_Static_Light_Iterator -- returns an iterator for static lights * * PhysicsSceneClass::Get_Static_Projector_Iterator -- returns an iterator for static projec * * PhysicsSceneClass::Get_Dynamic_Projector_Iterator -- returns an iterator for dynamic proj * * PhysicsSceneClass::Add_To_Dirty_Cull_List -- adds something to the "dirty cull" list * * PhysicsSceneClass::Remove_From_Dirty_Cull_List -- removes an object from the dirty cull l * * PhysicsSceneClass::Is_In_Dirty_Cull_List -- tests whether an object is in the dirty cull * * PhysicsSceneClass::Add_Render_Object -- Adds a render object to the scene * * PhysicsSceneClass::Remove_Render_Object -- removes a render object from the scene * * PhysicsSceneClass::Register -- rengisters given render object * * PhysicsSceneClass::Unregister -- Unregisters the given render object * * PhysicsSceneClass::Set_Vis_Sample_Point -- Set the current vis sample point * * PhysicsSceneClass::Pre_Render_Processing -- processing which occurs prior to rendering * * PhysicsSceneClass::Post_Render_Processing -- processing that occurs after rendering * * PhysicsSceneClass::Optimize_LODs -- Set the LOD level for each object * * PhysicsSceneClass::Render -- Render the scene * * PhysicsSceneClass::Render_Objects -- Render the visible objects * * PhysicsSceneClass::Render_Object -- Render an individual object * * PhysicsSceneClass::Render_Backface_Occluders -- Render backfaces of all occluders * * PhysicsSceneClass::Re_Partition_Static_Objects -- partition the static objects * * PhysicsSceneClass::Re_Partition_Static_Lights -- partition the static lights * * PhysicsSceneClass::Re_Partition_Dynamic_Culling_System -- partition the dynamic culling s * * PhysicsSceneClass::Re_Partition_Static_Projectors -- partition the static projectors * * PhysicsSceneClass::Update_Culling_System_Bounding_Boxes -- updates the cull systems * * PhysicsSceneClass::Get_Level_Extents -- returns the bounds of the level * * PhysicsSceneClass::Set_Polygon_Budgets -- set the budgets for the LOD system * * PhysicsSceneClass::Get_Polygon_Budgets -- returns the budgets for the LOD system * * PhysicsSceneClass::Per_Frame_Statistics_Update -- statistics tracking * * PhysicsSceneClass::Get_Statistics -- returns statistics * * PhysicsSceneClass::Find_Static_Object -- Find static object with the given ID * * PhysicsSceneClass::Shatter_Mesh -- Clips a mesh into pieces and scatters them * * PhysicsSceneClass::Verify_Culling_Systems -- Verify the culling systems * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "pscene.h" #include "rinfo.h" #include "light.h" #include "wwdebug.h" #include "wwhack.h" #include "wwprofile.h" #include "wwmemlog.h" #include "physgridcull.h" #include "staticaabtreecull.h" #include "dynamicaabtreecull.h" #include "lightcull.h" #include "camera.h" #include "wwphystrig.h" #include "vertmaterial.h" #include "predlod.h" #include "widgets.h" #include "renderobjphys.h" #include "pathfind.h" #include "lightexclude.h" #include "physdecalsys.h" #include "quat.h" #include "shader.h" #include "lookuptable.h" #include "shattersystem.h" #include "projectile.h" #include "staticphys.h" #include "vistable.h" #include "meshmdl.h" #include "camerashakesystem.h" #include "lightenvironment.h" #include "dx8wrapper.h" #include "physresourcemgr.h" #include "phys3.h" #include "umbrasupport.h" #define STATISTICS_FRAMES 20 // number of frames to average statistics across #define SHATTER_DEBUG 0 // debugging, freeze shattered particles in place for 60sec /* ** Static members of PhysicsSceneClass */ bool PhysicsSceneClass::AllowCollisionFlags[NUM_COLLISION_FLAGS]; PhysicsSceneClass * PhysicsSceneClass::TheScene = NULL; /* ** Constants */ const float MAX_TIMESTEP = 1.0f / 15.0f; const Vector3 MIN_GRID_CELL_SIZE(15.0f,15.0f,15.0f); const int MAX_GRID_CELL_COUNT = 8192; const float MAX_DYNAMIC_OBJ_RADIUS = 5.0f; const int DEFAULT_DYNAMIC_LOD_BUDGET = 4000; const int DEFAULT_STATIC_LOD_BUDGET = 4000; /****************************************************************************************** ** ** ** PhysicsSceneClass Implementation ** ** ******************************************************************************************/ /*********************************************************************************************** * PhysicsSceneClass::PhysicsSceneClass -- Constructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ PhysicsSceneClass::PhysicsSceneClass(void) : FrameNum(0), LastCameraPosition(0,0,0), LastValidVisId(-1), DebugDisplayEnabled(false), ProjectorDebugDisplayEnabled(false), DirtyCullDebugDisplayEnabled(false), LightingDebugDisplayEnabled(false), StaticCullingSystem(NULL), DynamicCullingSystem(NULL), StaticLightingSystem(NULL), StaticProjectorCullingSystem(NULL), DynamicProjectorCullingSystem(NULL), DynamicPolyBudget(DEFAULT_DYNAMIC_LOD_BUDGET), StaticPolyBudget(DEFAULT_STATIC_LOD_BUDGET), LightingMode(LIGHTING_MODE_CHEAP), SceneAmbientLight(0.5f,0.5f,0.5f), UseSun(false), SunLight(NULL), VisEnabled(true), VisInverted(false), VisQuickAndDirty(false), VisResetNeeded(false), VisSectorDisplayEnabled(false), VisSectorHistoryEnabled(false), VisGridDisplayMode(VIS_GRID_DISPLAY_NONE), VisSectorMissing(false), VisSectorFallbackEnabled(true), BackfaceDebugEnabled(false), VisSamplePointLocked(false), LockedVisSamplePoint(0,0,0), VisCamera(NULL), CurrentVisTable(NULL), StaticProjectorsEnabled(false), DynamicProjectorsEnabled(false), ShadowMode(SHADOW_MODE_NONE), ShadowAttenStart(25.0f), ShadowAttenEnd(40.0f), ShadowNormalIntensity(0.45f), ShadowBlobTexture(NULL), ShadowCamera(NULL), ShadowRenderContext(NULL), ShadowMaterialPass(NULL), ShadowResWidth(128), ShadowResHeight(128), DecalSystem(NULL), Pathfinder(NULL), CameraShakeSystem(NULL), HighlightMaterialPass(NULL), UpdateOnlyVisibleObjects(false), CurrentFrameNumber(0) { WWASSERT_PRINT(TheScene == NULL,"Only one instance of the PhysicsSceneClass is allowed.\r\n"); WWMEMLOG(MEM_PHYSICSDATA); TheScene = this; /* ** Initialize Umbra */ #if (UMBRASUPPORT) UmbraSupport::Init(); #endif /* ** Clear the collision flags */ memset(AllowCollisionFlags,0,NUM_COLLISION_FLAGS); /* ** Allocate culling systems */ StaticCullingSystem = new StaticAABTreeCullClass(this); DynamicCullingSystem = new PhysGridCullClass(this); DynamicObjVisSystem = new DynamicAABTreeCullClass(this); StaticLightingSystem = new StaticLightCullClass; StaticProjectorCullingSystem = new TypedAABTreeCullSystemClass; DynamicProjectorCullingSystem = new TypedGridCullSystemClass; /* ** Allocate pathfind object */ Pathfinder = new PathfindClass; /* ** Allocate the camera shake system */ CameraShakeSystem = new CameraShakeSystemClass; /* ** Allocate the sun light */ SunLight = NEW_REF(LightClass,(LightClass::DIRECTIONAL)); Reset_Sun_Light(); /* ** Initialize the debug code */ WidgetSystem::Init_Debug_Widgets(); /* ** Allocate decal resources */ Allocate_Decal_Resources(); } /*********************************************************************************************** * PhysicsSceneClass::~PhysicsSceneClass -- Destructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ PhysicsSceneClass::~PhysicsSceneClass(void) { Remove_All(); delete StaticCullingSystem; delete DynamicCullingSystem; delete DynamicObjVisSystem; delete StaticLightingSystem; delete StaticProjectorCullingSystem; delete DynamicProjectorCullingSystem; delete Pathfinder; delete CameraShakeSystem; REF_PTR_RELEASE(SunLight); Release_Vis_Resources(); Release_Projector_Resources(); Release_Decal_Resources(); WidgetSystem::Release_Debug_Widgets(); WWASSERT(TheScene == this); TheScene = NULL; /* ** Shutdown UMBRA */ #if (UMBRASUPPORT) UmbraSupport::Shutdown(); #endif } /*********************************************************************************************** * PhysicsSceneClass::Update -- Simulates the entire scene forward one timestep * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Update(float dt,int frameid) { WWPROFILE("PhysicsScene::Update"); Generate_Static_Shadow_Projectors(); FrameNum = frameid; if (dt == 0.0f) { return; } /* ** Timestep all of the physics objects */ { WWPROFILE("Timestep"); float remaining = dt; while (remaining > 0) { float step = min(remaining,MAX_TIMESTEP); /* ** Loop through each object telling each to time-step itself. */ RefPhysListIterator it(&TimestepList); for (it.First(); !it.Is_Done(); it.Next()) { PhysClass* phys_obj=it.Peek_Obj(); // Little optimization hack - only update vehicles that are visible (for now update all other physics // objects regardless of the visibility to avoid problems, vehicles are the most expensive anyway). // This same thing is done to Post Timestep couple lines lower. if (phys_obj->Is_Object_Simulating()) { if (!UpdateOnlyVisibleObjects || phys_obj->Get_Last_Visible_Frame()==CurrentFrameNumber || !phys_obj->As_VehiclePhysClass()) { phys_obj->Timestep(step); } } } remaining -= step; } } { WWPROFILE("Post Timestep"); RefPhysListIterator it(&TimestepList); for (it.First(); !it.Is_Done(); it.Next()) { // if (it.Peek_Obj()->Is_Object_Simulating()) { // if (!UpdateOnlyVisibleObjects || it.Peek_Obj()->Get_Last_Visible_Frame()==CurrentFrameNumber) { PhysClass* phys_obj=it.Peek_Obj(); if (phys_obj->Is_Object_Simulating()) { if (!UpdateOnlyVisibleObjects || phys_obj->Get_Last_Visible_Frame()==CurrentFrameNumber || !phys_obj->As_VehiclePhysClass()) { phys_obj->Post_Timestep_Process(); } } } } /* ** Timestep the camera shakers */ { WWPROFILE("CameraShakeSystem"); CameraShakeSystem->Timestep(dt); } /* ** Timestep the material effects */ { WWPROFILE("MaterialEffects"); MaterialEffectClass::Timestep_All_Effects(dt); } /* ** Process pending release requests ** Put here prior to rendering to insure items won't draw too many times. */ Process_Release_List(); CurrentFrameNumber++; } /*********************************************************************************************** * PhysicsSceneClass::Add_Dynamic_Object -- Adds a dynamic object to the scene * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Add_Dynamic_Object(PhysClass * newobj) { WWASSERT(newobj != NULL); WWASSERT(newobj->Peek_Model() != NULL); WWASSERT(newobj->Get_Culling_System() == NULL); // Add the object to the dynamic culling system DynamicCullingSystem->Add_Object(newobj); // Add the object to the lists in the physics scene Internal_Add_Dynamic_Object(newobj); // Clean up any cached visibility data that may have been in the object DynamicPhysClass * dynobj = newobj->As_DynamicPhysClass(); WWASSERT(dynobj != NULL); if (dynobj != NULL) { dynobj->Update_Visibility_Status(); } } /*********************************************************************************************** * PhysicsSceneClass::Internal_Add_Dynamic_Object -- internal function finishes adding a dynam * * * * This function is called both by the loading code and the Add_Dynamic_Object function. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Internal_Add_Dynamic_Object(PhysClass * newobj) { // Add the object to the appropriate lists ObjList.Add(newobj); SceneClass::Add_Render_Object(newobj->Peek_Model()); if (newobj->Needs_Timestep()) { TimestepList.Add(newobj); } } /*********************************************************************************************** * PhysicsSceneClass::Add_Static_Object -- Adds a static object to the scene * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Add_Static_Object(StaticPhysClass * newtile,int cull_node_id/*=-1*/) { WWASSERT(newtile != NULL); WWASSERT(newtile->Peek_Model() != NULL); WWASSERT(newtile->Get_Culling_System() == NULL); // Add the object to the static culling system StaticCullingSystem->Add_Object(newtile,cull_node_id); // Add the object to the lists in the physics scene Internal_Add_Static_Object(newtile); } /*********************************************************************************************** * PhysicsSceneClass::Internal_Add_Static_Object -- internal add static object... * * * * This function is called by both the loading code and the Add_Static_Object function * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Internal_Add_Static_Object(StaticPhysClass * newtile) { // Add the object to the appropriate lists StaticObjList.Add(newtile); SceneClass::Add_Render_Object(newtile->Peek_Model()); if (newtile->Needs_Timestep()) { TimestepList.Add(newtile); } if (newtile->As_StaticAnimPhysClass() != NULL) { StaticAnimList.Add(newtile); } } /*********************************************************************************************** * PhysicsSceneClass::Add_Static_Light -- Adds a static light to the system * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Add_Static_Light(LightPhysClass * newlight,int cull_node_id/*=-1*/) { WWASSERT(newlight != NULL); WWASSERT(newlight->Peek_Model() != NULL); WWASSERT(newlight->Get_Culling_System() == NULL); // Add the light to the static light culling system StaticLightingSystem->Add_Object(newlight); // Add the light to all of the appropriate lists Internal_Add_Static_Light(newlight); } /*********************************************************************************************** * PhysicsSceneClass::Internal_Add_Static_Light -- internal add static light... * * * * This function is called by both the loading code and the Add_Static_Light function * * * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Internal_Add_Static_Light(LightPhysClass * newlight) { // Add the object to the appropriate lists StaticLightList.Add(newlight); //(gth) hack, I don't want static lights to get registered as vertex processors. //so don't let the scene class know about them ;-) I should probably come up with //a better mechanism for this... //SceneClass::Add_Render_Object(newlight->Peek_Model()); if (newlight->Needs_Timestep()) { TimestepList.Add(newlight); } } /*********************************************************************************************** * PhysicsSceneClass::Delayed_Remove_Object -- registers an object for removal * * * * The object will be released by the scene at the end of the next frame. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Delayed_Remove_Object(PhysClass * obj) { if (!ReleaseList.Contains(obj)) { ReleaseList.Add(obj); } } /*********************************************************************************************** * PhysicsSceneClass::Process_Release_List -- Removes all objects in the ReleaseList * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Process_Release_List(void) { while(!ReleaseList.Is_Empty()) { PhysClass * obj = ReleaseList.Remove_Head(); Remove_Object(obj); obj->Release_Ref(); } } /*********************************************************************************************** * PhysicsSceneClass::Remove_Object -- Remove an object from the scene * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Remove_Object(PhysClass * obj) { // NOTE: sometimes the game tries to 'remove' objects that havent been added... if (!Contains(obj)) return; // Assert that the object is valid WWASSERT(obj != NULL); WWASSERT(obj->Peek_Model() != NULL); // Notify the model that it is being removed from the scene SceneClass::Remove_Render_Object(obj->Peek_Model()); // Notify the observer (if it has one) if (obj->Get_Observer() != NULL) { obj->Get_Observer()->Object_Removed_From_Scene(obj); } // Pull the object out of any of the "extra-processing" lists Remove_From_Dirty_Cull_List(obj); TimestepList.Remove(obj); StaticAnimList.Remove(obj); // Pull the physics object out of whatever system it is in CullSystemClass * cullsys = obj->Get_Culling_System(); if (cullsys == DynamicCullingSystem) { DynamicCullingSystem->Remove_Object(obj); ObjList.Remove(obj); } else if (cullsys == StaticCullingSystem) { WWASSERT(obj->As_StaticPhysClass() != NULL); StaticCullingSystem->Remove_Object(obj->As_StaticPhysClass()); StaticObjList.Remove(obj); } else if (cullsys == StaticLightingSystem) { WWASSERT(obj->As_LightPhysClass() != NULL); StaticLightingSystem->Remove_Object(obj->As_LightPhysClass()); StaticLightList.Remove(obj); } else { WWASSERT(0); // should never happen! } } /*********************************************************************************************** * PhysicsSceneClass::Remove_All -- Removes all objects from the scene * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Remove_All(void) { PhysClass * obj = ObjList.Peek_Head(); while (obj) { Remove_Object(obj); obj = ObjList.Peek_Head(); } StaticPhysClass * tile = (StaticPhysClass *)StaticObjList.Peek_Head(); while (tile) { Remove_Object(tile); tile = (StaticPhysClass *)StaticObjList.Peek_Head(); } LightPhysClass * light = (LightPhysClass *)StaticLightList.Peek_Head(); while(light) { Remove_Object(light); light = (LightPhysClass *)StaticLightList.Peek_Head(); } TexProjectClass * static_proj = StaticProjectorList.Peek_Head(); while(static_proj) { Remove_Static_Texture_Projector(static_proj); static_proj = StaticProjectorList.Peek_Head(); } TexProjectClass * dynamic_proj = DynamicProjectorList.Peek_Head(); while(dynamic_proj) { Remove_Dynamic_Texture_Projector(dynamic_proj); dynamic_proj = DynamicProjectorList.Peek_Head(); } Pathfinder->Reset_Sectors (); } /*********************************************************************************************** * PhysicsSceneClass::Contains -- Tests if the scene contains the given object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ bool PhysicsSceneClass::Contains(PhysClass * obj) { if (ObjList.Is_In_List(obj)) return true; if (StaticObjList.Is_In_List(obj)) return true; if (StaticLightList.Is_In_List(obj)) return true; return false; } /*********************************************************************************************** * PhysicsSceneClass::Get_Dynamic_Object_Iterator -- returns an iterator for the dynamic objec * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/29/2000 gth : Created. * *=============================================================================================*/ RefPhysListIterator PhysicsSceneClass::Get_Dynamic_Object_Iterator(void) { return RefPhysListIterator(&ObjList); } /*********************************************************************************************** * PhysicsSceneClass::Get_Static_Object_Iterator -- return an iterator for the static objs * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/29/2000 gth : Created. * *=============================================================================================*/ RefPhysListIterator PhysicsSceneClass::Get_Static_Object_Iterator(void) { return RefPhysListIterator(&StaticObjList); } /*********************************************************************************************** * PhysicsSceneClass::Get_Static_Anim_Object_Iterator -- returns an iterator for static anim o * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/29/2000 gth : Created. * *=============================================================================================*/ RefPhysListIterator PhysicsSceneClass::Get_Static_Anim_Object_Iterator(void) { return RefPhysListIterator(&StaticAnimList); } /*********************************************************************************************** * PhysicsSceneClass::Get_Static_Light_Iterator -- returns an iterator for static lights * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/29/2000 gth : Created. * *=============================================================================================*/ RefPhysListIterator PhysicsSceneClass::Get_Static_Light_Iterator(void) { return RefPhysListIterator(&StaticLightList); } /*********************************************************************************************** * PhysicsSceneClass::Get_Static_Projector_Iterator -- returns an iterator for static projecto * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/29/2000 gth : Created. * *=============================================================================================*/ TexProjListIterator PhysicsSceneClass::Get_Static_Projector_Iterator(void) { return TexProjListIterator(&StaticProjectorList); } /*********************************************************************************************** * PhysicsSceneClass::Get_Dynamic_Projector_Iterator -- returns an iterator for dynamic projec * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/29/2000 gth : Created. * *=============================================================================================*/ TexProjListIterator PhysicsSceneClass::Get_Dynamic_Projector_Iterator(void) { return TexProjListIterator(&DynamicProjectorList); } /*********************************************************************************************** * PhysicsSceneClass::Add_To_Dirty_Cull_List -- adds something to the "dirty cull" list * * * * objects in the dirty cull list have their visiblity and cull box re-computed each * * frame. We should try to keep things like this to a minimum. Particle buffers are * * an example of something that would end up in the "dirty cull" list * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/29/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Add_To_Dirty_Cull_List(PhysClass *obj) { DirtyCullList.Add (obj); } /*********************************************************************************************** * PhysicsSceneClass::Remove_From_Dirty_Cull_List -- removes an object from the dirty cull lis * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/29/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Remove_From_Dirty_Cull_List(PhysClass *obj) { DirtyCullList.Remove (obj); } /*********************************************************************************************** * PhysicsSceneClass::Is_In_Dirty_Cull_List -- tests whether an object is in the dirty cull li * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/29/2000 gth : Created. * *=============================================================================================*/ bool PhysicsSceneClass::Is_In_Dirty_Cull_List(PhysClass *obj) { return DirtyCullList.Contains (obj); } /*********************************************************************************************** * PhysicsSceneClass::Add_Render_Object -- Adds a render object to the scene * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * This interface is less efficient than wrapping your render objects in some kind of physics * * object. * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Add_Render_Object(RenderObjClass * obj) { WWMEMLOG(MEM_PHYSICSDATA); // Right category? // NOTE: The *ONLY* way this code should get activated is when the user // or some deep dark w3d code is directly adding and removing render objects // in the physics scene. In this case, I wrap the render objects with // RenderObjPhysClass's and set the UserData pointer to point back to this // wrapper. WWASSERT(obj != NULL); RenderObjPhysClass * cullnode = NEW_REF(RenderObjPhysClass,()); cullnode->Set_Model(obj); Add_Dynamic_Object(cullnode); Add_To_Dirty_Cull_List(cullnode); // // Make sure we don't save particle buffers or lines // if ((obj->Class_ID () == RenderObjClass::CLASSID_PARTICLEBUFFER) || (obj->Class_ID () == RenderObjClass::CLASSID_SEGLINE)) { cullnode->Enable_Dont_Save(true); } cullnode->Release_Ref(); SceneClass::Add_Render_Object(obj); } /*********************************************************************************************** * PhysicsSceneClass::Remove_Render_Object -- removes a render object from the scene * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Remove_Render_Object(RenderObjClass * obj) { // NOTE: The *ONLY* way this code should get activated is when the user // or some deep dark w3d code is directly adding and removing render objects // in the physics scene. In this case, I wrap the render objects with // RenderObjPhysClass's and set the UserData pointer to point back to this // wrapper. SceneClass::Remove_Render_Object(obj); WWASSERT(obj != NULL); PhysClass * cullnode = (PhysClass *)obj->Get_User_Data(); WWASSERT(cullnode != NULL); WWASSERT(cullnode->As_RenderObjPhysClass() != NULL); Remove_Object(cullnode); } /*********************************************************************************************** * PhysicsSceneClass::Register -- rengisters given render object * * * * Render objects can be registered for On_Frame_Update calls, added to the vertex * * processor list, or added to the release list. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Register(RenderObjClass * obj,RegType for_what) { WWASSERT(obj != NULL); switch (for_what) { case ON_FRAME_UPDATE: UpdateList.Add(obj); break; case LIGHT: VertexProcList.Add(obj); break; case RELEASE: { if (obj->Get_Container() != NULL) { obj->Get_Container()->Remove_Sub_Object(obj); } else { PhysClass * wrapper = (PhysClass *)obj->Get_User_Data(); /* ** If there is no wrapper, the object isn't actually in the scene so do nothing */ if (wrapper != NULL) { Delayed_Remove_Object(wrapper); } } } break; } } /*********************************************************************************************** * PhysicsSceneClass::Unregister -- Unregisters the given render object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Unregister(RenderObjClass * obj,RegType for_what) { WWASSERT(obj != NULL); switch (for_what) { case ON_FRAME_UPDATE: UpdateList.Remove(obj); break; case LIGHT: VertexProcList.Remove(obj); break; case RELEASE: WWASSERT_PRINT(0,("Error! Object %s tried to un-register from the release list\r\n",obj->Get_Name())); break; } } /*********************************************************************************************** * PhysicsSceneClass::Pre_Render_Processing -- processing which occurs prior to rendering * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Pre_Render_Processing(CameraClass & camera) { WWPROFILE("Pre_Render_Processing"); LastCameraPosition = camera.Get_Position(); DecalSystem->Update_Decal_Fade_Distances(camera); // Do the needed 'On_Frame_Update's RefRenderObjListIterator rit(&UpdateList); for (rit.First(); !rit.Is_Done(); rit.Next()) { rit.Peek_Obj()->On_Frame_Update(); } // Update culling info for all of the objects in the "dirty cull" list (these are // objects which were added to the scene as pure render objects so I don't assume // that the I have control over when their transform or bounding box is changed...) RefPhysListIterator it(&DirtyCullList); for (it.First(); !it.Is_Done(); it.Next()) { PhysClass * obj = it.Peek_Obj(); obj->Update_Cull_Box(); if (obj->As_DynamicPhysClass()) { obj->As_DynamicPhysClass()->Update_Visibility_Status(); } if (DirtyCullDebugDisplayEnabled) { const AABoxClass & box = obj->Get_Cull_Box(); if (box.Extent.Length2() > 0.0f) { DEBUG_RENDER_AABOX(obj->Get_Cull_Box(),Vector3(1,1,1),0.25f); } } } // Get the pvs VisTableClass * pvs = Get_Vis_Table_For_Rendering(camera); // Collect the visible objects bool use_umbra = false; #if (UMBRASUPPORT) use_umbra = UmbraSupport::Is_Umbra_Enabled(); #endif if (!use_umbra) { // Get the lists of visible objects { WWPROFILE( "Collect Static Objs" ); StaticCullingSystem->Collect_Visible_Objects(camera.Get_Frustum(),pvs,VisibleStaticObjectList,VisibleWSMeshList); } // Collect list of the visible dynamic objects { WWPROFILE( "Collect Dynamic Objs" ); DynamicCullingSystem->Collect_Visible_Objects(camera.Get_Frustum(),pvs,VisibleDynamicObjectList); } // LOD processing Optimize_LODs(camera,&VisibleDynamicObjectList,&VisibleStaticObjectList,&VisibleWSMeshList); // Texture projectors Apply_Projectors(camera); } else { #if (UMBRASUPPORT) RefPhysListClass vis_obj_list; { WWPROFILE("Umbra!"); UmbraSupport::Collect_Visible_Objects(camera,VisibleDynamicObjectList); } #endif } // release the visibility table REF_PTR_RELEASE(pvs); } /*********************************************************************************************** * PhysicsSceneClass::Post_Render_Processing -- processing that occurs after rendering * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Post_Render_Processing(void) { WWPROFILE("Post_Render_Processing"); // Release the visible object lists, release the shadow textures VisibleDynamicObjectList.Reset_List(); VisibleStaticObjectList.Reset_List(); VisibleWSMeshList.Reset_List(); // Update statistics Per_Frame_Statistics_Update(); } /*********************************************************************************************** * PhysicsSceneClass::Optimize_LODs -- Set the LOD level for each object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Optimize_LODs ( CameraClass & camera, RefPhysListClass * dyn_objs, RefPhysListClass * static_objs, RefPhysListClass * static_ws_meshes ) { WWPROFILE("Optimize_LODs"); // process the dynamic objects PredictiveLODOptimizerClass::Clear(); RefPhysListIterator it(dyn_objs); for (it.First(); !it.Is_Done(); it.Next()) { it.Peek_Obj()->Peek_Model()->Prepare_LOD(camera); it.Peek_Obj()->Set_Last_Visible_Frame(CurrentFrameNumber); } PredictiveLODOptimizerClass::Optimize_LODs(DynamicPolyBudget); // process the static objects PredictiveLODOptimizerClass::Clear(); for (it.First(static_objs); !it.Is_Done(); it.Next()) { it.Peek_Obj()->Peek_Model()->Prepare_LOD(camera); it.Peek_Obj()->Set_Last_Visible_Frame(CurrentFrameNumber); } for (it.First(static_ws_meshes); !it.Is_Done(); it.Next()) { it.Peek_Obj()->Peek_Model()->Prepare_LOD(camera); it.Peek_Obj()->Set_Last_Visible_Frame(CurrentFrameNumber); } PredictiveLODOptimizerClass::Optimize_LODs(StaticPolyBudget); } /*********************************************************************************************** * PhysicsSceneClass::Render -- Render the scene * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Customized_Render(RenderInfoClass & rinfo) { WWPROFILE("PhysicsSceneClass::Render"); /* ** Render the normal models */ Render_Objects(rinfo,&VisibleWSMeshList,&VisibleStaticObjectList,&VisibleDynamicObjectList); /* ** Backface Debug rendering */ #ifdef WWDEBUG Render_Backface_Occluders(rinfo,&VisibleWSMeshList,&VisibleStaticObjectList); #endif /* ** Debug widget rendering */ { static LightEnvironmentClass _defaultlightenvironment; _defaultlightenvironment.Reset(Vector3(0,0,0),Get_Ambient_Light()); _defaultlightenvironment.Add_Light(*SunLight); rinfo.light_environment = &_defaultlightenvironment; Render_Debug_Widgets(rinfo); Reset_Debug_Widget_List(); rinfo.light_environment = NULL; } if (Pathfinder != NULL) { Pathfinder->Render_Debug_Widgets(rinfo); } /* ** Vis Sector Debugging */ if (VisSectorDisplayEnabled || VisSectorHistoryEnabled) { // list of previous vis sectors so we can render them static StaticPhysClass * old_vis_sectors[3] = { NULL, NULL, NULL }; static int old_vis_index = 0; Vector3 vis_sample_point; Compute_Vis_Sample_Point(rinfo.Camera,&vis_sample_point); StaticPhysClass * vis_sector = StaticCullingSystem->Find_Vis_Tile(vis_sample_point); if (vis_sector != NULL) { MaterialPassClass * matpass = PhysResourceMgrClass::Get_Highlight_Material_Pass(); if (matpass) { // flush all rendering, set wireframe render mode WW3D::Flush(rinfo); DX8Wrapper::Set_DX8_Render_State(D3DRS_FILLMODE,D3DFILL_WIREFRAME); // set wireframe mode and draw the vis sector rinfo.Push_Material_Pass(matpass); rinfo.Push_Override_Flags(RenderInfoClass::RINFO_OVERRIDE_ADDITIONAL_PASSES_ONLY); if (VisSectorHistoryEnabled) { // render the previous vis sectors for (int i=0; i<3; i++) { if (old_vis_sectors[i] != NULL) { old_vis_sectors[i]->Render_Vis_Meshes(rinfo); } } // add this one to the history if it is new int prev_index = (old_vis_index + 2) % 3; if (old_vis_sectors[prev_index] != vis_sector) { old_vis_sectors[old_vis_index] = vis_sector; old_vis_index = (old_vis_index + 1) % 3; } } else { // Just draw the current vis sector vis_sector->Render_Vis_Meshes(rinfo); } WW3D::Flush(rinfo); rinfo.Pop_Material_Pass(); rinfo.Pop_Override_Flags(); // restore previous render mode switch(Get_Polygon_Mode()) { case POINT: DX8Wrapper::Set_DX8_Render_State(D3DRS_FILLMODE,D3DFILL_POINT); break; case LINE: DX8Wrapper::Set_DX8_Render_State(D3DRS_FILLMODE,D3DFILL_WIREFRAME); break; case FILL: DX8Wrapper::Set_DX8_Render_State(D3DRS_FILLMODE,D3DFILL_SOLID); break; } // release resources REF_PTR_RELEASE(matpass); } } } /* ** Dynamic Vis, Virtual Occludee Debugging */ if (VisGridDisplayMode == VIS_GRID_DISPLAY_ACTUAL_BOXES) { VisTableClass * pvs = Get_Vis_Table_For_Rendering(rinfo.Camera); if ((pvs != NULL) && (DynamicObjVisSystem != NULL)) { DynamicObjVisSystem->Render_Visible_Cells(rinfo,pvs,DynamicAABTreeCullClass::DISPLAY_ACTUAL_BOXES); } REF_PTR_RELEASE(pvs); } /* ** Light Source Debugging, render debug widgets at each light transform */ static bool ACTIVE_ONLY = true; if (LightingDebugDisplayEnabled) { StaticLightingSystem->Reset_Collection(); StaticLightingSystem->Collect_Objects(rinfo.Camera.Get_Frustum()); LightPhysClass * light = StaticLightingSystem->Peek_First_Collected_Object(); while (light != NULL) { if ((!light->Is_Disabled()) || (!ACTIVE_ONLY)) { DEBUG_RENDER_AXES(light->Get_Transform(),Vector3(1.0f,1.0f,1.0f)); } light = StaticLightingSystem->Peek_Next_Collected_Object(light); } } } /*********************************************************************************************** * PhysicsSceneClass::Render_Objects -- Render the visible objects * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 4/24/2001 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Render_Objects( RenderInfoClass& rinfo, RefPhysListClass * static_ws_list, RefPhysListClass * static_list, RefPhysListClass * dyn_list) { WWPROFILE("Render_Meshes"); RefPhysListIterator it(static_ws_list); if (WW3D::Get_Mesh_Draw_Mode()!=WW3D::MESH_DRAW_MODE_NONE) { if (Is_Backface_Occluder_Debug_Enabled()) { // render the static world-space meshes { WWPROFILE("world-space meshes"); for (it.First(static_ws_list); !it.Is_Done(); it.Next()) { // Only render occluders when backface debug is on if (it.Peek_Obj()->As_StaticPhysClass()->Is_Occluder() != 0) { Render_Object(rinfo,it.Peek_Obj()); } } } // render the other static objects { WWPROFILE("static objects"); for (it.First(static_list); !it.Is_Done(); it.Next()) { // Only render occluders when backface debug is on if (it.Peek_Obj()->As_StaticPhysClass()->Is_Occluder() != 0) { Render_Object(rinfo,it.Peek_Obj()); } } } } else { // render the static world-space meshes { WWPROFILE("world-space meshes"); for (it.First(static_ws_list); !it.Is_Done(); it.Next()) { Render_Object(rinfo,it.Peek_Obj()); } } // render the other static objects { WWPROFILE("static objects"); for (it.First(static_list); !it.Is_Done(); it.Next()) { Render_Object(rinfo,it.Peek_Obj()); } } } } // render the dynamic objects // render dynamic objects even if the render type is "NONE" { WWPROFILE("dynamic objects"); for (it.First(dyn_list); !it.Is_Done(); it.Next()) { Render_Object(rinfo,it.Peek_Obj()); } } } /*********************************************************************************************** * PhysicsSceneClass::Render_Object -- Render an individual object * * * * This function installs the lighting environment and renders the object. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 4/24/2001 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Render_Object(RenderInfoClass & context,PhysClass * obj) { if ((obj->Peek_Model() == NULL) || (obj->Is_Rendering_Disabled())) { return; } /* ** Set up the lighting environment for this object */ bool do_lighting = ( (obj->Is_Pre_Lit() == false) && (obj->Peek_Model()->Is_Not_Hidden_At_All()) ); if (do_lighting) { WWPROFILE("setup lights"); LightEnvironmentClass & light_env = *(obj->Get_Static_Lighting_Environment()); light_env.Pre_Render_Update(context.Camera.Get_Transform()); /* ** If lighting debugging is enabled, display a vector to each light source */ #if WWDEBUG Vector3 pos = obj->Peek_Model()->Get_Bounding_Box().Center; if (LightingDebugDisplayEnabled) { if ((pos - context.Camera.Get_Position()).Length2() < 30.0f * 30.0f) { for (int i=0; iRender(context); } /* ** Remove the lighting environment */ if (do_lighting) { context.light_environment = NULL; } } /*********************************************************************************************** * PhysicsSceneClass::Render_Backface_Occluders -- Render backfaces of all occluders * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 4/24/2001 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Render_Backface_Occluders ( RenderInfoClass & context, RefPhysListClass * static_ws_list, RefPhysListClass * static_list ) { static LightEnvironmentClass lenv; if (BackfaceDebugEnabled) { MaterialPassClass * matpass = PhysResourceMgrClass::Get_Highlight_Material_Pass(); if (matpass != NULL) { /* ** Flush the system and invert the backface culling check */ WW3D::Flush(context); ShaderClass::Invert_Backface_Culling(true); /* ** Set up the render context to render everything bright green */ ShaderClass shader = matpass->Peek_Shader(); shader.Set_Depth_Compare(ShaderClass::PASS_LESS); matpass->Set_Shader(shader); context.Push_Material_Pass(matpass); context.Push_Override_Flags(RenderInfoClass::RINFO_OVERRIDE_ADDITIONAL_PASSES_ONLY); lenv.Reset(Vector3(0,0,0),Vector3(1,1,1)); context.light_environment = &lenv; /* ** Render the world-space mesh that are occluders */ RefPhysListIterator it(static_ws_list); while (!it.Is_Done()) { StaticPhysClass * sphys = it.Peek_Obj()->As_StaticPhysClass(); if (sphys && sphys->Is_Occluder()) { sphys->Render(context); } it.Next(); } /* ** Render the static objects that are occluders */ it.First(static_list); while (!it.Is_Done()) { StaticPhysClass * sphys = it.Peek_Obj()->As_StaticPhysClass(); if (sphys && sphys->Is_Occluder()) { sphys->Render(context); } it.Next(); } /* ** Flush all rendering and restore the normal backface culling state */ WW3D::Flush(context); ShaderClass::Invert_Backface_Culling(false); context.Pop_Material_Pass(); context.Pop_Override_Flags(); REF_PTR_RELEASE(matpass); } } } /*********************************************************************************************** * PhysicsSceneClass::Re_Partition_Static_Objects -- partition the static objects * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * This should be done in the editor. VIS data is invalidated when you do this... * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Re_Partition_Static_Objects(void) { StaticCullingSystem->Re_Partition(); } /*********************************************************************************************** * PhysicsSceneClass::Re_Partition_Static_Lights -- partition the static lights * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * This should be done in the editor. VIS data is invalidated when you do this... * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Re_Partition_Static_Lights(void) { StaticLightingSystem->Re_Partition(); } /*********************************************************************************************** * PhysicsSceneClass::Re_Partition_Dynamic_Culling_System -- partition the dynamic culling sys * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * This should be done in the editor. VIS data is invalidated when you do this... * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Re_Partition_Dynamic_Culling_System(void) { Vector3 wmin,wmax; Get_Level_Extents(wmin,wmax); DynamicCullingSystem->Re_Partition( wmin,wmax, MAX_DYNAMIC_OBJ_RADIUS ); DynamicObjVisSystem->Re_Partition( NULL, wmin,wmax, MIN_GRID_CELL_SIZE, MAX_GRID_CELL_COUNT, MAX_DYNAMIC_OBJ_RADIUS ); Reset_Vis(); } /*********************************************************************************************** * PhysicsSceneClass::Re_Partition_Dynamic_Culling_System -- partition the dynamic culling sys * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * This should be done in the editor. VIS data is invalidated when you do this... * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Re_Partition_Dynamic_Culling_System(DynamicVectorClass & virtual_occludees) { Vector3 wmin,wmax; Get_Level_Extents(wmin,wmax); DynamicCullingSystem->Re_Partition( wmin,wmax, MAX_DYNAMIC_OBJ_RADIUS ); AABoxClass bounds(virtual_occludees[0]); for (int i=0; iRe_Partition( &virtual_occludees, bounds.Center - bounds.Extent, bounds.Center + bounds.Extent, MIN_GRID_CELL_SIZE, MAX_GRID_CELL_COUNT, MAX_DYNAMIC_OBJ_RADIUS ); Reset_Vis(); } /*********************************************************************************************** * PhysicsSceneClass::Re_Partition_Static_Projectors -- partition the static projectors * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Re_Partition_Static_Projectors(void) { StaticProjectorCullingSystem->Re_Partition(); } /*********************************************************************************************** * PhysicsSceneClass::Update_Culling_System_Bounding_Boxes -- updates the cull systems * * * * This should be performed by the level editor when geometry may have changed but we do not * * want to do a re-partition due to the loss of hierarchical VIS data. Basically, the editor * * will call this every time it loads an LVL in case the user has changed the geometry. It * * causes all bounding boxes in the static culling systems to be validated. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 9/3/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Update_Culling_System_Bounding_Boxes(void) { StaticCullingSystem->Update_Bounding_Boxes(); StaticLightingSystem->Update_Bounding_Boxes(); } /*********************************************************************************************** * PhysicsSceneClass::Verify_Culling_Systems -- Verify the culling systems * * * * This function asks the culling systems to verify that all of thier bounding boxes * * are properly constructed. I.e. they contain the objects they claim to contain, etc. * * * * INPUT: * * error_report - will be filled in with a description of any errors encountered * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 9/28/2000 gth : Created. * *=============================================================================================*/ bool PhysicsSceneClass::Verify_Culling_Systems(StringClass & set_error_report) { return StaticCullingSystem->Verify(set_error_report); } /*********************************************************************************************** * PhysicsSceneClass::Get_Level_Extents -- returns the bounds of the level * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Get_Level_Extents(Vector3 &min, Vector3 &max) { const AABoxClass & level_bounds = StaticCullingSystem->Get_Bounding_Box(); min = level_bounds.Center - level_bounds.Extent; max = level_bounds.Center + level_bounds.Extent; } /*********************************************************************************************** * PhysicsSceneClass::Set_Polygon_Budgets -- set the budgets for the LOD system * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Set_Polygon_Budgets(int static_count,int dynamic_count) { StaticPolyBudget = static_count; DynamicPolyBudget = dynamic_count; } /*********************************************************************************************** * PhysicsSceneClass::Get_Polygon_Budgets -- returns the budgets for the LOD system * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Get_Polygon_Budgets(int * static_count,int * dynamic_count) { *static_count = StaticPolyBudget; *dynamic_count = DynamicPolyBudget; } /*********************************************************************************************** * PhysicsSceneClass::Per_Frame_Statistics_Update -- statistics tracking * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Per_Frame_Statistics_Update(void) { CurrentStats.FrameCount ++; if (CurrentStats.FrameCount >= STATISTICS_FRAMES) { /* ** Collect the culling system stats */ const GridCullSystemClass::StatsStruct & dyn_stats = DynamicCullingSystem->Get_Statistics(); const AABTreeCullSystemClass::StatsStruct & static_stats = StaticCullingSystem->Get_Statistics(); const AABTreeCullSystemClass::StatsStruct & light_stats = StaticLightingSystem->Get_Statistics(); CurrentStats.CullNodeCount = dyn_stats.NodeCount + static_stats.NodeCount + light_stats.NodeCount; CurrentStats.CullNodesAccepted = dyn_stats.NodesAccepted + static_stats.NodesAccepted + light_stats.NodesAccepted; CurrentStats.CullNodesTriviallyAccepted = dyn_stats.NodesTriviallyAccepted + static_stats.NodesTriviallyAccepted + light_stats.NodesTriviallyAccepted; CurrentStats.CullNodesRejected = dyn_stats.NodesRejected + static_stats.NodesRejected + light_stats.NodesRejected; DynamicCullingSystem->Reset_Statistics(); StaticCullingSystem->Reset_Statistics(); StaticLightingSystem->Reset_Statistics(); /* ** Copy over LastValidStats, reset */ LastValidStats = CurrentStats; CurrentStats.Reset(); } } /*********************************************************************************************** * PhysicsSceneClass::Get_Statistics -- returns statistics * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ const PhysicsSceneClass::StatsStruct & PhysicsSceneClass::Get_Statistics(void) { return LastValidStats; } /*********************************************************************************************** * PhysicsSceneClass::Find_Static_Object -- Find static object with the given ID * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ StaticPhysClass * PhysicsSceneClass::Find_Static_Object( int instance_id ) { RefPhysListIterator it(&StaticObjList); for (it.First(); !it.Is_Done(); it.Next()) { if ( (int)(it.Peek_Obj()->Get_ID()) == instance_id ) { return (StaticPhysClass*)it.Peek_Obj(); } } return NULL; } /*********************************************************************************************** * PhysicsSceneClass::Shatter_Mesh -- Clips a mesh into pieces and scatters them * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/7/2000 gth : Created. * *=============================================================================================*/ void PhysicsSceneClass::Shatter_Mesh ( MeshClass * mesh, const Vector3 & impact_point, const Vector3 & impact_normal, const Vector3 & impact_velocity ) { LookupTableClass * vel_table = LookupTableMgrClass::Get_Table("ShatterVel.tbl"); LookupTableClass * avel_table = LookupTableMgrClass::Get_Table("ShatterAVel.tbl"); /* ** Clip the mesh into fragments */ ShatterSystem::Shatter_Mesh(mesh,impact_point,impact_normal); /* ** Wake up any dynamic objects in the area */ if (mesh->Get_Collision_Type() & COLLISION_TYPE_PHYSICAL) { AABoxClass bounds = mesh->Get_Bounding_Box(); bounds.Extent *= 1.05f; Force_Dynamic_Objects_Awake(bounds); } /* ** Disable the original mesh so that it doesn't shatter repeatedly */ mesh->Set_Hidden(true); mesh->Set_Collision_Type(0); /* ** Now create new auto-destructing projectiles for each fragment */ for (int i=0; iGet_Transform(); frag->Set_Model(frag_model); frag->Set_Transform(frag_tm); frag->Set_Orientation_Mode_Tumbling(); frag->Set_Lifetime(3.0f); frag->Set_Gravity_Multiplier(2.0f); frag->Set_Bounce_Count(1); /* ** Vector from the impact to the center of the fragment is ** used in generating the initial velocity and rotation of the fragment */ Vector3 dc = frag_tm.Get_Translation() - impact_point; float dclen = dc.Length(); dc /= dclen; /* ** Generate a suitable velocity for the fragment */ Vector3 frag_vel = impact_velocity; frag_vel.Normalize(); if (rand() & 0x00000100) { frag_vel *= -1.0f; } frag_vel += 0.2f*dc; frag_vel *= vel_table->Get_Value(dclen); frag->Set_Velocity(frag_vel); /* ** Generate a rotation for the fragment. The axis it rotates about ** will be in the plane of the impact, perpendicular to a vector from ** the impact to the CM */ Vector3 axis; Vector3::Cross_Product(impact_velocity,dc,&axis); frag->Set_Orientation_Mode_Tumbling(axis,avel_table->Get_Value(dclen)); /* ** We cannot allow these object to get saved since their model was ** procedurally generated and it will not get loaded... */ frag->Enable_Dont_Save(true); /* ** Debugging, Stop the velocity, set life to infinite, move along initial velocity to offset pieces */ #if (SHATTER_DEBUG) Matrix3D tm = frag->Get_Transform(); Vector3 pos,vel; tm.Get_Translation(&pos); frag->Get_Velocity(&vel); tm.Set_Translation(pos+vel*0.1f); frag->Set_Transform(tm); frag->Set_Velocity(Vector3(0,0,0)); frag->Set_Lifetime(60.0f); frag->Set_Gravity_Multiplier(0.0f); frag->Set_Bounce_Count(100); frag->Set_Orientation_Mode_Fixed(); #endif /* ** Add the fragment to the scene */ Add_Dynamic_Object(frag); REF_PTR_RELEASE(frag); } /* ** Done, have the shatter system release the fragments */ ShatterSystem::Release_Fragments(); vel_table->Release_Ref(); avel_table->Release_Ref(); } void PhysicsSceneClass::Add_Camera_Shake ( const Vector3 & position, float radius, float duration, float power ) { WWASSERT(CameraShakeSystem != NULL); CameraShakeSystem->Add_Camera_Shake(position,radius,duration,power); } void PhysicsSceneClass::Apply_Camera_Shakes(CameraClass & camera) { CameraShakeSystem->Update_Camera(camera); } float PhysicsSceneClass::Compute_Vis_Mesh_Ram(void) { float total = 0.0f; RefPhysListIterator it(&StaticObjList); for (it.First(); !it.Is_Done(); it.Next()) { total += ((StaticPhysClass *)it.Peek_Obj())->Compute_Vis_Mesh_Ram(); } return total; } void PhysicsSceneClass::Force_Dynamic_Objects_Awake(const AABoxClass & box) { /* ** Collect the objects that touch this box and wake them up. */ NonRefPhysListClass list; Collect_Objects(box,false,true,&list); NonRefPhysListIterator it(&list); while (!it.Is_Done()) { PhysClass * obj = it.Peek_Obj(); obj->Force_Awake(); if (obj->As_Phys3Class() != NULL) { obj->As_Phys3Class()->Invalidate_Ground_State(); } it.Next(); } } /****************************************************************************************** ** ** ** PhysicsSceneClass::StatsStruct Implementation ** ** ******************************************************************************************/ PhysicsSceneClass::StatsStruct::StatsStruct(void) { Reset(); } void PhysicsSceneClass::StatsStruct::Reset(void) { FrameCount = 0; CullNodeCount = 0; CullNodesAccepted = 0; CullNodesTriviallyAccepted = 0; CullNodesRejected = 0; } /* ** Force-Link relevant modules from WWPhys */ void Force_Link_Modules(void) { FORCE_LINK(decophys); FORCE_LINK(humanphys); FORCE_LINK(lightphys); FORCE_LINK(motorcycle); FORCE_LINK(movephys); FORCE_LINK(phys3); FORCE_LINK(rbody); FORCE_LINK(staticphys); FORCE_LINK(staticanimphys); FORCE_LINK(wheelvehicle); FORCE_LINK(projectile); FORCE_LINK(timeddecophys); FORCE_LINK(trackedvehicle); FORCE_LINK(vtolvehicle); FORCE_LINK(waypath); FORCE_LINK(waypoint); FORCE_LINK(dynamicanimphys); FORCE_LINK(shakeablestaticphys); FORCE_LINK(RenegadeTerrainPatch); }