/* ** 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; }