| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994 |
- /*
- ** 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/Pathfind.cpp $*
- * *
- * Author:: Patrick Smith *
- * *
- * $Modtime:: 10/15/01 7:44p $*
- * *
- * $Revision:: 35 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "pathfind.h"
- #include "pathfindportal.h"
- #include "path.h"
- #include "pscene.h"
- #include "boxrobj.h"
- #include "decophys.h"
- #include "mesh.h"
- #include "assetmgr.h"
- #include "chunkio.h"
- #include "wwphysids.h"
- #include "pathdebugplotter.h"
- #include "persistfactory.h"
- #include "waypath.h"
- #include "waypoint.h"
- #include "wwmemlog.h"
- #include "heightdb.h"
- #include "colmathaabox.h"
- ///////////////////////////////////////////////////////////////////////////
- // Local prototypes
- ///////////////////////////////////////////////////////////////////////////
- int __cdecl fnCompareWaypathPortalsCallback (const void *elem1, const void *elem2);
- bool Find_Intersection_Point (const AABoxClass &box, const Vector3 &p0, const Vector3 &p1, float *percent, Vector3 *intersection_point);
- void Add_New_Portal_To_List (DynamicVectorClass<PathfindWaypathPortalClass *> &portal_list, PathfindSectorClass *dest_sector1, PathfindSectorClass *dest_sector2, int waypath_id, int waypoint_index, const Vector3 &portal_pos, float percent);
- ///////////////////////////////////////////////////////////////////////////
- // Constants
- ///////////////////////////////////////////////////////////////////////////
- const int MAX_TEMP_PORTALS = 20;
- ///////////////////////////////////////////////////////////////////////////
- // Static data initialization
- ///////////////////////////////////////////////////////////////////////////
- static int _NextTempPortalID = PathfindClass::TEMP_PORTAL_ID_START;
- ///////////////////////////////////////////////////////////////////////////
- // Save/Load stuff
- ///////////////////////////////////////////////////////////////////////////
- enum
- {
- CHUNKID_DATABASE = 0x01060635,
- XXX_CHUNKID_SECTOR,
- CHUNKID_PORTAL,
- CHUNKID_SECTOR_CULLING_SYSTEM,
- CHUNKID_SECTOR,
- CHUNKID_SECTOR_CULL_TREE,
- CHUNKID_SECTOR_LINKAGE,
- CHUNKID_SECTOR_OBJECT,
- CHUNKID_HEIGHTDB,
- CHUNKID_ACTION_PORTAL,
- CHUNKID_WAYPATH_PORTAL,
- CHUNKID_PATHFIND_SECTOR_OBJECT
- };
- ///////////////////////////////////////////////////////////////////////////
- // Static member initialization
- ///////////////////////////////////////////////////////////////////////////
- PathfindClass *PathfindClass::_Pathfinder = NULL;
- int PathfindClass::_MemoryFootprint = 0;
- ///////////////////////////////////////////////////////////////////////////
- //
- // PathfindClass
- //
- ///////////////////////////////////////////////////////////////////////////
- PathfindClass::PathfindClass (void)
- : m_SectorsDisplayed (false),
- m_PortalsDisplayed (false),
- m_Plotter (NULL),
- m_SectorList(1000), // 1000's of these
- m_PortalList(5000), // 10.000's of these
- m_SectorDisplayList(1000), // 1000's of these (debug only)
- m_WaypathList(30) // 5-30 of these?
- {
- WWASSERT (_Pathfinder == NULL);
- _Pathfinder = this;
- // Set good estimates of growth steps
- m_SectorList.Set_Growth_Step(500);
- m_PortalList.Set_Growth_Step(2500);
- m_SectorDisplayList.Set_Growth_Step(500);
- m_WaypathList.Set_Growth_Step(10);
- m_Plotter = new PathDebugPlotterClass;
- //
- // Initialize the height database
- //
- HeightDBClass::Initialize ();
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // ~PathfindClass
- //
- ///////////////////////////////////////////////////////////////////////////
- PathfindClass::~PathfindClass (void)
- {
- Reset_Sectors ();
- Reset_Portals ();
- Reset_Waypaths ();
- _Pathfinder = NULL;
- REF_PTR_RELEASE (m_Plotter);
- //
- // Free the height database
- //
- HeightDBClass::Shutdown ();
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Add_Sector
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Add_Sector (PathfindSectorClass *sector, bool add_to_tree)
- {
- WWASSERT (sector != NULL);
- if (sector != NULL) {
- sector->Add_Ref ();
-
- //
- // Add this sector to the culling system (if needs be)
- //
- if (add_to_tree) {
- m_SectorTree.Add_Object (sector);
- }
- //
- // Add this sector to our linear list (for housekeeping)
- //
- m_SectorList.Add (sector);
- //
- // For debugging purposes, add this object to our
- // memory footprint counter.
- //
- _MemoryFootprint += sizeof (PathfindSectorClass);
- }
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Add_Portal
- //
- ///////////////////////////////////////////////////////////////////////////
- int
- PathfindClass::Add_Portal (PathfindPortalClass *portal)
- {
- //
- // Add this portal to the housekeeping list
- //
- portal->Add_Ref ();
- m_PortalList.Add (portal);
- //
- // Assign the portal a unique ID
- //
- int portal_id = m_PortalList.Count () - 1;
- portal->Set_ID (portal_id);
- //
- // Add the size of this portal to the pool.
- //
- _MemoryFootprint += sizeof (PathfindPortalClass);
- return portal_id;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Add_Waypath_Portal
- //
- ///////////////////////////////////////////////////////////////////////////
- int
- PathfindClass::Add_Waypath_Portal (PathfindWaypathPortalClass *portal)
- {
- //
- // Add this portal to the housekeeping list
- //
- portal->Add_Ref ();
- m_WaypathPortalList.Add (portal);
-
- //
- // Assign the portal a unique ID
- //
- int portal_id = (m_WaypathPortalList.Count () - 1) + WAYPATH_PORTAL_ID_START;
- portal->Set_ID (portal_id);
- //
- // Add the size of this portal to the pool.
- //
- _MemoryFootprint += sizeof (PathfindWaypathPortalClass);
- return portal_id;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Add_Temporary_Portal
- //
- ///////////////////////////////////////////////////////////////////////////
- int
- PathfindClass::Add_Temporary_Portal
- (
- PathfindSectorClass *sector_from,
- PathfindSectorClass *sector_to,
- const Vector3 & start_pos,
- const Vector3 & dest_pos
- )
- {
- int retval = 0;
- if (sector_from != NULL && sector_to != NULL) {
-
- //
- // Check to see if there is already a portal between the two sectors
- //
- bool found = false;
- for (int index = 0; index < sector_from->Get_Portal_Count (); index ++) {
- PathfindPortalClass *portal = sector_from->Peek_Portal (index);
- PathfindSectorClass *sector = portal->Peek_Dest_Sector (sector_from);
- //
- // Is this portal's destination sector the one we are looking for?
- //
- if (sector == sector_to) {
- found = true;
- break;
- }
- }
- //
- // If there isn't already a portal between the sectors, then add one...
- //
- if (found == false) {
- AABoxClass portal_box (start_pos, Vector3 (0.25F, 0.25F, 1.0F));
- PathfindActionPortalClass *new_portal = new PathfindActionPortalClass;
- new_portal->Set_Bounding_Box (portal_box);
- new_portal->Add_Dest_Sector (sector_to);
- new_portal->Set_Entrance_Sector (sector_from);
- new_portal->Set_Action_Type (PathClass::ACTION_LEAP);
- new_portal->Set_Destination (dest_pos);
- new_portal->Set_ID (_NextTempPortalID ++);
-
- //
- // Add this portal to the housekeeping list
- //
- m_TemporaryPortalList.Add (new_portal);
- sector_from->Add_Portal (new_portal->Get_ID ());
- //
- // Add the size of this portal to the pool.
- //
- _MemoryFootprint += sizeof (PathfindActionPortalClass);
- retval = new_portal->Get_ID ();
- //
- // Have we reached the maximum number of temporary portals?
- //
- if (m_TemporaryPortalList.Count () > MAX_TEMP_PORTALS) {
-
- //
- // Remove the first temp portal in the list
- //
- PathfindActionPortalClass *old_portal = (PathfindActionPortalClass *)m_TemporaryPortalList[0];
- if (old_portal != NULL) {
-
- //
- // Remove the portal from which ever sectors reference it
- //
- PathfindSectorClass *sector = old_portal->Get_Entrance_Sector ();
- if (sector != NULL) {
- sector->Remove_Portal (old_portal->Get_ID ());
- }
- //
- // Remove the portal from our list and free our hold on it
- //
- m_TemporaryPortalList.Delete (0);
- old_portal->Release_Ref ();
- }
- }
- }
- }
- return retval;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Save
- //
- ///////////////////////////////////////////////////////////////////////////
- bool
- PathfindClass::Save (ChunkSaveClass &csave)
- {
- WWMEMLOG(MEM_PATHFIND);
- csave.Begin_Chunk (CHUNKID_DATABASE);
-
- //
- // Save the sectors and portals
- //
- bool retval = Save_Culling_System (csave);
- retval &= Save_Portals (csave);
- retval &= Save_Waypaths (csave);
- //
- // Save the height database for flying vehicles
- //
- csave.Begin_Chunk (CHUNKID_HEIGHTDB);
- HeightDBClass::Save (csave);
- csave.End_Chunk ();
- csave.End_Chunk ();
- return retval;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Save_Portals
- //
- ///////////////////////////////////////////////////////////////////////////
- bool
- PathfindClass::Save_Portals (ChunkSaveClass &csave)
- {
- bool retval = true;
- int count = m_PortalList.Count ();
- for (int index = 0; index < count && retval; index ++) {
- PathfindPortalClass *portal = m_PortalList[index];
- //
- // Determine what type of chunk to save this portal in
- //
- if (portal->As_PathfindActionPortalClass () != NULL) {
- csave.Begin_Chunk (CHUNKID_ACTION_PORTAL);
- } else {
- csave.Begin_Chunk (CHUNKID_PORTAL);
- }
- //
- // Write this portal out ot its own chunk
- //
- retval &= portal->Save (csave);
- csave.End_Chunk ();
- }
- //
- // Now save the waypath portals
- //
- count = m_WaypathPortalList.Count ();
- for (index = 0; index < count && retval; index ++) {
- PathfindPortalClass *portal = m_WaypathPortalList[index];
- //
- // Write this portal out ot its own chunk
- //
- csave.Begin_Chunk (CHUNKID_WAYPATH_PORTAL);
- retval &= portal->Save (csave);
- csave.End_Chunk ();
- }
- return retval;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Load
- //
- ///////////////////////////////////////////////////////////////////////////
- bool
- PathfindClass::Load (ChunkLoadClass &cload)
- {
- WWMEMLOG(MEM_PATHFIND);
- Reset_Sectors ();
- Reset_Portals ();
- Reset_Waypaths ();
- bool retval = true;
- //
- // Make sure we are reading data from the right file...
- //
- if ( cload.Open_Chunk () != true ||
- cload.Cur_Chunk_ID () != CHUNKID_DATABASE)
- {
- retval = false;
- }
- //
- // Read all the chunks...
- //
- while (retval && cload.Open_Chunk ()) {
- switch (cload.Cur_Chunk_ID ()) {
-
- case CHUNKID_HEIGHTDB:
- retval &= HeightDBClass::Load (cload);
- break;
- case CHUNKID_SECTOR_CULLING_SYSTEM:
- retval &= Load_Culling_System (cload);
- break;
- case CHUNKID_PORTAL:
- {
- PathfindPortalClass *portal = new PathfindPortalClass;
- retval &= Load_Portal (cload, portal);
- }
- break;
- case CHUNKID_ACTION_PORTAL:
- {
- PathfindActionPortalClass *portal = new PathfindActionPortalClass;
- retval &= Load_Portal (cload, portal);
- }
- break;
- case CHUNKID_WAYPATH_PORTAL:
- {
- PathfindWaypathPortalClass *portal = new PathfindWaypathPortalClass;
- retval &= Load_Portal (cload, portal);
- }
- break;
-
- default:
- {
- //
- // Load the object from the chunk (if possible)
- //
- PersistFactoryClass *factory = SaveLoadSystemClass::Find_Persist_Factory (cload.Cur_Chunk_ID ());
- if (factory != NULL) {
- PersistClass *object = factory->Load (cload);
-
- //
- // Were we successful?
- //
- if (object != NULL) {
-
- //
- // If this is a waypath, then register it with the system
- //
- if (cload.Cur_Chunk_ID () == PHYSICS_CHUNKID_WAYPATH) {
- Add_Waypath ((WaypathClass *)object);
- ((WaypathClass *)object)->Release_Ref ();
- }
- } else {
- WWDEBUG_SAY (("Unknown chunk ID 0x%X\r\n", cload.Cur_Chunk_ID ()));
- retval = false;
- }
- }
- }
- break;
- }
- cload.Close_Chunk ();
- }
- cload.Close_Chunk ();
- return retval;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Save_Sector
- //
- ///////////////////////////////////////////////////////////////////////////
- bool
- PathfindClass::Save_Sector
- (
- ChunkSaveClass & csave,
- PathfindSectorClass * sector
- )
- {
- bool retval = true;
- csave.Begin_Chunk (CHUNKID_SECTOR);
-
- //
- // Write this sector out to its own chunk
- //
- bool save_linkage = true;
- if (sector->As_PathfindWaypathSectorClass () != NULL) {
- csave.Begin_Chunk (CHUNKID_PATHFIND_SECTOR_OBJECT);
- save_linkage = false;
- } else {
- csave.Begin_Chunk (CHUNKID_SECTOR_OBJECT);
- }
-
- retval &= sector->Save (csave);
- csave.End_Chunk ();
- //
- // Now write the sector's AABTreeCullSystem linkage to a chunk
- //
- if (save_linkage) {
- csave.Begin_Chunk (CHUNKID_SECTOR_LINKAGE);
- m_SectorTree.Save_Object_Linkage (csave, sector);
- csave.End_Chunk ();
- }
- csave.End_Chunk ();
- return retval;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Load_Sector
- //
- ///////////////////////////////////////////////////////////////////////////
- bool
- PathfindClass::Load_Sector (ChunkLoadClass &cload)
- {
- bool retval = true;
- PathfindSectorClass *sector = NULL;
- //
- // Read all the chunks...
- //
- while (cload.Open_Chunk ()) {
- switch (cload.Cur_Chunk_ID ()) {
-
- case CHUNKID_SECTOR_OBJECT:
- sector = new PathfindSectorClass;
- retval &= sector->Load (cload);
- break;
- case CHUNKID_PATHFIND_SECTOR_OBJECT:
- sector = new PathfindWaypathSectorClass;
- retval &= sector->Load (cload);
- //
- // Add this sector to our housekeeping list
- //
- Add_Sector (sector, false);
- break;
- case CHUNKID_SECTOR_LINKAGE:
- WWASSERT (sector != NULL);
- if (sector != NULL) {
-
- //
- // Read the linkage information from the chunk
- //
- m_SectorTree.Load_Object_Linkage (cload, sector);
- //
- // Add this sector to our housekeeping list
- //
- Add_Sector (sector, false);
- }
- break;
- default:
- WWDEBUG_SAY (("Unknown chunk ID 0x%X\r\n", cload.Cur_Chunk_ID ()));
- retval = false;
- break;
- }
- cload.Close_Chunk ();
- }
- REF_PTR_RELEASE (sector);
- return retval;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Load_Portal
- //
- ///////////////////////////////////////////////////////////////////////////
- bool
- PathfindClass::Load_Portal (ChunkLoadClass &cload, PathfindPortalClass *portal)
- {
- //
- // Load the portal's data from its chunk
- // and add it to our global portal list.
- //
- bool retval = portal->Load (cload);
- if (retval) {
- //
- // Now add this portal to its list
- //
- if (portal->As_PathfindWaypathPortalClass () == NULL) {
- m_PortalList.Add (portal);
- } else {
- m_WaypathPortalList.Add (portal->As_PathfindWaypathPortalClass ());
- }
- //
- // Add the size of this portal to the pool.
- //
- _MemoryFootprint += sizeof (PathfindPortalClass);
- }
- return retval;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Get_Sector_Index
- //
- ///////////////////////////////////////////////////////////////////////////
- int
- PathfindClass::Get_Sector_Index (PathfindSectorClass *sector)
- {
- int index = m_SectorList.Count ();
- bool keep_going = true;
- while (keep_going && index --) {
- keep_going = (m_SectorList[index] != sector);
- }
- return index;
- }
- static inline bool Clip_Point (Vector3 *point, const AABoxClass &box)
- {
- Vector3 temp_point = *point;
- //
- // Clip the temporary point
- //
- temp_point.X = max (temp_point.X, box.Center.X - box.Extent.X);
- temp_point.Y = max (temp_point.Y, box.Center.Y - box.Extent.Y);
- temp_point.Z = max (temp_point.Z, box.Center.Z - box.Extent.Z);
- temp_point.X = min (temp_point.X, box.Center.X + box.Extent.X);
- temp_point.Y = min (temp_point.Y, box.Center.Y + box.Extent.Y);
- temp_point.Z = min (temp_point.Z, box.Center.Z + box.Extent.Z);
- //
- // Did the clip change the point?
- //
- bool retval = (point->X != temp_point.X);
- retval |= (point->Y != temp_point.Y);
- retval |= (point->Z != temp_point.Z);
-
- //
- // Pass the new point back to the caller
- //
- (*point) = temp_point;
-
- return retval;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Collect_Sectors
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Collect_Sectors
- (
- DynamicVectorClass<PathfindSectorClass *> & list,
- const AABoxClass & box,
- PathfindSectorClass * exclude_sector
- )
- {
- //
- // Collect all the sectors this box intersects
- //
- m_SectorTree.Reset_Collection ();
- m_SectorTree.Collect_Objects (box);
- //
- // Return the list of sectors to the caller
- //
- PathfindSectorClass *sector = NULL;
- for ( sector = m_SectorTree.Get_First_Collected_Object ();
- sector != NULL;
- sector = m_SectorTree.Get_Next_Collected_Object (sector))
- {
- if (sector != exclude_sector) {
- //
- // Ignore sectors that are 0 size
- //
- const AABoxClass &box = sector->Get_Bounding_Box ();
- if (box.Extent.X != 0 && box.Extent.Y != 0 && box.Extent.Z != 0) {
- list.Add (sector);
- }
- }
- }
-
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Find_Sector
- //
- ///////////////////////////////////////////////////////////////////////////
- PathfindSectorClass *
- PathfindClass::Find_Sector
- (
- const Vector3 & position,
- float sector_fudge,
- PathfindSectorClass *exclude_sector
- )
- {
- //
- // Collect all the sectors this position intersects (hopefully
- // will be only one).
- //
- SphereClass sphere (position, sector_fudge);
- m_SectorTree.Reset_Collection ();
- m_SectorTree.Collect_Objects (sphere);
- float closest = 99999.9F;
- //
- // Find an acceptable sector to return
- //
- PathfindSectorClass *closest_sector = NULL;
- PathfindSectorClass *sector = NULL;
- for ( sector = m_SectorTree.Get_First_Collected_Object ();
- sector != NULL;
- sector = m_SectorTree.Get_Next_Collected_Object (sector))
- {
- if (sector != exclude_sector) {
- //
- // Ignore sectors that are small
- //
- const AABoxClass &box = sector->Get_Bounding_Box ();
- if (box.Extent.X > 0.325F && box.Extent.Y > 0.325F && box.Extent.Z > WWMATH_EPSILON) {
- //
- // Clip the player's position to this sector
- //
- Vector3 clipped_pos = position;
- ::Clip_Point (&clipped_pos, box);
- //
- // Check to see if this clipped position is the closest yet
- //
- float dist = (clipped_pos - position).Length ();
- if (dist < closest) {
- closest = dist;
- closest_sector = sector;
- }
- }
- }
- }
-
- //
- // Return the first (and hopefully only) sector
- //
- return closest_sector;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Reset_Sectors
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Reset_Sectors (void)
- {
- Display_Sectors (false);
- Display_Portals (false);
- //
- // Release our hold on each of the sectors
- //
- for (int index = 0; index < m_SectorList.Count (); index ++) {
- PathfindSectorClass *sector = m_SectorList[index];
-
- //
- // Remove this sector from the culling system (if necessary)
- //
- if (sector->As_PathfindWaypathSectorClass () == NULL) {
- m_SectorTree.Remove_Object (sector);
- }
- REF_PTR_RELEASE (sector);
- }
- m_SectorList.Delete_All ();
- _MemoryFootprint = 0;
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Reset_Portals
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Reset_Portals (void)
- {
- Display_Portals (false);
- //
- // Release our hold on each of the portals
- //
- for (int index = 0; index < m_PortalList.Count (); index ++) {
- PathfindPortalClass *portal = m_PortalList[index];
- REF_PTR_RELEASE (portal);
- }
- //
- // Release our hold on each of the temporary portals
- //
- for (index = 0; index < m_TemporaryPortalList.Count (); index ++) {
- PathfindPortalClass *portal = m_TemporaryPortalList[index];
- REF_PTR_RELEASE (portal);
- }
- //
- // Release our hold on each of the waypath portals
- //
- for (index = 0; index < m_WaypathPortalList.Count (); index ++) {
- PathfindPortalClass *portal = m_WaypathPortalList[index];
- REF_PTR_RELEASE (portal);
- }
- //
- // Reset the lists
- //
- m_PortalList.Delete_All ();
- m_TemporaryPortalList.Delete_All ();
- m_WaypathPortalList.Delete_All ();
- //
- // Reset the starting IDs
- //
- _NextTempPortalID = TEMP_PORTAL_ID_START;
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Display_Sectors
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Display_Sectors (bool onoff)
- {
- //
- // Start fresh
- //
- m_SectorDisplayWidgets.Reset_Debug_Widget_List ();
- if (onoff) {
-
- //
- // Add boxes to our debug widget system to represent the sectors
- //
- for (int index = 0; index < m_SectorList.Count (); index ++) {
- PathfindSectorClass *sector = m_SectorList[index];
- const AABoxClass &bounding_box = sector->Get_Bounding_Box ();
- //
- // Add a randomly colored box to the widget system
- //
- float red = 0;
- float green = 0.5F + float(rand () % 128) / 256.0F;
- float blue = 0.5F + float(rand () % 128) / 256.0F;
- m_SectorDisplayWidgets.Add_Debug_AABox (bounding_box, Vector3 (red, green, blue));
- }
- }
- m_SectorsDisplayed = onoff;
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Display_Portals
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Display_Portals (bool onoff)
- {
- //
- // Start fresh
- //
- m_PortalDisplayWidgets.Reset_Debug_Widget_List ();
- //
- // Add boxes to our debug widget system to represent the sectors
- //
- if (onoff) {
- for (int index = 0; index < m_PortalList.Count (); index ++) {
- PathfindPortalClass *portal = m_PortalList[index];
- AABoxClass bounding_box;
- portal->Get_Bounding_Box (bounding_box);
- //
- // Choose a color for this box
- //
- Vector3 color (1, 1, 1);
- if (portal->Is_Two_Way_Portal () == false) {
- color.Set (1, 0, 0);
- }
- //
- // Add a box to the system
- //
- m_PortalDisplayWidgets.Add_Debug_AABox (bounding_box, color);
- }
- }
- m_PortalsDisplayed = onoff;
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Add_Waypath
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Add_Waypath (WaypathClass *waypath)
- {
- if (waypath != NULL) {
- waypath->Add_Ref ();
- m_WaypathList.Add (waypath);
- }
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Remove_Waypath
- //
- ///////////////////////////////////////////////////////////////////////////
- bool
- PathfindClass::Remove_Waypath (WaypathClass *waypath)
- {
- bool retval = false;
- if (waypath != NULL) {
-
- int index = m_WaypathList.Count ();
- while (index -- && (retval == false)) {
- WaypathClass *curr_waypath = m_WaypathList[index];
-
- //
- // If this is the waypath we are looking for
- // then remove it from the list and release our
- // hold on it.
- //
- if (curr_waypath == waypath) {
- REF_PTR_RELEASE (waypath);
- m_WaypathList.Delete (index);
- retval = true;
- }
- }
- }
- return retval;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Find_Waypath
- //
- ///////////////////////////////////////////////////////////////////////////
- WaypathClass *
- PathfindClass::Find_Waypath (int id) const
- {
- WaypathClass *waypath = NULL;
- //
- // Loop over all the paths in our list until we've
- // found the one are looking for.
- //
- int index = m_WaypathList.Count ();
- while (index -- && (waypath == NULL)) {
- WaypathClass *curr_waypath = m_WaypathList[index];
-
- //
- // Is this the waypath we are looking for?
- //
- if (curr_waypath->Get_ID () == id) {
- waypath = curr_waypath;
- }
- }
- return waypath;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Count_Waypaths_Starting_In_Box
- //
- ///////////////////////////////////////////////////////////////////////////
- int PathfindClass::Count_Waypaths_Starting_In_Box (const AABoxClass & box)
- {
- //
- // Loop over all the paths in our list counting the ones whose
- // start points are contained inside the given box.
- //
- int count = 0;
- for (int index=0; index<m_WaypathList.Count(); index++) {
- WaypathClass *curr_waypath = m_WaypathList[index];
- if (CollisionMath::Overlap_Test(box,curr_waypath->Get_Point(0)->Get_Position()) == CollisionMath::INSIDE) {
- count++;
- }
- }
- return count;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Get_Waypath_Starting_In_Box
- //
- ///////////////////////////////////////////////////////////////////////////
- WaypathClass * PathfindClass::Get_Waypath_Starting_In_Box (const AABoxClass & box,int i)
- {
- //
- // Loop over all the paths in our list counting down until
- // we get to the i'th one that starts in the given box.
- //
- WaypathClass * path = NULL;
- int count = i;
- for (int index=0; index<m_WaypathList.Count(); index++) {
- WaypathClass *curr_waypath = m_WaypathList[index];
-
- if (CollisionMath::Overlap_Test(box,curr_waypath->Get_Point(0)->Get_Position()) == CollisionMath::INSIDE) {
- if (count == 0) {
- path = curr_waypath;
- break;
- } else {
- count--;
- }
- }
- }
-
- if (path != NULL) {
- path->Add_Ref();
- }
- return path;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Reset_Waypaths
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Reset_Waypaths (void)
- {
- //
- // Release our hold on each of the waypaths
- //
- int index = m_WaypathList.Count ();
- while (index --) {
- WaypathClass *waypath = m_WaypathList[index];
- REF_PTR_RELEASE (waypath);
- }
- //
- // Remove all the waypaths from our list
- //
- m_WaypathList.Delete_All ();
- return ;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Save_Waypaths
- //
- //////////////////////////////////////////////////////////////////////////////////
- bool
- PathfindClass::Save_Waypaths (ChunkSaveClass &csave)
- {
- //
- // Loop over all the waypaths
- //
- int index = m_WaypathList.Count ();
- while (index --) {
- WaypathClass *waypath = m_WaypathList[index];
- //
- // Save this waypath object
- //
- csave.Begin_Chunk (waypath->Get_Factory ().Chunk_ID ());
- waypath->Get_Factory ().Save (csave, waypath);
- csave.End_Chunk ();
- //
- // Now save all the waypoints that this waypath contains
- //
- int waypoint_index = waypath->Get_Point_Count ();
- while (waypoint_index --) {
- WaypointClass *waypoint = waypath->Get_Point (waypoint_index);
- //
- // Save this waypoint object
- //
- csave.Begin_Chunk (waypoint->Get_Factory ().Chunk_ID ());
- waypoint->Get_Factory ().Save (csave, waypoint);
- csave.End_Chunk ();
- }
- }
- return true;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Save_Culling_System
- //
- //////////////////////////////////////////////////////////////////////////////////
- bool
- PathfindClass::Save_Culling_System (ChunkSaveClass &csave)
- {
- bool retval = true;
- csave.Begin_Chunk (CHUNKID_SECTOR_CULLING_SYSTEM);
- //
- // Write the AABTreeCullSystem we use for sector lookups
- // to the chunk
- //
- csave.Begin_Chunk (CHUNKID_SECTOR_CULL_TREE);
- m_SectorTree.Save (csave);
- csave.End_Chunk ();
- //
- // Now write the contents of the tree (the sector list)
- // to the chunk
- //
- int count = m_SectorList.Count ();
- for (int index = 0; index < count && retval; index ++) {
- Save_Sector (csave, m_SectorList[index]);
- }
- csave.End_Chunk ();
- return retval;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Load_Culling_System
- //
- //////////////////////////////////////////////////////////////////////////////////
- bool
- PathfindClass::Load_Culling_System (ChunkLoadClass &cload)
- {
- bool retval = true;
- //
- // Read all the chunks...
- //
- while (cload.Open_Chunk ()) {
- switch (cload.Cur_Chunk_ID ()) {
-
- case CHUNKID_SECTOR_CULL_TREE:
- m_SectorTree.Load (cload);
- break;
- case CHUNKID_SECTOR:
- retval &= Load_Sector (cload);
- break;
- default:
- WWDEBUG_SAY (("Unknown chunk ID 0x%X\r\n", cload.Cur_Chunk_ID ()));
- retval = false;
- break;
- }
- cload.Close_Chunk ();
- }
- return retval;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Re_Partition_Sector_Tree
- //
- //////////////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Re_Partition_Sector_Tree (void)
- {
- m_SectorTree.Re_Partition ();
- return ;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Peek_Portal
- //
- /////////////////////////////////////////////////////////////////////////
- PathfindPortalClass *
- PathfindClass::Peek_Portal (int portal_index)
- {
- PathfindPortalClass *portal = NULL;
-
- if (portal_index >= TEMP_PORTAL_ID_START) {
- //
- // Try to find the portal in our temporary portal list
- //
- for (int index = 0; index < m_TemporaryPortalList.Count (); index ++) {
-
- //
- // Is this the portal we are looking for?
- //
- if (portal_index == (int)m_TemporaryPortalList[index]->Get_ID ()) {
- portal = m_TemporaryPortalList[index];
- break;
- }
- }
- } else if (portal_index >= WAYPATH_PORTAL_ID_START) {
-
- //
- // Look for the portal in our waypath portal list
- //
- portal = m_WaypathPortalList[portal_index - WAYPATH_PORTAL_ID_START];
- } else if (portal_index >= 0) {
- portal = m_PortalList[portal_index];
- }
- return portal;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Get_Height_Value
- //
- //////////////////////////////////////////////////////////////////////////////////
- float
- PathfindClass::Get_Height_Value (const Vector3 &pos)
- {
- return HeightDBClass::Get_Height (pos);
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Find_Random_Spot
- //
- //////////////////////////////////////////////////////////////////////////////////
- static DynamicVectorClass<AABoxClass> box_list;
- bool
- PathfindClass::Find_Random_Spot
- (
- const Vector3 ¢er,
- float max_dist,
- Vector3 * dest
- )
- {
- bool retval = false;
- //
- // Lookup the starting sector we'll search from
- //
- PathfindSectorClass *start_sector = Find_Sector (center, 0.1F, NULL);
- if (start_sector != NULL) {
- box_list.Reset_Active();
- //
- // Start a list of valid 'regions' with the bounding box of the
- // current sector
- //
- box_list.Add (start_sector->Get_Bounding_Box ());
- //
- // Square the distances for quick compares
- //
- float max_dist2 = max_dist * max_dist;
- //
- // Loop over all connecting sectors and add any of them that meet
- // the distance requirements to our list
- //
- for (int index = 0; index < start_sector->Get_Portal_Count (); index ++) {
- PathfindPortalClass *portal = start_sector->Peek_Portal (index);
- PathfindSectorClass *dest_sector = portal->Peek_Dest_Sector (start_sector);
- if (dest_sector != NULL) {
- const AABoxClass &bounding_box = dest_sector->Get_Bounding_Box ();
-
- //
- // Find a "close" point to the box from the starting position
- //
- Vector3 closest_pt = center;
- Clip_Point (&closest_pt, bounding_box);
-
- //
- // Is this box within the maximum acceptable distance?
- //
- float dist_to_box2 = (center - closest_pt).Length2 ();
- if (dist_to_box2 < max_dist2) {
- box_list.Add (bounding_box);
- }
- }
- }
- //
- // Pick a random box from the list
- //
- int count = box_list.Count ();
- int box_index = (rand () % count);
- const AABoxClass &box = box_list[box_index];
- //
- // Find a "close" point to the box from the starting position
- //
- Vector3 closest_pt = center;
- Clip_Point (&closest_pt, box);
- //
- // Now add a random vector to this point that will stay
- // inside the requirements
- //
- float curr_dist = (closest_pt - center).Length ();
- float max_allowable_dist = (max_dist - curr_dist);
- (*dest) = closest_pt;
- dest->X += WWMath::Random_Float (-max_allowable_dist, max_allowable_dist);
- dest->Y += WWMath::Random_Float (-max_allowable_dist, max_allowable_dist);
- //
- // Now, simply make sure the point stays inside the pathfind sector
- //
- Clip_Point (dest, box);
- retval = true;
- } else if (m_SectorList.Count () == 0) {
- //
- // If we don't have any pathfind data, then simply choose a random point
- //
- (*dest) = center;
- dest->X += WWMath::Random_Float (-max_dist, max_dist);
- dest->Y += WWMath::Random_Float (-max_dist, max_dist);
- retval = true;
- }
- return retval;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Free_Waypath_Sectors_And_Portals
- //
- //////////////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Free_Waypath_Sectors_And_Portals (void)
- {
- //
- // Release our hold on each of the waypath portals
- //
- for (int index = 0; index < m_WaypathPortalList.Count (); index ++) {
- PathfindPortalClass *portal = m_WaypathPortalList[index];
- //
- // Remove this portal from the sectors that reference it
- //
- uint16 dest_sector1_id = portal->Get_Dest_Sector1 ();
- uint16 dest_sector2_id = portal->Get_Dest_Sector2 ();
- PathfindSectorClass *dest_sector1 = Peek_Sector (dest_sector1_id);
- PathfindSectorClass *dest_sector2 = Peek_Sector (dest_sector2_id);
- if (dest_sector1 != NULL) {
- dest_sector1->Remove_Portal (portal->Get_ID ());
- }
- if (dest_sector2 != NULL) {
- dest_sector2->Remove_Portal (portal->Get_ID ());
- }
- REF_PTR_RELEASE (portal);
- }
- //
- // Loop over all the sectors in our list
- //
- for (index = 0; index < m_SectorList.Count (); index ++) {
- PathfindSectorClass *sector = m_SectorList[index];
-
- //
- // Is this sector a waypath sector?
- //
- if (sector->As_PathfindWaypathSectorClass () != NULL) {
- //
- // Free the sector and remove it from the list
- //
- REF_PTR_RELEASE (sector);
- m_SectorList.Delete (index);
- index --;
- }
- }
- //
- // Reset the portal list
- //
- m_WaypathPortalList.Delete_All ();
- return ;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Generate_Waypath_Sectors_And_Portals
- //
- //////////////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Generate_Waypath_Sectors_And_Portals (void)
- {
- //
- // Start fresh
- //
- Free_Waypath_Sectors_And_Portals ();
- //
- // Loop over all the waypaths in the system
- //
- for (int index = 0; index < m_WaypathList.Count (); index ++) {
- WaypathClass *waypath = m_WaypathList[index];
- //
- // Only process waypaths that can be used during a path solve
- //
- if (waypath->Get_Flag (WaypathClass::FLAG_INNATE_PATHFIND)) {
- Generate_Waypath_Sector_And_Portals (waypath);
- }
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Generate_Waypath_Sector_And_Portals
- //
- //////////////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Generate_Waypath_Sector_And_Portals (WaypathClass *waypath)
- {
- DynamicVectorClass<PathfindWaypathPortalClass *> portal_list;
- //
- // Get information about this waypath
- //
- int waypoint_count = waypath->Get_Point_Count ();
- int waypath_id = waypath->Get_ID ();
- //
- // Create a new "waypath sector" that will hold all the enter and
- // exit portals for us
- //
- PathfindWaypathSectorClass *new_sector = new PathfindWaypathSectorClass;
- new_sector->Set_Waypath_ID (waypath_id);
- new_sector->Set_Bounding_Box (AABoxClass (Vector3 (0, 0, 0), Vector3 (0, 0, 0)));
-
- //
- // Register this new sector with the pathfind system
- //
- Add_Sector (new_sector, false);
-
- //
- // Add a portal around each waypoint in the path
- //
- for (int index = 0; index < waypoint_count; index ++) {
- WaypointClass *waypoint = waypath->Get_Point (index);
- const Vector3 &waypoint_pos = waypoint->Get_Position ();
- //
- // Check to see if there is a pathfind sector at the waypoint position...
- // if there is, then we should create a new portal at this position.
- //
- PathfindSectorClass *sector_at_pos = Find_Sector (waypoint_pos, 0.125F);
- if (sector_at_pos != NULL) {
- //
- // Add a new portal to the list at this position
- //
- ::Add_New_Portal_To_List (portal_list, new_sector, sector_at_pos, waypath_id,
- index, waypoint_pos, 0);
- }
- }
- //
- // Now add a portal everywhere the waypath intersects a pathfind sector
- //
- Add_Intersection_Portals_To_List (portal_list, waypath, new_sector);
- if (portal_list.Count () > 0) {
-
- //
- // Now sort the portals based on occurance within the path
- //
- ::qsort (&portal_list[0], portal_list.Count (),
- sizeof (PathfindWaypathPortalClass *), fnCompareWaypathPortalsCallback);
- //
- // Register the portals with the system and add them to their sectors
- //
- for (int portal_index = 0; portal_index < portal_list.Count (); portal_index ++) {
- PathfindWaypathPortalClass *curr_portal = portal_list[portal_index];
-
- //
- // Register the portal
- //
- int portal_id = Add_Waypath_Portal (curr_portal);
- //
- // Lookup the sectors this portal will connect
- //
- uint16 dest_sector1_id = curr_portal->Get_Dest_Sector1 ();
- uint16 dest_sector2_id = curr_portal->Get_Dest_Sector2 ();
- PathfindSectorClass *dest_sector1 = Peek_Sector (dest_sector1_id);
- PathfindSectorClass *dest_sector2 = Peek_Sector (dest_sector2_id);
- //
- // Add this portal to the sectors
- //
- if (dest_sector1 != NULL) {
- dest_sector1->Add_Portal (portal_id);
- }
-
- if (dest_sector2 != NULL) {
- dest_sector2->Add_Portal (portal_id);
- }
- //
- // Release our hold on this portal
- //
- REF_PTR_RELEASE (curr_portal);
- }
- }
-
- //
- // Now release our hold on the sector we just created
- //
- REF_PTR_RELEASE (new_sector);
- return ;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Add_Intersection_Portals_To_List
- //
- //////////////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Add_Intersection_Portals_To_List
- (
- DynamicVectorClass<PathfindWaypathPortalClass *> & portal_list,
- WaypathClass * waypath,
- PathfindWaypathSectorClass * dest_sector
- )
- {
- int waypoint_count = waypath->Get_Point_Count ();
- int waypath_id = waypath->Get_ID ();
- //
- // For this waypath, find all the pathfind sectors it intersects
- //
- for (int waypoint_index = 0; waypoint_index < waypoint_count - 1; waypoint_index ++) {
- WaypointClass *waypoint1 = waypath->Get_Point (waypoint_index);
- WaypointClass *waypoint2 = waypath->Get_Point (waypoint_index + 1);
- const Vector3 &pos1 = waypoint1->Get_Position ();
- const Vector3 &pos2 = waypoint2->Get_Position ();
- //
- // Build a bounding box around the two points
- //
- Vector3 extent = (pos2 - pos1) * 0.5F;
- Vector3 center = pos1 + extent;
- extent.X = max (WWMath::Fabs (extent.X), 1.0F);
- extent.Y = max (WWMath::Fabs (extent.Y), 1.0F);
- extent.Z = max (WWMath::Fabs (extent.Z), 1.0F);
- AABoxClass bounding_box (center, extent);
-
- //
- // Find all the pathfind sectors in this bounding box
- //
- m_SectorTree.Reset_Collection ();
- m_SectorTree.Collect_Objects (bounding_box);
- //
- // Loop over all the sectors that this line segment could possibly intersect
- //
- PathfindSectorClass *sector = NULL;
- for ( sector = m_SectorTree.Peek_First_Collected_Object ();
- sector != NULL;
- sector = m_SectorTree.Peek_Next_Collected_Object (sector))
- {
- const AABoxClass §or_box = sector->Get_Bounding_Box ();
- //
- // Find where this line segment intersects the sector (if at all)
- //
- float percent = 0;
- Vector3 portal_pos;
- if (::Find_Intersection_Point (sector_box, pos1, pos2, &percent, &portal_pos)) {
- //
- // Add a new portal to the list at this position
- //
- ::Add_New_Portal_To_List (portal_list, dest_sector, sector, waypath_id,
- waypoint_index, portal_pos, percent);
- }
- }
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Add_New_Portal_To_List
- //
- //////////////////////////////////////////////////////////////////////////////////
- void
- Add_New_Portal_To_List
- (
- DynamicVectorClass<PathfindWaypathPortalClass *> & portal_list,
- PathfindSectorClass * dest_sector1,
- PathfindSectorClass * dest_sector2,
- int waypath_id,
- int waypoint_index,
- const Vector3 & portal_pos,
- float percent
- )
- {
- const Vector3 portal_extent (0.5F, 0.5F, 1.0F);
- //
- // Create a position along this waypath for the waypoint
- //
- WaypathPositionClass waypath_pos;
- waypath_pos.Set_Waypath_ID (waypath_id);
- waypath_pos.Set_Waypoint_Index (waypoint_index);
- waypath_pos.Set_Percent (percent);
- //
- // Allcoate and configure a new portal
- //
- PathfindWaypathPortalClass *new_portal = new PathfindWaypathPortalClass;
- new_portal->Set_Waypath_Pos (waypath_pos);
- new_portal->Set_Bounding_Box (AABoxClass (portal_pos, portal_extent));
-
- if (dest_sector1 != NULL) {
- new_portal->Add_Dest_Sector (dest_sector1);
- }
- if (dest_sector2 != NULL) {
- new_portal->Add_Dest_Sector (dest_sector2);
- }
- //
- // Add this portal to the list
- //
- portal_list.Add (new_portal);
- return ;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Find_Intersection_Point
- //
- //////////////////////////////////////////////////////////////////////////////////
- bool
- Find_Intersection_Point
- (
- const AABoxClass & box,
- const Vector3 & p0,
- const Vector3 & p1,
- float * percent,
- Vector3 * intersection_point
- )
- {
- bool retval = false;
- //
- // Find the locations of each of the 6 "planes"
- // we will be testing against
- //
- float x1 = box.Center.X - box.Extent.X;
- float x2 = box.Center.X + box.Extent.X;
- float y1 = box.Center.Y - box.Extent.Y;
- float y2 = box.Center.Y + box.Extent.Y;
- float z1 = box.Center.Z - box.Extent.Z;
- float z2 = box.Center.Z + box.Extent.Z;
- float t_values[6] = { -1, -1, -1, -1, -1, -1 };
- Vector3 delta = p1 - p0;
- //
- // Find the "t" values where the line intersects the
- // 2 "Y-Z" planes
- //
- if (delta.X != 0) {
- t_values[0] = (x1 - p0.X) / delta.X;
- t_values[1] = (x2 - p0.X) / delta.X;
- }
- //
- // Find the "t" values where the line intersects the
- // 2 "X-Z" planes
- //
- if (delta.Y != 0) {
- t_values[2] = (y1 - p0.Y) / delta.Y;
- t_values[3] = (y2 - p0.Y) / delta.Y;
- }
- //
- // Find the "t" values where the line intersects the
- // 2 "X-Y" planes
- //
- if (delta.Z != 0) {
- t_values[4] = (z1 - p0.Z) / delta.Z;
- t_values[5] = (z2 - p0.Z) / delta.Z;
- }
- //
- // Loop over all the "t" values we've calculated
- //
- (*percent) = 2.0F;
- for (int index = 0; index < 6; index ++) {
- //
- // Is this "t" value the smallest in-range value we've
- // found yet?
- //
- if ( t_values[index] >= 0 &&
- t_values[index] <= 1.0F &&
- t_values[index] < (*percent))
- {
- //
- // Find the point which exists at this "t" value along the line segment
- //
- Vector3 point = p0 + delta * t_values[index];
- //
- // If this point isn't outside the box, then we'll consider it good enough
- //
- if ( (WWMath::Fabs (point.X - box.Center.X) <= (box.Extent.X + WWMATH_EPSILON)) &&
- (WWMath::Fabs (point.Y - box.Center.Y) <= (box.Extent.Y + WWMATH_EPSILON)) &&
- (WWMath::Fabs (point.Z - box.Center.Z) <= (box.Extent.Z + WWMATH_EPSILON)))
- {
- (*percent) = t_values[index];
- (*intersection_point) = point;
- retval = true;
- }
- }
- }
- return retval;
- }
- ////////////////////////////////////////////////////////////////
- //
- // fnCompareWaypathPortalsCallback
- //
- ////////////////////////////////////////////////////////////////
- int __cdecl
- fnCompareWaypathPortalsCallback
- (
- const void *elem1,
- const void *elem2
- )
- {
- WWASSERT (elem1 != NULL);
- WWASSERT (elem2 != NULL);
- PathfindWaypathPortalClass *portal1 = *((PathfindWaypathPortalClass **)elem1);
- PathfindWaypathPortalClass *portal2 = *((PathfindWaypathPortalClass **)elem2);
- const WaypathPositionClass &pos1 = portal1->Get_Waypath_Pos ();
- const WaypathPositionClass &pos2 = portal2->Get_Waypath_Pos ();
- //
- // Sort based on the waypath segment the portals lie one
- //
- int result = 0;
- if (pos1.Get_Waypoint_Index () < pos2.Get_Waypoint_Index ()) {
- result = -1;
- } else if (pos1.Get_Waypoint_Index () > pos2.Get_Waypoint_Index ()) {
- result = 1;
- } else {
-
- //
- // If the portals lie on the same segment, then sort by their
- // position along the segment
- //
- if (pos1.Get_Percent () < pos2.Get_Percent ()) {
- result = -1;
- } else if (pos1.Get_Percent () > pos2.Get_Percent ()) {
- result = 1;
- }
- }
- return result;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Find_Portals
- //
- //////////////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Find_Portals
- (
- const Vector3 & p0,
- const Vector3 & p1,
- DynamicVectorClass<PathfindPortalClass *> & list,
- bool action_portals_only
- )
- {
- //
- // Loop over all the portals
- //
- for (int index = 0; index < m_PortalList.Count (); index ++) {
- PathfindPortalClass *portal = m_PortalList[index];
- PathfindActionPortalClass *action_portal = portal->As_PathfindActionPortalClass ();
- if (action_portals_only == false || (action_portal != NULL && portal->Get_Action_Type () != PathClass::ACTION_NONE)) {
-
- //
- // Get the bounding box for the portal
- //
- AABoxClass box;
- portal->Get_Bounding_Box (box);
- //
- // Does the line pass through this box?
- //
- float percent1 = 0;
- Vector3 intersection_pt (0, 0, 0);
- if (::Find_Intersection_Point (box, p0, p1, &percent1, &intersection_pt)) {
- bool is_valid = true;
-
- //
- // If this is an action portal request, we need to ensure that the
- // line segment passes through to the exit portal
- //
- if (action_portals_only) {
- is_valid = false;
- PathfindSectorClass *sector = action_portal->Peek_Dest_Sector (NULL);
- if (sector != NULL) {
- //
- // Get a pointer to the exit portal
- //
- PathfindPortalClass *exit_portal = action_portal->Get_Exit_Portal ();
- if (exit_portal != NULL) {
-
- //
- // Does the line segment pass through to the exit portal?
- //
- AABoxClass exit_box;
- exit_portal->Get_Bounding_Box (exit_box);
- if (::Find_Intersection_Point (exit_box, p0, p1,
- &percent1, &intersection_pt))
- {
- float dist1 = (box.Center - p0).Length2 ();
- float dist2 = (exit_box.Center - p0).Length2 ();
- if (dist1 < dist2) {
- is_valid = true;
- }
- }
- }
- }
- }
-
- //
- // Add the portal to the list
- //
- if (is_valid) {
- list.Add (portal);
- }
- }
- }
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Render_Debug_Widgets
- //
- //////////////////////////////////////////////////////////////////////////////////
- void
- PathfindClass::Render_Debug_Widgets (RenderInfoClass &rinfo)
- {
- m_SectorDisplayWidgets.Render_Debug_Widgets (rinfo);
- m_PortalDisplayWidgets.Render_Debug_Widgets (rinfo);
- return ;
- }
|