| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840 |
- /*
- ** 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 : LevelEdit *
- * *
- * $Archive:: /Commando/Code/wwphys/PathfindSectorBuilder.cpp $Revision:: 2 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "stdafx.h"
- #include "pathfindsectorbuilder.h"
- #include "phys3.h"
- #include "filemgr.h"
- #include "editorassetmgr.h"
- #include "_assetmgr.h"
- #include "humanphys.h"
- #include "utils.h"
- #include "editorphys.h"
- #include "collisiongroups.h"
- #include "sceneeditor.h"
- #include "boxrobj.h"
- #include "pathfind.h"
- #include "systimer.h"
- //////////////////////////////////////////////////////////////////////////
- // Static member initialization
- //////////////////////////////////////////////////////////////////////////
- BodyBoxCullObj *BodyBoxCullObj::m_First = NULL;
- //////////////////////////////////////////////////////////////////////////
- // Local constants
- //////////////////////////////////////////////////////////////////////////
- class SimDirInfoClass
- {
- public:
- SimDirInfoClass (void) { }
- SimDirInfoClass (float _heading, float _speed, const Vector3 &_move, const Vector3 &min, const Vector3 &max)
- : heading (_heading), speed (_speed), move (_move), min_move (min), max_move (max) { }
- float heading;
- float speed;
- Vector3 move;
- Vector3 min_move;
- Vector3 max_move;
- };
- /*const SIM_DIR_INFO DIR_INFO[DIR_MAX] =
- {
- SIM_DIR_INFO ( 0.0F, Vector3 ( 0.9F, -0.1F, -1.5F), Vector3 ( 2.0F, 0.1F, 1.5F) ),
- SIM_DIR_INFO ( (float)DEG_TO_RAD (90), Vector3 (-0.1F, 0.9F, -1.5F), Vector3 ( 0.1F, 2.0F, 1.5F) ),
- SIM_DIR_INFO ( (float)DEG_TO_RAD (180), Vector3 (-2.0F, -0.1F, -1.5F), Vector3 (-0.9F, 0.1F, 1.5F) ),
- SIM_DIR_INFO ( (float)DEG_TO_RAD (270), Vector3 (-0.1F, -2.0F, -1.5F), Vector3 ( 0.1F, -0.9F, 1.5F) )
- };*/
- //
- // Note: The vector members are in "percentage of bounding box" units.
- //
- static const SimDirInfoClass DIR_INFO[DIR_MAX] =
- {
- SimDirInfoClass ( 0.0F, 0, Vector3 ( 1.0F, 0, 0), Vector3 ( 0.95F, -0.05F, -2.0F), Vector3 ( 1.2F, 0.05F, 2.0F) ),
- SimDirInfoClass ( (float)DEG_TO_RAD (90), 0, Vector3 ( 0, 1.0F, 0), Vector3 (-0.05F, 0.95F, -2.0F), Vector3 ( 0.05F, 1.2F, 2.0F) ),
- SimDirInfoClass ( (float)DEG_TO_RAD (180), 0, Vector3 (-1.0F, 0, 0), Vector3 ( -1.2F, -0.05F, -2.0F), Vector3 (-0.95F, 0.05F, 2.0F) ),
- SimDirInfoClass ( (float)DEG_TO_RAD (270), 0, Vector3 ( 0, -1.0F, 0), Vector3 (-0.05F, -1.2F, -2.0F), Vector3 ( 0.05F, -0.95F, 2.0F) )
- };
- //////////////////////////////////////////////////////////////////////////
- //
- // PathfindSectorBuilderClass
- //
- //////////////////////////////////////////////////////////////////////////
- PathfindSectorBuilderClass::PathfindSectorBuilderClass (void)
- : m_PhysicsSim (NULL),
- m_RecurseLevel (0),
- m_RepartitionCount (0),
- m_CurrentSector (NULL),
- m_SimBoundingBox (Vector3 (0.5F, 0.5F, 1.8F)),
- m_DirInfo (NULL),
- m_bCancel (false)
- {
- //
- // Create an instance of the commando render object we can
- // use to simulate character movement
- //
- CString full_path;
- full_path = Get_File_Mgr ()->Make_Full_Path ("Characters\\Commando");
- _pThe3DAssetManager->Set_Current_Directory (full_path);
- RenderObjClass *commando_obj = WW3DAssetManager::Get_Instance()->Create_Render_Obj ("COMMANDO");
- if (commando_obj != NULL) {
- //
- // Attempt to find the collision box for this physics object
- //
- RenderObjClass *collision_box = NULL;
- if (commando_obj->Class_ID () == RenderObjClass::CLASSID_DISTLOD) {
- RenderObjClass *lod0 = commando_obj->Get_Sub_Object(0);
- collision_box = lod0->Get_Sub_Object_By_Name ("WORLDBOX");
- MEMBER_RELEASE (lod0);
- } else {
- collision_box = commando_obj->Get_Sub_Object_By_Name ("WORLDBOX");
- }
- //
- // Store the exents of the collision box for use in our simulation
- //
- if (collision_box != NULL) {
- const AABoxClass &box = collision_box->Get_Bounding_Box ();
- m_SimBoundingBox = box.Extent * 2;
- MEMBER_RELEASE (collision_box);
- }
- //
- // Build an array of simulation information (specific to this
- // physics object).
- //
- m_DirInfo = new SimDirInfoClass[DIR_MAX];
- for (int index = 0; index < DIR_MAX; index ++) {
- m_DirInfo[index] = DIR_INFO[index];
- m_DirInfo[index].move.X *= m_SimBoundingBox.X;
- m_DirInfo[index].move.Y *= m_SimBoundingBox.Y;
- m_DirInfo[index].move.Z *= m_SimBoundingBox.Z;
- m_DirInfo[index].min_move.X *= m_SimBoundingBox.X;
- m_DirInfo[index].min_move.Y *= m_SimBoundingBox.Y;
- m_DirInfo[index].min_move.Z *= m_SimBoundingBox.Z;
- m_DirInfo[index].max_move.X *= m_SimBoundingBox.X;
- m_DirInfo[index].max_move.Y *= m_SimBoundingBox.Y;
- m_DirInfo[index].max_move.Z *= m_SimBoundingBox.Z;
- m_DirInfo[index].speed = m_DirInfo[index].move.Length ();
- }
- //
- // Create the physics object we will use for character simulation
- //
- m_PhysicsSim = new HumanPhysClass;
- m_PhysicsSim->Set_Model (commando_obj);
- m_PhysicsSim->Set_Controller (&m_Controller);
- m_PhysicsSim->Set_Collision_Group (0);
- MEMBER_RELEASE (commando_obj);
- //
- // Setup the culling system for the boxes.
- //
- float max_extent = max (m_SimBoundingBox.X, m_SimBoundingBox.Y);
- max_extent = max (m_SimBoundingBox.Z, max_extent);
- Vector3 min;
- Vector3 max;
- PhysicsSceneClass::Get_Instance ()->Get_Level_Extents (min, max);
- m_BodyBoxCullingSystem.Re_Partition (min, max, max_extent * 5);
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // ~PathfindSectorBuilderClass
- //
- //////////////////////////////////////////////////////////////////////////
- PathfindSectorBuilderClass::~PathfindSectorBuilderClass (void)
- {
- //MEMBER_RELEASE (m_PhysicsSim);
- Free_Sectors ();
- SAFE_DELETE_ARRAY (m_DirInfo);
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Generate_Sectors
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Generate_Sectors (const Vector3 &start_pos)
- {
- bool sectors_displayed = PathfindClass::Get_Instance ()->Are_Sectors_Displayed ();
- bool portals_displayed = PathfindClass::Get_Instance ()->Are_Portals_Displayed ();
- PathfindClass::Get_Instance ()->Display_Sectors (false);
- PathfindClass::Get_Instance ()->Display_Portals (false);
- //
- // Start fresh
- //
- Free_Sectors ();
- PathfindClass::Get_Instance ()->Reset_Sectors ();
- Import_Raw_Data ();
- m_RecurseLevel = 0;
- m_RepartitionCount = 0;
- m_bCancel = false;
- //
- // Normalize the starting position. We do this so that we can start as many
- // different 'generations' in the world and they will all match up perfectly.
- //
- Vector3 normalized_start_pos = start_pos;
- normalized_start_pos.X = (int(start_pos.X / m_SimBoundingBox.X)) * m_SimBoundingBox.X;
- normalized_start_pos.Y = (int(start_pos.Y / m_SimBoundingBox.Y)) * m_SimBoundingBox.Y;
- //
- // Start flood filling from the given position
- //
- m_CurrentSector = Mark_Sector (normalized_start_pos);
- Floodfill (normalized_start_pos);
- DWORD start_ticks = TIMEGETTIME ();
- //
- // Process all the sectors in our queue
- //
- while (m_FloodFillProcessList.Count () > 0) {
- m_CurrentSector = m_FloodFillProcessList[0];
- m_FloodFillProcessList.Delete (0);
- Floodfill (m_CurrentSector->Get_Transform ().Get_Translation ());
- m_bCancel = ((TIMEGETTIME () - start_ticks) > 20000000L);
- }
- //
- // Compress the sectors into the largest possible rectangular regions
- //
- DWORD before_ticks = TIMEGETTIME ();
- Compress_Sectors ();
- DWORD after_ticks = TIMEGETTIME ();
- CString message;
- message.Format ("Time spent compressing: %d secs.\r\n", (after_ticks-before_ticks)/1000);
- ::Ouput_Message (message);
- //
- // Add the sectors to our global pathfind object
- //
- for (int index = 0; index < m_SectorList.Count (); index ++) {
- PathfindSectorClass *sector = m_SectorList[index];
- if (sector->Is_Valid ()) {
- PathfindClass::Get_Instance ()->Add_Sector (sector);
- }
- }
- //
- // Turn the debug display back on if necessary
- //
- PathfindClass::Get_Instance ()->Display_Sectors (sectors_displayed);
- PathfindClass::Get_Instance ()->Display_Portals (portals_displayed);
- return ;
- }
- float Re_Orient_Vector (const Vector3 &pos, const Vector3 &look_at)
- {
- float dx = (look_at[0] - pos[0]);
- float dy = (look_at[1] - pos[1]);
- float len = (float)sqrt(dx*dx + dy*dy);
- float angle = 0;
- if (fabs (dx) >= fabs(dy)) {
- double cosy = 0;
- if (len != 0.0f) {
- cosy = dx/len;
- } else {
- cosy = 1.0f;
- }
- angle = ::acos (cosy);
- } else {
- double siny = 0;
- if (len != 0.0f) {
- siny = dy/len;
- } else {
- siny = 0.0f;
- }
- angle = ::asin (siny);
- }
- return angle;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Do_Physics_Sim
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Do_Physics_Sim
- (
- const Vector3 & start_pos,
- PATHFIND_DIR direction
- )
- {
- //
- // Position the physics object at the test location
- //
- Matrix3D transform (start_pos);
- m_PhysicsSim->Set_Transform (transform);
- //
- // Determine how far the simulation can move in each of the 3 directions
- // and still be considered 'valid'.
- //
- Vector3 expected_move = m_DirInfo[direction].move;
- Vector3 min_exceptable_move = m_DirInfo[direction].min_move;
- Vector3 max_exceptable_move = m_DirInfo[direction].max_move;
- //
- // Set-up the simulation to move one 'step' in the given direction
- //
- m_Controller.Reset ();
- m_Controller.Set_Move_Forward (1);
- m_PhysicsSim->Set_Normalized_Speed (m_DirInfo[direction].speed);
- m_PhysicsSim->Set_Heading (m_DirInfo[direction].heading);
- Vector3 expected_pos = start_pos + expected_move;
- //
- // Do the simulation
- //
- Vector3 new_pos;
- Vector3 move_vector;
- bool found = false;
- bool on_ground = false;
- #if 0
- bool should_continue = true;
- for (int attempt = 0; (attempt < 50) && should_continue; attempt ++) {
- //
- // Break the physics timestep down into small steps (however
- // make sure it processes for exactly 1 sec).
- //
- for (int index = 0; index < 2; index ++) {
- m_PhysicsSim->Timestep (0.05F);
- }
- new_pos = m_PhysicsSim->Get_Position ();
- move_vector = new_pos - start_pos;
- //
- // Did we move into the expected range?
- //
- if ((move_vector.X >= min_exceptable_move.X) &&
- (move_vector.Y >= min_exceptable_move.Y) &&
- (move_vector.Z >= min_exceptable_move.Z) &&
- (move_vector.X <= max_exceptable_move.X) &&
- (move_vector.Y <= max_exceptable_move.Y) &&
- (move_vector.Z <= max_exceptable_move.Z))
- {
- should_continue = false;
- found = true;
- } else {
- float angle = Re_Orient_Vector (new_pos, expected_pos);
- m_PhysicsSim->Set_Heading (angle);
- }
- }
- on_ground = m_PhysicsSim->Is_In_Contact ();
- #else
- float half_height = m_SimBoundingBox.Z * 0.5F;
- float movement = (4.9F + (m_SimBoundingBox.Z * 0.15F));
- //m_PhysicsSim->Set_Transform (Matrix3D (expected_pos));
- AABoxClass box;
- box.Center = expected_pos;
- box.Center.Z += (m_SimBoundingBox.Z * 0.75F);
- box.Extent.X = m_SimBoundingBox.X * 0.5F;
- box.Extent.Y = m_SimBoundingBox.Y * 0.5F;
- box.Extent.Z = half_height;
- CastResultStruct result;
- PhysAABoxCollisionTestClass test( box,
- Vector3 (0, 0, -movement),
- &result,
- m_PhysicsSim->Get_Collision_Group (),
- COLLISION_TYPE_PHYSICAL);
- PhysicsSceneClass::Get_Instance ()->Cast_AABox (test);
- found = (result.StartBad == false) && (result.Normal.Z > 0.7F);
- if (found) {
- on_ground = (result.Fraction < 1.0F);
- new_pos.Z = box.Center.Z - half_height - (movement * result.Fraction) + 0.001F;
- } else {
- int test = 0;
- }
- #endif
- if (found && on_ground) {
- //
- // Force the x and y values to snap to the expected position
- //
- new_pos.X = start_pos.X + expected_move.X;
- new_pos.Y = start_pos.Y + expected_move.Y;
- //
- // Is this cell already marked?
- //
- BodyBoxCullObj *occupant = Get_Sector_Occupant (new_pos);
- if (occupant == NULL) {
- //
- // Mark this cell and add it to the list of sectors
- // that need to be recursed.
- //
- occupant = Mark_Sector (new_pos);
- m_FloodFillProcessList.Add (occupant);
- }
- //
- // Let the sector know who its new neighbor is
- //
- if (occupant != m_CurrentSector) {
- m_CurrentSector->Set_Neighbor (direction, occupant);
- }
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Floodfill
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Floodfill (const Vector3 &start_pos)
- {
- //
- // Do a simulation in each of the four directions from the
- // current cell.
- //
- if (m_bCancel == false) {
- Do_Physics_Sim (start_pos, DIR_FORWARD);
- Do_Physics_Sim (start_pos, DIR_LEFT);
- Do_Physics_Sim (start_pos, DIR_BACKWARD);
- Do_Physics_Sim (start_pos, DIR_RIGHT);
- //
- // Let the current sector 'know' its been completely processed
- //
- m_CurrentSector->Needs_Processing (false);
- }
- //
- // Allow the user to cancel this operation
- //
- if (!m_bCancel && (::GetAsyncKeyState (VK_ESCAPE) < 0)) {
- m_bCancel = true;
- ::MessageBox (NULL, "Operation cancelled.", "Pathfind", MB_OK | MB_SETFOREGROUND);
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Get_Sector_Occupant
- //
- //////////////////////////////////////////////////////////////////////////
- BodyBoxCullObj *
- PathfindSectorBuilderClass::Get_Sector_Occupant (const Vector3 &pos)
- {
- Vector3 box_center_pos = pos;
- //box_center_pos.Z += (m_SimBoundingBox.Z * 0.1F);
- //
- // Collect all the objects in our culling system that occupy the
- // given point
- //
- m_BodyBoxCullingSystem.Reset_Collection ();
- m_BodyBoxCullingSystem.Collect_Objects (box_center_pos);
- BodyBoxCullObj *body_box = m_BodyBoxCullingSystem.Get_First_Collected_Object ();
- if (body_box == NULL) {
- box_center_pos = pos;
- box_center_pos.Z += (m_SimBoundingBox.Z * 0.25F);
- m_BodyBoxCullingSystem.Reset_Collection ();
- m_BodyBoxCullingSystem.Collect_Objects (box_center_pos);
- body_box = m_BodyBoxCullingSystem.Get_First_Collected_Object ();
- }
- if (body_box == NULL) {
- box_center_pos = pos;
- box_center_pos.Z += (m_SimBoundingBox.Z * 0.5F);
- m_BodyBoxCullingSystem.Reset_Collection ();
- m_BodyBoxCullingSystem.Collect_Objects (box_center_pos);
- body_box = m_BodyBoxCullingSystem.Get_First_Collected_Object ();
- }
- //
- // If we found any objects in the culling system, then the sector is occupied
- //
- return body_box;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Mark_Sector
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Mark_Sector (BodyBoxCullObj *body_box)
- {
- //
- // Add the culling object to our AABTree culling system. (This
- // effectively marks the cell as 'occupied').
- //
- body_box->Add_Ref ();
- m_BodyBoxCullingSystem.Add_Object (body_box);
- BodyBoxCullObj::Add (body_box);
- //
- // Repartition the culling system every few hundred
- // entries.
- //
- /*m_RepartitionCount ++;
- if (m_RepartitionCount > 1000) {
- m_RepartitionCount = 0;
- m_BodyBoxCullingSystem.Re_Partition ();
- }*/
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Mark_Sector
- //
- //////////////////////////////////////////////////////////////////////////
- BodyBoxCullObj *
- PathfindSectorBuilderClass::Mark_Sector (const Vector3 &pos)
- {
- //
- // Create a culling system object to represent this 'sector' and
- // add it to our AABTree culling system. (This effectively marks
- // the cell as 'occupied').
- //
- BodyBoxCullObj *body_box = new BodyBoxCullObj;
- AABoxClass box;
- box.Center = pos;
- box.Extent.X = m_SimBoundingBox.X * 0.5F;
- box.Extent.Y = m_SimBoundingBox.Y * 0.5F;
- box.Extent.Z = m_SimBoundingBox.Z * 0.5F;
- body_box->Set_Bounding_Box (box);
- body_box->Init_Transform (pos);
- Mark_Sector (body_box);
- body_box->Release_Ref ();
- return body_box;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Compress_Sectors
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Compress_Sectors (void)
- {
- BODY_BOX_LIST body_box_list;
- int sectors = 0;
- int largest_area = 0;
- int largest_area_right = 0;
- int largest_area_down = 0;
- BodyBoxCullObj *upper_left_ptr = NULL;
- //
- // Keep looping until we've compressed all the body boxes into sectors
- //
- while (BodyBoxCullObj::Get_First () != NULL) {
- //
- // Find the largest possible rectangular area that's 'free'
- // in the world.
- //
- largest_area = 0;
- for ( BodyBoxCullObj *cull_obj = BodyBoxCullObj::Get_First ();
- cull_obj != NULL;
- cull_obj = cull_obj->Get_Next ())
- {
- int max_down = 0;
- int max_right = 0;
- int max_area = 0;
- int curr_down = 65536;
- int curr_right = 1;
- //
- // Find the largest rectangular area that this box is the upper-left
- // corner for.
- //
- BodyBoxCullObj *neighbor = cull_obj;
- Vector3 pos = cull_obj->Get_Position ();
- float min_z_pos = pos.Z - m_SimBoundingBox.Z;
- float max_z_pos = pos.Z + (m_SimBoundingBox.Z * 1.5F);
- while (neighbor != NULL)
- {
- curr_down = min (neighbor->Get_Count (DIR_BACKWARD, min_z_pos, max_z_pos) + 1, curr_down);
- //
- // Determine if this region (right x down) contains the
- // largest area so far.
- //
- int area = (curr_down * curr_right);
- if (area > max_area) {
- max_area = area;
- max_down = curr_down;
- max_right = curr_right;
- }
- //
- // Move to the next cell to the right
- //
- curr_right ++;
- neighbor = neighbor->Next_Valid (DIR_RIGHT, min_z_pos, max_z_pos);
- }
- if (max_area > largest_area) {
- upper_left_ptr = cull_obj;
- largest_area = max_area;
- largest_area_right = max_right;
- largest_area_down = max_down;
- }
- }
- //
- // Debug info
- //
- if (largest_area > 1) {
- CString message;
- message.Format ("Combining cells: width = %d, height = %d, area = %d\r\n", largest_area_right, largest_area_down, largest_area);
- ::Ouput_Message (message);
- sectors ++;
- }
- Vector3 min_point (100000, 100000, 100000);
- Vector3 max_point (-100000, -100000, -100000);
- PathfindSectorClass *sector = new PathfindSectorClass;
- //
- // Remove all the cells that compose this area from the list
- //
- BodyBoxCullObj *curr_cell = upper_left_ptr;
- for (int right = 0; (right < largest_area_right) && (curr_cell != NULL); right ++) {
- BodyBoxCullObj *down_obj = curr_cell;
- for (int down = 0; (down < largest_area_down) && (down_obj != NULL); down ++) {
- Matrix3D transform = down_obj->Get_Transform ();
- Vector3 position = transform.Get_Translation ();
- min_point.X = min (min_point.X, position.X - (m_SimBoundingBox.X / 2));
- min_point.Y = min (min_point.Y, position.Y - (m_SimBoundingBox.Y / 2));
- min_point.Z = min (min_point.Z, position.Z);
- max_point.X = max (max_point.X, position.X + (m_SimBoundingBox.X / 2));
- max_point.Y = max (max_point.Y, position.Y + (m_SimBoundingBox.Y / 2));
- max_point.Z = max (max_point.Z, position.Z + m_SimBoundingBox.Z);
- ASSERT (down_obj->Is_Taken () == false);
- down_obj->Set_Sector (sector);
- body_box_list.Add (down_obj);
- down_obj->Remove ();
- down_obj->Set_Taken ();
- down_obj = down_obj->Peek_Neighbor (DIR_BACKWARD);
- }
- curr_cell = curr_cell->Peek_Neighbor (DIR_RIGHT);
- }
- //
- // Sumbit this sector
- //
- if (largest_area > 1) {
- AABoxClass bounding_box;
- bounding_box.Center = min_point + ((max_point - min_point) / 2.0F);
- bounding_box.Extent.X = (max_point.X - min_point.X) / 2;
- bounding_box.Extent.Y = (max_point.Y - min_point.Y) / 2;
- bounding_box.Extent.Z = (max_point.Z - min_point.Z) / 2;
- sector->Set_Bounding_Box (bounding_box);
- m_SectorList.Add (sector);
- } else {
- sector->Set_Valid (false);
- m_SectorList.Add (sector);
- }
- }
- //
- // Build portals
- //
- for (int index = 0; index < body_box_list.Count (); index ++) {
- BodyBoxCullObj *cull_obj = body_box_list[index];
- PathfindSectorClass *sector = cull_obj->Peek_Sector ();
- if (sector->Is_Valid ()) {
- //
- // Make portals out of this box for any of the four directions
- //
- for (int dir = 0; dir < DIR_MAX; dir ++) {
- if (cull_obj->Is_New_Portal ((PATHFIND_DIR)dir)) {
- PathfindPortalClass *portal = cull_obj->Make_Portal ((PATHFIND_DIR)dir, m_SimBoundingBox);
- sector->Add_Portal (portal);
- }
- }
- }
- }
- //
- // Free the body box culling objects
- //
- for (index = 0; index < body_box_list.Count (); index ++) {
- //
- // Remove the body box from the culling system
- //
- BodyBoxCullObj *cull_obj = body_box_list[index];
- m_BodyBoxCullingSystem.Remove_Object (cull_obj);
- //
- // Save the body box in the global list so we can combine
- // generated sections later (if we want). Also usefull
- // for debugging purposes.
- //
- cull_obj->Reset_Portal_Info ();
- cull_obj->Set_Taken (false);
- cull_obj->Set_Sector (NULL);
- PathfindClass::Get_Instance ()->Add_Body_Box (cull_obj);
- MEMBER_RELEASE (cull_obj);
- }
- body_box_list.Delete_All ();
- //
- // Debug info
- //
- CString message;
- message.Format ("Total sectors: %d\r\n", sectors);
- ::Ouput_Message (message);
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Free_Sectors
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Free_Sectors (void)
- {
- //
- // Free all the sector objects
- //
- for (int index = 0; index < m_SectorList.Count (); index ++) {
- PathfindSectorClass *sector = m_SectorList[index];
- MEMBER_RELEASE (sector);
- }
- m_SectorList.Delete_All ();
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Import_Raw_Data
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Import_Raw_Data (void)
- {
- BODY_BOX_LIST &raw_list = PathfindClass::Get_Instance ()->Get_Raw_Data ();
- //
- // Add all the body boxes from a previous build to the system.
- //
- for (int index = 0; index < raw_list.Count (); index ++) {
- BodyBoxCullObj *body_box = raw_list[index];
- Mark_Sector (body_box);
- //
- // Add this box to our process queue if it wasn't processed
- // the first time around.
- //
- if (body_box->Needs_Processing ()) {
- m_FloodFillProcessList.Add (body_box);
- }
- }
- PathfindClass::Get_Instance ()->Reset_Generated_Data ();
- return ;
- }
|