/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WWPhys *
* *
* $Archive:: /Commando/Code/wwphys/visoptimizationcontext.cpp $*
* *
* Original Author:: Greg Hjelstrom *
* *
* $Author:: Patrick $*
* *
* $Modtime:: 11/16/00 7:31p $*
* *
* $Revision:: 12 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "visoptimizationcontext.h"
#include "visoptprogress.h"
#include "pscene.h"
#include "vistablemgr.h"
#include "vistable.h"
#include "dynamicaabtreecull.h"
#include "wwdebug.h"
const float MIN_OBJECT_MATCH_FRACTION = 0.99f;
const float MIN_SECTOR_MATCH_FRACTION = 0.99f;
const float MIN_PRUNE_MATCH_FRACTION = 0.90f;
/***************************************************************************************************
**
** PVSInfoStruct Implementation
**
***************************************************************************************************/
VisOptimizationContextClass::PVSInfoStruct::PVSInfoStruct(void) :
Table(NULL),
UnUsed(false)
{
}
VisOptimizationContextClass::PVSInfoStruct::~PVSInfoStruct(void)
{
REF_PTR_RELEASE(Table);
}
const VisOptimizationContextClass::PVSInfoStruct &
VisOptimizationContextClass::PVSInfoStruct::operator = (const PVSInfoStruct & that)
{
REF_PTR_SET(Table,that.Table);
UnUsed = that.UnUsed;
return *this;
}
/***************************************************************************************************
**
** VisOptimizationContextClass Implementation
**
***************************************************************************************************/
VisOptimizationContextClass::VisOptimizationContextClass
(
PhysicsSceneClass * scene,
VisOptProgressClass & stats
) :
MinDynCellPruneMatchFraction(MIN_PRUNE_MATCH_FRACTION),
MinVisObjectMatchFraction(MIN_OBJECT_MATCH_FRACTION),
MinVisSectorMatchFraction(MIN_SECTOR_MATCH_FRACTION),
Scene(scene),
Stats(stats)
{
WWASSERT(Scene != NULL);
}
VisOptimizationContextClass::~VisOptimizationContextClass(void)
{
}
float VisOptimizationContextClass::Compute_Sector_Table_Match_Fraction(int sector_id_0,int sector_id_1)
{
if (SectorTables[sector_id_0].UnUsed || SectorTables[sector_id_1].UnUsed) {
return 0.0f;
}
return SectorTables[sector_id_0].Table->Match_Fraction(*(SectorTables[sector_id_1].Table));
}
float VisOptimizationContextClass::Compute_Object_Table_Match_Fraction(int object_id_0,int object_id_1)
{
return ObjectTables[object_id_0].Table->Match_Fraction(*(ObjectTables[object_id_1].Table));
}
void VisOptimizationContextClass::Optimize
(
VisTableMgrClass * vis_mgr,
DynamicAABTreeCullClass * dyn_obj_tree
)
{
/*
** Generate the object tables
*/
Build_Object_Tables(vis_mgr);
/*
** Prune redundant leaves of the dynamic object culling tree. This operation actually
** deletes leaf nodes from the tree.
*/
dyn_obj_tree->Prune_Redundant_Leaf_Nodes(*this);
/*
** Combine the redundant objects. This operation combines objects by assigning the
** same vis ID to both of them.
*/
Combine_Redundant_Objects();
/*
** Now that we're done combining objects, build new sector tables so that we
** can remove the redundant vis sectors. Each table will have a bitcount
** equal to the number of object tables.
*/
Build_Sector_Tables_From_Object_Tables(vis_mgr);
/*
** Now combine the redundant sectors
*/
Combine_Redundant_Sectors();
/*
** All done, so install the results
*/
Install_Results(vis_mgr);
}
void VisOptimizationContextClass::Build_Object_Tables(VisTableMgrClass * vis_mgr)
{
/*
** Generate the object tables (what sectors can see each object). Consider the sector
** tables columns and the object tables rows of the same 2D grid of visibility bits.
*/
int i,j;
int sector_count = vis_mgr->Get_Vis_Table_Count();
int object_count = vis_mgr->Get_Vis_Table_Size();
ObjectTables.Resize(object_count);
for (i=0; iGet_Vis_Table(i);
if (sector_table == NULL) {
sector_table = NEW_REF(VisTableClass,(object_count,0));
sector_table->Reset_All();
}
/*
** Copy its bits into the object tables
*/
for (j=0; jSet_Bit(i,sector_table->Get_Bit(j) != 0);
}
/*
** Release it
*/
REF_PTR_RELEASE(sector_table);
}
}
void VisOptimizationContextClass::Combine_Redundant_Objects(void)
{
int i,j;
for (i=0; iMatch_Fraction(*(ObjectTables[j].Table));
if (frac > MinVisObjectMatchFraction) {
Combine_Object_Tables(i,j);
Stats.Increment_Objects_Merged();
j--;
}
}
Stats.Increment_Completed_Operations();
REF_PTR_RELEASE (table_i);
}
}
void VisOptimizationContextClass::Build_Sector_Tables_From_Object_Tables(VisTableMgrClass * vis_mgr)
{
int i,j;
for (i=0; iGet_Vis_Table_Count(); i++) {
PVSInfoStruct sectorinfo;
sectorinfo.Table = NEW_REF(VisTableClass,(ObjectTables.Count(),0));
sectorinfo.UnUsed = (vis_mgr->Has_Vis_Table(i) == false);
for (j=0; jSet_Bit(j,(ObjectTables[j].Table->Get_Bit(i) != 0));
}
SectorTables.Add(sectorinfo);
}
}
void VisOptimizationContextClass::Combine_Redundant_Sectors(void)
{
int i,j;
for (i=0; iMatch_Fraction(*(SectorTables[j].Table));
if (frac > MinVisSectorMatchFraction) {
Combine_Sector_Tables(i,j);
Stats.Increment_Sectors_Merged();
j--;
}
}
Stats.Increment_Completed_Operations(1);
REF_PTR_RELEASE (table_i);
}
}
void VisOptimizationContextClass::Combine_Sector_Tables(int sector_id_0,int sector_id_1)
{
/*
** Sort the given id's into ascending order
*/
int id0 = sector_id_0;
int id1 = sector_id_1;
if (id0 > id1) {
int tmp = id0;
id0 = id1;
id1 = tmp;
}
/*
** Merge the second table into the first.
*/
SectorTables[id0].Table->Merge(*(SectorTables[id1].Table));
SectorTables.Delete(id1);
#if 0
/*
** Remove the id1'th bit from each object_table
*/
for (int i=0; iDelete_Bit(id1);
}
#endif
/*
** Tell the physics scene to merge any sector with id1 into id0
*/
Scene->Merge_Vis_Sector_IDs(id0,id1);
}
void VisOptimizationContextClass::Combine_Object_Tables(int object_id_0,int object_id_1)
{
/*
** Sort the given id's into ascending order
*/
int id0 = object_id_0;
int id1 = object_id_1;
if (id0 > id1) {
int tmp = id0;
id0 = id1;
id1 = tmp;
}
/*
** Merge the second table into the first
*/
ObjectTables[id0].Table->Merge(*(ObjectTables[id1].Table));
ObjectTables.Delete(id1);
#if 0
/*
** Remove the id1'th bit from each sector table
*/
for (int i=0; iDelete_Bit(id1);
}
#endif
/*
** Tell the physics scene to merge any object with id1 into id0
*/
Scene->Merge_Vis_Object_IDs(id0,id1);
}
void VisOptimizationContextClass::Install_Results(VisTableMgrClass * vismgr)
{
if (vismgr == NULL) {
WWDEBUG_SAY(("Error! NULL VisTableMgrClass passed into Install_Results\n"));
return;
}
/*
** First, reset the contents of the vis manager
*/
vismgr->Reset();
/*
** Allocate the ID's needed (which also sets the number of tables and the size of each table)
*/
vismgr->Set_Optimized_Vis_Object_Count(ObjectTables.Count());
vismgr->Allocate_Vis_Sector_ID(SectorTables.Count());
/*
** Install the Vis Tables.
*/
for (int i=0; iUpdate_Vis_Table(i,SectorTables[i].Table);
REF_PTR_RELEASE(SectorTables[i].Table);
}
}
}
int VisOptimizationContextClass::Get_Vis_Sector_Count(void)
{
return SectorTables.Count();
}
int VisOptimizationContextClass::Get_Vis_Object_Count(void)
{
return ObjectTables.Count();
}
VisOptProgressClass & VisOptimizationContextClass::Get_Progress_Object(void)
{
return Stats;
}