887 lines
38 KiB
C++
887 lines
38 KiB
C++
/*
|
|
** 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_vis.cpp $*
|
|
* *
|
|
* Original Author:: Greg Hjelstrom *
|
|
* *
|
|
* $Author:: Greg_h $*
|
|
* *
|
|
* $Modtime:: 10/23/01 8:35p $*
|
|
* *
|
|
* $Revision:: 47 $*
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* PhysicsSceneClass::Release_Vis_Resources -- Releases resources used by the VIS code *
|
|
* PhysicsSceneClass::Reset_Vis -- Sets the internal vis reset flag. *
|
|
* PhysicsSceneClass::Validate_Vis -- Clears the internal vis reset flag *
|
|
* PhysicsSceneClass::Internal_Vis_Reset -- Resets the vis system if needed *
|
|
* PhysicsSceneClass::Get_Vis_Camera -- returns a pointer (ref-counted) to the vis camera *
|
|
* PhysicsSceneClass::Get_Vis_Gerd -- returns a pointer to the VIS Gerd *
|
|
* PhysicsSceneClass::Show_Vis_Window -- Makes the vis render window visible to the user *
|
|
* PhysicsSceneClass::Is_Vis_Window_Visible -- Returns status of the vis render window *
|
|
* PhysicsSceneClass::Get_Static_Light_Count -- returns the number of static lights *
|
|
* PhysicsSceneClass::Generate_Vis_For_Light -- generate a PVS for the specified light *
|
|
* PhysicsSceneClass::Update_Vis -- Performs a vis sample from the given coord system *
|
|
* PhysicsSceneClass::Vis_Render_And_Scan -- Renders the scene and scans for visible objects *
|
|
* PhysicsSceneClass::Vis_Debug_Render -- Renders the same way VIS does *
|
|
* PhysicsSceneClass::Generate_Vis_Statistics_Report -- Stats about the visibility in the le *
|
|
* PhysicsSceneClass::Optimize_Visibility_Data -- combines and removes redundant vis data *
|
|
* PhysicsSceneClass::Merge_Vis_Sector_IDs -- Merges two sector ID's *
|
|
* PhysicsSceneClass::Merge_Vis_Object_IDs -- combines two vis object ID's *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
|
|
#include "pscene.h"
|
|
#include "staticaabtreecull.h"
|
|
#include "dynamicaabtreecull.h"
|
|
#include "staticphys.h"
|
|
#include "lightcull.h"
|
|
#include "camera.h"
|
|
#include "vertmaterial.h"
|
|
#include "shader.h"
|
|
#include "visrendercontext.h"
|
|
#include "visoptimizationcontext.h"
|
|
#include "visoptprogress.h"
|
|
#include "light.h"
|
|
#include "visrasterizer.h"
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
**
|
|
** PhysicsSceneClass Visibility system
|
|
**
|
|
************************************************************************************/
|
|
|
|
|
|
void PhysicsSceneClass::Enable_Vis(bool onoff)
|
|
{
|
|
VisEnabled = onoff;
|
|
}
|
|
|
|
void PhysicsSceneClass::Invert_Vis(bool onoff)
|
|
{
|
|
VisInverted = onoff;
|
|
}
|
|
|
|
void PhysicsSceneClass::Set_Vis_Quick_And_Dirty(bool onoff)
|
|
{
|
|
VisQuickAndDirty = onoff;
|
|
}
|
|
|
|
void PhysicsSceneClass::Enable_Vis_Sector_Display(bool onoff)
|
|
{
|
|
VisSectorDisplayEnabled = onoff;
|
|
}
|
|
|
|
void PhysicsSceneClass::Enable_Vis_Sector_History_Display(bool onoff)
|
|
{
|
|
VisSectorHistoryEnabled = onoff;
|
|
}
|
|
|
|
void PhysicsSceneClass::Enable_Vis_Sector_Fallback(bool onoff)
|
|
{
|
|
VisSectorFallbackEnabled = onoff;
|
|
}
|
|
|
|
void PhysicsSceneClass::Enable_Backface_Occluder_Debug(bool onoff)
|
|
{
|
|
BackfaceDebugEnabled = onoff;
|
|
}
|
|
|
|
void PhysicsSceneClass::Set_Vis_Grid_Display_Mode(int mode)
|
|
{
|
|
VisGridDisplayMode = mode;
|
|
}
|
|
|
|
bool PhysicsSceneClass::Is_Vis_Enabled(void)
|
|
{
|
|
return VisEnabled;
|
|
}
|
|
|
|
bool PhysicsSceneClass::Is_Vis_Inverted(void)
|
|
{
|
|
return VisInverted;
|
|
}
|
|
|
|
bool PhysicsSceneClass::Is_Vis_Quick_And_Dirty(void)
|
|
{
|
|
return VisQuickAndDirty;
|
|
}
|
|
|
|
bool PhysicsSceneClass::Is_Vis_Sector_Display_Enabled(void)
|
|
{
|
|
return VisSectorDisplayEnabled;
|
|
}
|
|
|
|
bool PhysicsSceneClass::Is_Vis_Sector_History_Display_Enabled(void)
|
|
{
|
|
return VisSectorHistoryEnabled;
|
|
}
|
|
|
|
bool PhysicsSceneClass::Is_Vis_Sector_Fallback_Enabled(void)
|
|
{
|
|
return VisSectorFallbackEnabled;
|
|
}
|
|
|
|
bool PhysicsSceneClass::Is_Backface_Occluder_Debug_Enabled(void)
|
|
{
|
|
return BackfaceDebugEnabled;
|
|
}
|
|
|
|
int PhysicsSceneClass::Get_Vis_Grid_Display_Mode(void)
|
|
{
|
|
return VisGridDisplayMode;
|
|
}
|
|
|
|
void PhysicsSceneClass::Vis_Grid_Debug_Reset_Node(void)
|
|
{
|
|
DynamicObjVisSystem->Debug_Reset_Node();
|
|
}
|
|
|
|
bool PhysicsSceneClass::Vis_Grid_Debug_Enter_Parent(void)
|
|
{
|
|
return DynamicObjVisSystem->Debug_Enter_Parent();
|
|
}
|
|
|
|
bool PhysicsSceneClass::Vis_Grid_Debug_Enter_Sibling(void)
|
|
{
|
|
return DynamicObjVisSystem->Debug_Enter_Sibling();
|
|
}
|
|
|
|
bool PhysicsSceneClass::Vis_Grid_Debug_Enter_Front_Child(void)
|
|
{
|
|
return DynamicObjVisSystem->Debug_Enter_Front_Child();
|
|
}
|
|
|
|
bool PhysicsSceneClass::Vis_Grid_Debug_Enter_Back_Child(void)
|
|
{
|
|
return DynamicObjVisSystem->Debug_Enter_Back_Child();
|
|
}
|
|
|
|
bool PhysicsSceneClass::Is_Vis_Sector_Missing(void)
|
|
{
|
|
return VisSectorMissing;
|
|
}
|
|
|
|
int PhysicsSceneClass::Allocate_Vis_Object_ID(int count /* = 1*/)
|
|
{
|
|
return VisTableManager.Allocate_Vis_Object_ID(count);
|
|
}
|
|
|
|
int PhysicsSceneClass::Allocate_Vis_Sector_ID(int count /* = 1*/)
|
|
{
|
|
return VisTableManager.Allocate_Vis_Sector_ID(count);
|
|
}
|
|
|
|
int PhysicsSceneClass::Get_Vis_Table_Size(void)
|
|
{
|
|
Internal_Vis_Reset();
|
|
return VisTableManager.Get_Vis_Table_Size();
|
|
}
|
|
|
|
int PhysicsSceneClass::Get_Vis_Table_Count(void)
|
|
{
|
|
Internal_Vis_Reset();
|
|
return VisTableManager.Get_Vis_Table_Count();
|
|
}
|
|
|
|
void PhysicsSceneClass::Compute_Vis_Sample_Point(const CameraClass & camera,Vector3 * set_point)
|
|
{
|
|
WWASSERT(set_point != NULL);
|
|
if (!VisSamplePointLocked) {
|
|
float nearz,farz;
|
|
camera.Get_Clip_Planes(nearz,farz);
|
|
Matrix3D::Transform_Vector(camera.Get_Transform(),Vector3(0,0,-nearz-0.05f),set_point);
|
|
} else {
|
|
*set_point = LockedVisSamplePoint;
|
|
}
|
|
}
|
|
|
|
VisTableClass * PhysicsSceneClass::Get_Vis_Table(int vis_sector_id)
|
|
{
|
|
return VisTableManager.Get_Vis_Table(vis_sector_id);
|
|
}
|
|
|
|
VisTableClass * PhysicsSceneClass::Get_Vis_Table(const Vector3 & point)
|
|
{
|
|
int vis_id = StaticCullingSystem->Get_Vis_Sector_ID(point);
|
|
return VisTableManager.Get_Vis_Table(vis_id);
|
|
}
|
|
|
|
VisTableClass * PhysicsSceneClass::Get_Vis_Table(const CameraClass & camera)
|
|
{
|
|
Vector3 sample_point;
|
|
Compute_Vis_Sample_Point(camera,&sample_point);
|
|
return Get_Vis_Table(sample_point);
|
|
}
|
|
|
|
VisTableClass * PhysicsSceneClass::Get_Vis_Table_For_Rendering(const CameraClass & camera)
|
|
{
|
|
// Decompress the visibility table for the current camera view
|
|
// Note that if the vis system needs to be reset, we don't want to use any obsolete data
|
|
// Also, if a sample point hasn't been given, we will skip visibility.
|
|
// Also, if we don't find a vis sector, we'll try to use the last valid one that we had.
|
|
int vis_id = -1;
|
|
VisTableClass * pvs = NULL;
|
|
Vector3 vis_sample_point;
|
|
Compute_Vis_Sample_Point(camera,&vis_sample_point);
|
|
|
|
if ((!VisResetNeeded) && VisEnabled) {
|
|
|
|
vis_id = StaticCullingSystem->Get_Vis_Sector_ID(vis_sample_point);
|
|
|
|
if (vis_id == -1) {
|
|
VisSectorMissing = true;
|
|
if (VisSectorFallbackEnabled) {
|
|
vis_id = LastValidVisId;
|
|
}
|
|
} else {
|
|
|
|
if ((LastValidVisId != vis_id) && VisSectorDisplayEnabled) {
|
|
StaticPhysClass * tile = StaticCullingSystem->Find_Vis_Tile(vis_sample_point);
|
|
WWDEBUG_SAY (("Vis Sector: %s\n", tile->Peek_Model ()->Get_Name ()));
|
|
}
|
|
|
|
LastValidVisId = vis_id;
|
|
VisSectorMissing = false;
|
|
}
|
|
|
|
if (vis_id != -1) {
|
|
pvs = VisTableManager.Get_Vis_Table(LastValidVisId);
|
|
}
|
|
|
|
if ((VisInverted) && (pvs != NULL)) {
|
|
VisTableClass * new_pvs = NEW_REF(VisTableClass,(*pvs));
|
|
new_pvs->Invert();
|
|
REF_PTR_RELEASE(pvs);
|
|
pvs = new_pvs;
|
|
}
|
|
}
|
|
|
|
return pvs;
|
|
}
|
|
|
|
|
|
uint32 PhysicsSceneClass::Get_Dynamic_Object_Vis_ID
|
|
(
|
|
const AABoxClass & obj_bounds,
|
|
int * node_id
|
|
)
|
|
{
|
|
return DynamicObjVisSystem->Get_Dynamic_Object_Vis_ID(obj_bounds,node_id);
|
|
}
|
|
|
|
void PhysicsSceneClass::Debug_Display_Dynamic_Vis_Node(int node_id)
|
|
{
|
|
if (VisGridDisplayMode == VIS_GRID_DISPLAY_OCCUPIED) {
|
|
AABoxClass bounds;
|
|
DynamicObjVisSystem->Get_Node_Bounds(node_id,&bounds);
|
|
bounds.Extent -= Vector3(5,5,5);
|
|
DEBUG_RENDER_AABOX(bounds,Vector3(0,1,1),0.25f);
|
|
}
|
|
}
|
|
|
|
void PhysicsSceneClass::Lock_Vis_Sample_Point(bool onoff)
|
|
{
|
|
VisSamplePointLocked = onoff;
|
|
LockedVisSamplePoint = LastCameraPosition;
|
|
}
|
|
|
|
bool PhysicsSceneClass::Is_Vis_Sample_Point_Locked(void)
|
|
{
|
|
return VisSamplePointLocked;
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Release_Vis_Resources -- Releases resources used by the VIS code *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void PhysicsSceneClass::Release_Vis_Resources(void)
|
|
{
|
|
REF_PTR_RELEASE(VisCamera);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Reset_Vis -- Sets the internal vis reset flag. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void PhysicsSceneClass::Reset_Vis(bool doitnow)
|
|
{
|
|
/*
|
|
** defer the actual reset until later.
|
|
** the Update_Vis call and the Save_Map methods will check
|
|
** this bit and do the real reset
|
|
*/
|
|
VisResetNeeded = true;
|
|
|
|
if (doitnow) {
|
|
Internal_Vis_Reset();
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Validate_Vis -- Clears the internal vis reset flag *
|
|
* *
|
|
* This should not normally be called. It is needed when the level editor loads a level. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void PhysicsSceneClass::Validate_Vis(void)
|
|
{
|
|
/*
|
|
** Clear the reset flag, this is needed after a level is loaded.
|
|
** Normally as static objects are added to the system, the reset
|
|
** flag will be set, but in the case of loading, we are also
|
|
** loading the visibility data...
|
|
*/
|
|
VisResetNeeded = false;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Internal_Vis_Reset -- Resets the vis system if needed *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void PhysicsSceneClass::Internal_Vis_Reset(void)
|
|
{
|
|
if (VisResetNeeded) {
|
|
|
|
VisResetNeeded = false;
|
|
WWDEBUG_SAY(("Resetting the visibility system.\r\n"));
|
|
|
|
/*
|
|
** Throw away all visibility data.
|
|
*/
|
|
VisTableManager.Reset();
|
|
|
|
/*
|
|
** Re-partition the static object culling systems for the heck of it.
|
|
** We don't re-partition the dynamic object culling system since it is
|
|
** a massive preprocessing step to actually generate it.
|
|
*/
|
|
StaticCullingSystem->Re_Partition();
|
|
StaticLightingSystem->Re_Partition();
|
|
|
|
/*
|
|
** Assign Vis IDs. Each system may allocate both vis sector ID's and
|
|
** vis object IDs.
|
|
*/
|
|
StaticCullingSystem->Assign_Vis_IDs();
|
|
DynamicObjVisSystem->Assign_Vis_IDs();
|
|
StaticLightingSystem->Assign_Vis_IDs();
|
|
|
|
/*
|
|
** Force all dynamic objects to recompute their visibility id
|
|
*/
|
|
RefPhysListIterator it(&ObjList);
|
|
while (!it.Is_Done()) {
|
|
DynamicPhysClass * pobj = it.Peek_Obj()->As_DynamicPhysClass();
|
|
if (pobj!=NULL) {
|
|
pobj->Update_Visibility_Status();
|
|
}
|
|
it.Next();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Get_Vis_Camera -- returns a pointer (ref-counted) to the vis camera *
|
|
* *
|
|
* The VIS camera is allocated the first time it is needed. Normally this is only done *
|
|
* as a pre-processing step inside the level editor. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
CameraClass * PhysicsSceneClass::Get_Vis_Camera(void)
|
|
{
|
|
if (VisCamera) {
|
|
VisCamera->Add_Ref();
|
|
return VisCamera;
|
|
}
|
|
|
|
VisCamera = new CameraClass;
|
|
VisCamera->Set_Clip_Planes(VIS_NEAR_CLIP,VIS_FAR_CLIP);
|
|
VisCamera->Set_View_Plane(DEG_TO_RAD(90.0f),DEG_TO_RAD(90.0f));
|
|
VisCamera->Set_Viewport(Vector2(0,0),Vector2(1,1));
|
|
|
|
VisCamera->Add_Ref();
|
|
return VisCamera;
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Update_Vis -- Performs a vis sample from the given coord system *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
VisSampleClass
|
|
PhysicsSceneClass::Update_Vis
|
|
(
|
|
const Matrix3D & camera_tm,
|
|
VisDirBitsType direction_bits
|
|
)
|
|
{
|
|
return Update_Vis(camera_tm.Get_Translation(),camera_tm,direction_bits);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Update_Vis -- Performs a vis sample from the given coord system *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
VisSampleClass
|
|
PhysicsSceneClass::Update_Vis
|
|
(
|
|
const Vector3 & sample_point,
|
|
const Matrix3D & camera_tm,
|
|
VisDirBitsType direction_bits,
|
|
CameraClass * alternate_camera,
|
|
int user_vis_id
|
|
)
|
|
{
|
|
/*
|
|
** If the visibility system has been invalidated, reset it now
|
|
*/
|
|
Internal_Vis_Reset();
|
|
|
|
/*
|
|
** Look up the vis-sector-id for this vis sample
|
|
*/
|
|
int vis_id = 0;
|
|
if (user_vis_id == -1) {
|
|
vis_id = StaticCullingSystem->Get_Vis_Sector_ID(sample_point);
|
|
} else {
|
|
vis_id = user_vis_id;
|
|
}
|
|
|
|
/*
|
|
** Get the existing pvs and make a copy of it that we can
|
|
** modify with the results of our sampling
|
|
*/
|
|
VisTableClass * original_pvs = VisTableManager.Get_Vis_Table(vis_id,true);
|
|
|
|
if (original_pvs == NULL) {
|
|
VisSampleClass vis_sample(camera_tm,direction_bits);
|
|
vis_sample.Init_Error();
|
|
WWDEBUG_SAY(("Vis Sample Rejected - No Vis Sector or Vis Sector ID not assigned!\r\n"));
|
|
return vis_sample;
|
|
}
|
|
|
|
VisTableClass * pvs = new VisTableClass(*original_pvs);
|
|
|
|
/*
|
|
** Grab the camera, GERD, shader, vertex material...
|
|
*/
|
|
CameraClass * camera = NULL;
|
|
if (alternate_camera) { // if user is supplying an alternate camera, use it
|
|
camera = alternate_camera;
|
|
camera->Add_Ref();
|
|
} else { // otherwise use the vis camera
|
|
camera = Get_Vis_Camera();
|
|
}
|
|
WWASSERT (camera != NULL);
|
|
|
|
/*
|
|
** Create the render context, initialize the GERD, install the Vis shader and vertex material
|
|
*/
|
|
VisRenderContextClass context(*camera,*pvs);
|
|
context.Set_Resolution(VIS_RENDER_WIDTH,VIS_RENDER_HEIGHT);
|
|
context.Set_Vis_Quick_And_Dirty(VisQuickAndDirty);
|
|
|
|
/*
|
|
** Evaluate visiblity for the six views from this point
|
|
*/
|
|
VisSampleClass vis_sample(camera_tm,direction_bits);
|
|
|
|
WWDEBUG_SAY(("Generating Vis for sector %d... ",vis_id));
|
|
|
|
for (int i=0; i<VIS_DIRECTIONS; i++) {
|
|
if (vis_sample.Direction_Enabled((VisDirType)i)) {
|
|
if (!vis_sample.Sample_Useless() || (direction_bits & VIS_FORCE_ACCEPT)) {
|
|
vis_sample.Set_Cur_Direction((VisDirType)i);
|
|
context.Camera.Set_Transform(vis_sample.Get_Camera_Transform((VisDirType)i));
|
|
Vis_Render_And_Scan(context,vis_sample);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** The static culling system needs to propogate the leaf visibility bits through its
|
|
** hierarchy.
|
|
*/
|
|
StaticCullingSystem->Propogate_Hierarchical_Visibility(pvs);
|
|
|
|
/*
|
|
** Record how many bits this sample actually changed
|
|
*/
|
|
vis_sample.Set_Bits_Changed(original_pvs->Count_Differences(*pvs));
|
|
|
|
/*
|
|
** Accept the sample if it was not rejected -OR- the user has set the VIS_FORCE_ACCEPT bit
|
|
*/
|
|
bool accept_sample = (!vis_sample.Sample_Rejected()) || (direction_bits & VIS_FORCE_ACCEPT);
|
|
if (accept_sample) {
|
|
VisTableManager.Update_Vis_Table(vis_id,pvs);
|
|
WWDEBUG_SAY(("Done! (%d bits changed) \r\n",vis_sample.Get_Bits_Changed()));
|
|
} else {
|
|
WWDEBUG_SAY(("Rejected!\r\n"));
|
|
}
|
|
|
|
/*
|
|
** Release assets
|
|
*/
|
|
REF_PTR_RELEASE(camera);
|
|
REF_PTR_RELEASE(original_pvs);
|
|
REF_PTR_RELEASE(pvs);
|
|
|
|
return vis_sample;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Get_Static_Light_Count -- returns the number of static lights *
|
|
* *
|
|
* Each static light allocates a PVS. This accessor will let you loop over each light *
|
|
* and update its PVS. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/19/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
int PhysicsSceneClass::Get_Static_Light_Count(void)
|
|
{
|
|
/*
|
|
** Count the lights in the list
|
|
*/
|
|
int counter = 0;
|
|
RefPhysListIterator light_it = Get_Static_Light_Iterator();
|
|
for (light_it.First();!light_it.Is_Done(); light_it.Next()) {
|
|
counter++;
|
|
}
|
|
|
|
return counter;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Generate_Vis_For_Light -- generate a PVS for the specified light *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/19/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void PhysicsSceneClass::Generate_Vis_For_Light(int light_index)
|
|
{
|
|
/*
|
|
** For lights, we're going to use the VIS camera but we're going to tweak the far
|
|
** clip plane to be the outer-radius of the light's falloff sphere.
|
|
*/
|
|
CameraClass * camera = Get_Vis_Camera();
|
|
|
|
/*
|
|
** Find the specified light. Array-like access into a list...
|
|
*/
|
|
RefPhysListIterator light_it = Get_Static_Light_Iterator();
|
|
for (; light_index > 0; light_index--) {
|
|
light_it.Next();
|
|
}
|
|
|
|
/*
|
|
** Update vis for the specified light.
|
|
*/
|
|
LightPhysClass * light = light_it.Peek_Obj()->As_LightPhysClass();
|
|
if ( (light != NULL) &&
|
|
(light->Get_Vis_Sector_ID() != 0xFFFFFFFF) &&
|
|
(light->Peek_Model() != NULL) &&
|
|
(light->Peek_Model()->Class_ID() == RenderObjClass::CLASSID_LIGHT))
|
|
{
|
|
/*
|
|
** Perform the vis sample
|
|
*/
|
|
LightClass * lightmodel = (LightClass *)light->Peek_Model();
|
|
camera->Set_Clip_Planes(0.01f,lightmodel->Get_Attenuation_Range());
|
|
camera->Set_Transform(light->Get_Transform());
|
|
|
|
Update_Vis( light->Get_Transform().Get_Translation(),
|
|
light->Get_Transform(),
|
|
(VisDirBitsType)(VIS_ALL | VIS_FORCE_ACCEPT),
|
|
camera,
|
|
light->Get_Vis_Sector_ID() );
|
|
|
|
}
|
|
|
|
/*
|
|
** Done, reset the camera clip planes, release resources
|
|
*/
|
|
camera->Set_Clip_Planes(VIS_NEAR_CLIP,VIS_FAR_CLIP);
|
|
REF_PTR_RELEASE(camera);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Vis_Render_And_Scan -- Renders the scene and scans for visible objects *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void PhysicsSceneClass::Vis_Render_And_Scan(VisRenderContextClass & context,VisSampleClass & vis_sample)
|
|
{
|
|
/*
|
|
** Have the static culling system evaluate visibility for the occluders
|
|
** and build the z-buffer in the process.
|
|
*/
|
|
WWASSERT(context.VisRasterizer != NULL);
|
|
context.VisRasterizer->Set_Render_Mode(IDBufferClass::OCCLUDER_MODE);
|
|
StaticCullingSystem->Evaluate_Occluder_Visibility(context,vis_sample);
|
|
|
|
On_Vis_Occluders_Rendered(context,vis_sample);
|
|
|
|
/*
|
|
** Evaluate the visibility of the non-occluders in all systems
|
|
*/
|
|
if (!vis_sample.Sample_Rejected()) {
|
|
context.VisRasterizer->Set_Render_Mode(IDBufferClass::NON_OCCLUDER_MODE);
|
|
StaticCullingSystem->Evaluate_Non_Occluder_Visibility(context,vis_sample);
|
|
DynamicObjVisSystem->Evaluate_Non_Occluder_Visibility(context);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Generate_Vis_Statistics_Report -- Stats about the visibility in the leve *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void PhysicsSceneClass::Generate_Vis_Statistics_Report(DynamicVectorClass<VisSectorStatsClass> & report)
|
|
{
|
|
/*
|
|
** Loop over each of the vis sectors in the level, adding up how many polygons and
|
|
** and how much texture memory can be seen from each one.
|
|
*/
|
|
VisSectorStatsClass stats;
|
|
RefPhysListIterator it(&StaticObjList);
|
|
|
|
for (it.First(); !it.Is_Done(); it.Next()) {
|
|
StaticPhysClass * obj = it.Peek_Obj()->As_StaticPhysClass();
|
|
if (obj && obj->Is_Vis_Sector()) {
|
|
VisTableClass * vistbl = VisTableManager.Get_Vis_Table(obj->Get_Vis_Sector_ID());
|
|
stats.Compute_Stats(obj,vistbl);
|
|
report.Add(stats);
|
|
REF_PTR_RELEASE(vistbl);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Optimize_Visibility_Data -- combines and removes redundant vis data *
|
|
* *
|
|
* This function does three things. *
|
|
* - The dynamic object AABTree removes useless leaf nodes (nodes with visibility identical *
|
|
* to their parent) *
|
|
* - All vis "objects" are checked and combined if their visibility is nearly the same *
|
|
* - All vis "sectors" are checked and combined if their visibility is nearly the same *
|
|
* *
|
|
* INPUT: *
|
|
* progress_status - class the the physics scene will update as the process proceeds. *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void PhysicsSceneClass::Optimize_Visibility_Data(VisOptProgressClass & stats)
|
|
{
|
|
|
|
/*
|
|
** Initialize the progress_status.
|
|
** I'm goint to count one operation per each of the following
|
|
** - each node in the dynamic aabtree for the "Prune_Redundant_Leaf_Nodes" process
|
|
** - each vis object for the "Combine_Redundant_Vis_Objects" process
|
|
** - each vis sector for the "Combine_Redundant_Vis_Sectors" process
|
|
*/
|
|
stats.Reset(DynamicObjVisSystem->Partition_Node_Count() + Get_Vis_Table_Size() + Get_Vis_Table_Count());
|
|
stats.Set_Initial_Bit_Count(VisTableManager.Get_Vis_Table_Size() * VisTableManager.Get_Vis_Table_Count());
|
|
stats.Set_Initial_Sector_Count(Get_Vis_Table_Count());
|
|
stats.Set_Initial_Object_Count(Get_Vis_Table_Size());
|
|
stats.Set_Initial_Dynamic_Cell_Count(DynamicObjVisSystem->Partition_Node_Count());
|
|
|
|
/*
|
|
** Create a VisOptimizationContextClass and optimize the vis data
|
|
*/
|
|
VisOptimizationContextClass optcontext(this,stats);
|
|
optcontext.Optimize(&VisTableManager,DynamicObjVisSystem);
|
|
|
|
/*
|
|
** Reset all of dynamic objects' cached vis-ID and cull node.
|
|
*/
|
|
RefPhysListIterator it(&ObjList);
|
|
|
|
for (it.First(); !it.Is_Done(); it.Next()) {
|
|
DynamicPhysClass * obj = it.Peek_Obj()->As_DynamicPhysClass();
|
|
if (obj != NULL) {
|
|
obj->Update_Visibility_Status();
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Finish the statistics
|
|
*/
|
|
stats.Set_Final_Bit_Count(VisTableManager.Get_Vis_Table_Size() * VisTableManager.Get_Vis_Table_Count());
|
|
stats.Set_Final_Sector_Count(Get_Vis_Table_Count());
|
|
stats.Set_Final_Object_Count(Get_Vis_Table_Size());
|
|
stats.Set_Final_Dynamic_Cell_Count(DynamicObjVisSystem->Partition_Node_Count());
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Merge_Vis_Sector_IDs -- Merges two sector ID's *
|
|
* *
|
|
* The greater ID will be set equal to the lesser ID. This should only be called by the *
|
|
* vis optimization process and relies on a VisOptimizationContext to track the changes *
|
|
* to the actual VIS bit vectors. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void PhysicsSceneClass::Merge_Vis_Sector_IDs(uint32 id0,uint32 id1)
|
|
{
|
|
StaticCullingSystem->Merge_Vis_Sector_IDs(id0,id1);
|
|
StaticLightingSystem->Merge_Vis_Sector_IDs(id0,id1);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* PhysicsSceneClass::Merge_Vis_Object_IDs -- combines two vis object ID's *
|
|
* *
|
|
* The greater ID will be set equal to the lesser ID. This should only be called by the *
|
|
* vis optimization process and relies on a VisOptimizationContext to track the changes *
|
|
* to the actual VIS bit vectors. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 7/5/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void PhysicsSceneClass::Merge_Vis_Object_IDs(uint32 id0,uint32 id1)
|
|
{
|
|
StaticCullingSystem->Merge_Vis_Object_IDs(id0,id1);
|
|
DynamicObjVisSystem->Merge_Vis_Object_IDs(id0,id1);
|
|
}
|