/*
**	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/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<TexProjectClass>;
	DynamicProjectorCullingSystem = new TypedGridCullSystemClass<TexProjectClass>;

	/*
	** 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; i<light_env.Get_Light_Count(); i++) {
					DEBUG_RENDER_VECTOR(pos,light_env.Get_Light_Direction(i),light_env.Get_Light_Diffuse(i));
				}
			}
		}
#endif
		context.light_environment = &light_env;
	
	} else {

		static LightEnvironmentClass _emptylightenvironment;
		_emptylightenvironment.Reset(Vector3(0,0,0),Vector3(1,1,1));
		context.light_environment = &_emptylightenvironment;

	}

	/*
	** Render the object
	*/
	{
		WWPROFILE("render");
		obj->Render(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<AABoxClass> & 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; i<virtual_occludees.Count(); i++) {
		bounds.Add_Box(virtual_occludees[i]);
	}
	
	DynamicObjVisSystem->Re_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; i<ShatterSystem::Get_Fragment_Count(); i++) {

		ProjectileClass * frag = NEW_REF(ProjectileClass,());
		RenderObjClass * frag_model = ShatterSystem::Peek_Fragment(i);
		Matrix3D frag_tm = frag_model->Get_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);
}


