| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004 |
- /*
- ** 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/Tools/LevelEdit/PathfindSectorBuilder.cpp $Modtime:: 5/27/00 4:10p $*
- * *
- * $Revision:: 56 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "stdafx.h"
- #include "pathfindsectorbuilder.h"
- #include "phys3.h"
- #include "editorassetmgr.h"
- #include "humanphys.h"
- #include "phys3.h"
- #include "boxrobj.h"
- #include "pathfind.h"
- #include "pscene.h"
- #include "physcoltest.h"
- #include "filemgr.h"
- #include "_assetmgr.h"
- #include "utils.h"
- #include "nodemgr.h"
- #include "filelocations.h"
- #include "transitionnode.h"
- #include "collisiongroups.h"
- #include "pathfindportal.h"
- #include "GeneratingPathfindDialog.h"
- #include "terrainnode.h"
- #include "sceneeditor.h"
- #include "staticanimphys.h"
- #include "elevator.h"
- #include "doors.h"
- #include "soldier.h"
- #include "humanphys.h"
- #include "combatchunkid.h"
- //////////////////////////////////////////////////////////////////////////
- // Local Prototypes
- //////////////////////////////////////////////////////////////////////////
- UINT fnPathfindDialogThread (DWORD dwparam1, DWORD dwparam2, DWORD, HRESULT *, HWND *);
- ///////////////////////////////////////////////////////////////////////////
- // Local inlines
- ///////////////////////////////////////////////////////////////////////////
- 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;
- }
- //////////////////////////////////////////////////////////////////////////
- // Local constants
- //////////////////////////////////////////////////////////////////////////
- const float ONE_SEC_FALL_DIST = 4.9F;
- class SimDirInfoClass
- {
- public:
- SimDirInfoClass (void) { }
- SimDirInfoClass (float _heading, float _speed, const Vector3 &_move, const Vector3 &_quadmove)
- : heading (_heading), speed (_speed), move (_move), quad_move (_quadmove) { }
- float heading;
- float speed;
- Vector3 move;
- Vector3 quad_move;
- };
- //
- // 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 ( 1.5F, -0.5F, 0) ),
- SimDirInfoClass ( (float)DEG_TO_RAD (90), 0, Vector3 ( 0, 1.0F, 0), Vector3 ( 0.5F, 1.5F, 0) ),
- SimDirInfoClass ( (float)DEG_TO_RAD (180), 0, Vector3 (-1.0F, 0, 0), Vector3 (-1.5F, 0.5F, 0) ),
- SimDirInfoClass ( (float)DEG_TO_RAD (270), 0, Vector3 ( 0, -1.0F, 0), Vector3 (-0.5F, -1.5F, 0) )
- };
- static HumanPhysClass *_PhysSimObj = NULL;
- static SoldierGameObj *_GameSimObj = NULL;
- //////////////////////////////////////////////////////////////////////////
- //
- // PathfindSectorBuilderClass
- //
- //////////////////////////////////////////////////////////////////////////
- PathfindSectorBuilderClass::PathfindSectorBuilderClass (void)
- : m_CurrentSector (NULL),
- m_SimBoundingBox (Vector3 (0.5F, 0.5F, 1.8F)),
- m_SimBoxExtents (Vector3 (0.25F, 0.25F, 0.9F)),
- m_DirInfo (NULL),
- m_StepHeight (0),
- m_TotalBoxCount (0),
- m_TotalBoxGuess (0),
- m_BeforeUpdateCount (0),
- m_AllowWaterFloodfill (false),
- m_MaxSectorDim (28000.0F)
- {
- RenderObjClass *commando_obj = NULL;
- //
- // Create an instance of the commando render object we can
- // use to simulate character movement
- //
- SoldierGameObjDef *definition = (SoldierGameObjDef *)DefinitionMgrClass::Find_Typed_Definition ("Commando", CLASSID_GAME_OBJECT_DEF_SOLDIER, false);
- if (definition != NULL) {
- SoldierGameObj *game_obj = new SoldierGameObj;
- game_obj->Init (*definition);
- REF_PTR_SET (commando_obj, game_obj->Peek_Model ());
- game_obj->Set_Delete_Pending ();
- }
- 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");
- REF_PTR_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;
- m_SimBoundingBox.Z = (box.Extent.Z * 2);
- m_SimBoxExtents = m_SimBoundingBox * 0.5F;
- m_StepHeight = 0.25F;
- REF_PTR_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].quad_move.X *= m_SimBoundingBox.X;
- m_DirInfo[index].quad_move.Y *= m_SimBoundingBox.Y;
- m_DirInfo[index].quad_move.Z *= m_SimBoundingBox.Z;
- m_DirInfo[index].speed = m_DirInfo[index].move.Length ();
- }
- REF_PTR_RELEASE (commando_obj);
- //
- // Configure the body box culling system
- //
- Vector3 lev_min;
- Vector3 lev_max;
- PhysicsSceneClass::Get_Instance ()->Get_Level_Extents (lev_min, lev_max);
- m_BodyBoxCullingSystem.Initialize (m_SimBoxExtents, lev_min, lev_max);
- //
- // Setup the simulation constants
- //
- m_SimMovement = Vector3 (0, 0, -(ONE_SEC_FALL_DIST + (m_SimBoundingBox.Z * 0.75F)));
- m_SimSweepBox.Extent = m_SimBoxExtents;
- }
- Detect_Level_Features ();
- /*AABoxClass collision_box;
- collision_box.Center.Set (0, 0, 0);
- collision_box.Extent = m_SimBoxExtents;
- _PhysSimObj->Set_Collision_Box (collision_box);*/
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // ~PathfindSectorBuilderClass
- //
- //////////////////////////////////////////////////////////////////////////
- PathfindSectorBuilderClass::~PathfindSectorBuilderClass (void)
- {
- /*if (_GameSimObj != NULL) {
- _GameSimObj->Destroy ();
- _GameSimObj = NULL;
- }*/
- if (m_DirInfo != NULL) {
- delete [] m_DirInfo;
- m_DirInfo = NULL;
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Prepare_Level
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Prepare_Level (void)
- {
- ::Get_Scene_Editor ()->Display_Static_Anim_Phys (true);
- //
- // Get the list of all static objects from the physics scene
- //
- RefPhysListIterator iterator = ::Get_Scene_Editor ()->Get_Static_Object_Iterator ();
- for (iterator.First (); !iterator.Is_Done (); iterator.Next ()) {
- //
- // Is this object a static anim phys?
- //
- PhysClass *phys_obj = iterator.Peek_Obj ();
- StaticAnimPhysClass *static_phys_obj = phys_obj->As_StaticAnimPhysClass ();
- if (static_phys_obj != NULL) {
- //
- // Should we disable collisions with this object during pathfind?
- //
- StaticAnimPhysDefClass *definition = static_phys_obj->Get_StaticAnimPhysDef ();
- if (definition->Does_Collide_In_Pathfind () == false) {
- phys_obj->Inc_Ignore_Counter ();
- } else {
- while (phys_obj->Is_Ignore_Me ()) {
- phys_obj->Dec_Ignore_Counter ();
- }
- }
- }
- }
- //
- // Make sure that tile's use collision group 15...
- //
- for ( NodeClass *node = NodeMgrClass::Get_First (NODE_TYPE_TILE);
- node != NULL;
- node = NodeMgrClass::Get_Next (node, NODE_TYPE_TILE))
- {
- PhysClass *phys_obj = node->Peek_Physics_Obj ();
- if (phys_obj != NULL) {
- phys_obj->Set_Collision_Group (15);
- }
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Restore_Level
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Restore_Level (void)
- {
- //
- // Restore each tile's collision group...
- //
- for ( NodeClass *node = NodeMgrClass::Get_First (NODE_TYPE_TILE);
- node != NULL;
- node = NodeMgrClass::Get_Next (node, NODE_TYPE_TILE))
- {
- PhysClass *phys_obj = node->Peek_Physics_Obj ();
- if (phys_obj != NULL) {
- phys_obj->Set_Collision_Group (EDITOR_COLLISION_GROUP);
- }
- }
- //
- // Get the list of all static objects from the physics scene
- //
- RefPhysListIterator iterator = ::Get_Scene_Editor ()->Get_Static_Object_Iterator ();
- for (iterator.First (); !iterator.Is_Done (); iterator.Next ()) {
- //
- // Is this object a static anim phys?
- //
- PhysClass *phys_obj = iterator.Peek_Obj ();
- StaticAnimPhysClass *static_phys_obj = phys_obj->As_StaticAnimPhysClass ();
- if (static_phys_obj != NULL) {
- //
- // Do we need to re-enable collisions with this object?
- //
- StaticAnimPhysDefClass *definition = static_phys_obj->Get_StaticAnimPhysDef ();
- if (definition->Does_Collide_In_Pathfind () == false) {
- phys_obj->Dec_Ignore_Counter ();
- }
- }
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Initialize
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Initialize (void)
- {
- Prepare_Level ();
- //
- // Turn off sector display
- //
- PathfindClass::Get_Instance ()->Display_Sectors (false);
- PathfindClass::Get_Instance ()->Display_Portals (false);
- //
- // Initialize the dynamic vector array's so they will resize
- // in appropriate size steps (to decrease the total number of resizes)
- //
- m_FloodFillProcessList.Set_Growth_Step (20000);
- m_PossiblePortalList.Set_Growth_Step (20000);
- m_BodyBoxReleaseList.Set_Growth_Step (100000);
- //
- // Make a guess at the total number of boxes in the world based on
- // its size
- //
- Vector3 lev_min;
- Vector3 lev_max;
- PhysicsSceneClass::Get_Instance ()->Get_Level_Extents (lev_min, lev_max);
- int width = (lev_max.X - lev_min.X) / m_SimBoundingBox.X;
- int height = (lev_max.Y - lev_min.Y) / m_SimBoundingBox.Y;
- m_TotalBoxGuess = width * height;
- //
- // Show some UI
- //
- Show_Dialog ();
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Shutdown
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Shutdown (void)
- {
- //
- // Do some cleanup
- //
- Free_Floodfill_Boxes ();
- Cleanup_Level_Features ();
- //
- // Make sure we re-partition the sector culling system so
- // it does us some good... :)
- //
- PathfindClass::Get_Instance ()->Re_Partition_Sector_Tree ();
- //
- // Shutdown the UI and restore any level objects we modified
- //
- Close_Dialog ();
- Restore_Level ();
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Compress_Sectors_For_Dyna_Culling
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Compress_Sectors_For_Dyna_Culling (void)
- {
- const float MAX_DYNAMIC_VIS_CELL_DIMENSION = 20.0f;
- //
- // Change the dialog's checkmark so the user knows we are comprssing sectors
- //
- m_pDialog->Set_State(GeneratingPathfindDialogClass::STATE_COMPRESS);
- //
- // Floodfill the level and compress the floodfill into sectors
- //
- DynamicVectorClass<AABoxClass> sectors;
- Set_Max_Sector_Size(MAX_DYNAMIC_VIS_CELL_DIMENSION);
-
- Compress_Sectors(§ors);
- //
- // Hand the sectors into the scene (NOTE: this will have to reset the
- // VIS system)
- //
- PhysicsSceneClass::Get_Instance()->Re_Partition_Dynamic_Culling_System(sectors);
- return;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Compress_Sectors_For_Pathfind
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Compress_Sectors_For_Pathfind (void)
- {
- //
- // Discard any previously generated data
- //
- PathfindClass::Get_Instance ()->Reset_Sectors ();
- PathfindClass::Get_Instance ()->Reset_Portals ();
- //
- // Change the dialog's checkmark so the user knows we are comprssing sectors
- //
- m_pDialog->Set_State (GeneratingPathfindDialogClass::STATE_COMPRESS);
- //
- // Compress the sectors into the largest possible rectangular regions
- //
- DWORD before_ticks = ::GetTickCount ();
-
- Post_Process_Floodfill_For_Level_Features ();
- Compress_Sectors ();
- Generate_Portals ();
- DWORD after_ticks = ::GetTickCount ();
- WWDEBUG_SAY(("Time spent compressing: %d secs.\r\n", (after_ticks-before_ticks)/1000));
-
- //
- // Loop through the level and create any portals around
- // ladders, doors, etc that may be needed.
- //
- Apply_Level_Features ();
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Generate_Sectors
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Generate_Sectors (void)
- {
- //
- // Start floodfilling from each of the start points
- //
- for (int index = 0; index < m_StartPointList.Count (); index ++) {
- Vector3 start_pos = m_StartPointList[index];
- //
- // Normalize the starting position. We do this so that all the different
- // generation points will match up perfectly.
- //
- start_pos.X = (int(start_pos.X / m_SimBoundingBox.X)) * m_SimBoundingBox.X;
- start_pos.Y = (int(start_pos.Y / m_SimBoundingBox.Y)) * m_SimBoundingBox.Y;
- start_pos.Z += (m_SimBoundingBox.Z * 0.5F);
- //
- // Start floodfilling from this position
- //
- AABoxClass new_box;
- if (Try_Standing_Here (start_pos, &new_box)) {
- m_CurrentSector = Mark_Sector (new_box);
- Floodfill (start_pos);
- }
- }
- //
- // Process all the floodfill boxes that have been queued up
- //
- int compress_count = 0;
- while (m_FloodFillProcessList.Count () > 0) {
-
- //
- // Pop a floodfill box off the list and process its neighbors
- //
- m_CurrentSector = m_FloodFillProcessList[0];
- m_FloodFillProcessList.Delete (0);
- AABoxClass box = Get_Body_Box_Bounds (m_CurrentSector);
- Vector3 pos = box.Center;
- pos.Z = box.Center.Z - box.Extent.Z + (m_SimBoundingBox.Z * 0.5F);
- Floodfill (pos);
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Find_Ground
- //
- //////////////////////////////////////////////////////////////////////////
- bool
- PathfindSectorBuilderClass::Find_Ground (const Vector3 &pos, float *ground_pos)
- {
- bool retval = false;
- AABoxClass sweep_box;
- sweep_box.Center = pos;
- sweep_box.Center.Z += m_StepHeight;
- sweep_box.Extent = m_SimBoxExtents;
- sweep_box.Extent.Z = 0.1F;
- //
- // Sweep a very short box downwards to see where the ground is
- //
- CastResultStruct result;
- Vector3 sweep_vector (0, 0, -6.5F);
- PhysAABoxCollisionTestClass test( sweep_box,
- sweep_vector,
- &result,
- STATIC_OBJ_COLLISION_GROUP,
- COLLISION_TYPE_PHYSICAL);
- PhysicsSceneClass::Get_Instance ()->Cast_AABox (test);
- //
- // Check to see if we found a floor, and its valid to stand on.
- //
- if ( (result.StartBad == false) &&
- (result.Fraction < 1.0F) &&
- (result.Normal.Z > 0.71F) &&
- (m_AllowWaterFloodfill || (result.SurfaceType != SURFACE_TYPE_WATER)))
- {
- //
- // Calculate what z-position the ground is
- //
- (*ground_pos) = (sweep_box.Center.Z + (sweep_vector.Z * result.Fraction)) - sweep_box.Extent.Z;
- retval = true;
- }
- return retval;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Find_Ceiling
- //
- //////////////////////////////////////////////////////////////////////////
- bool
- PathfindSectorBuilderClass::Find_Ceiling (const Vector3 &pos, float *ceiling_pos)
- {
- bool retval = false;
- AABoxClass sweep_box;
- sweep_box.Center = pos;
- sweep_box.Center.Z += m_StepHeight;
- sweep_box.Extent = m_SimBoxExtents;
- sweep_box.Extent.Z = 0.1F;
- //
- // Sweep a very short box downwards to see where the ground is
- //
- CastResultStruct result;
- Vector3 sweep_vector (0, 0, 6.5F);
- PhysAABoxCollisionTestClass test( sweep_box,
- sweep_vector,
- &result,
- STATIC_OBJ_COLLISION_GROUP,
- COLLISION_TYPE_PHYSICAL);
- PhysicsSceneClass::Get_Instance ()->Cast_AABox (test);
- //
- // Check to ensure we didn't start the cast intersecting a poly
- //
- if (result.StartBad == false) {
-
- //
- // Calculate what the z-position of the ceiling is
- //
- (*ceiling_pos) = (sweep_box.Center.Z + (sweep_vector.Z * result.Fraction)) + sweep_box.Extent.Z;
- retval = true;
- }
- return retval;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Try_Moving_Here
- //
- //////////////////////////////////////////////////////////////////////////
- bool
- PathfindSectorBuilderClass::Try_Moving_Here
- (
- const Vector3 & start_pos,
- const Vector3 & expected_pos,
- AABoxClass * real_pos
- )
- {
- bool is_valid = false;
- float start_ground_pos = start_pos.Z - m_SimBoxExtents.Z;
- float curr_ground_pos = 0;
- //
- // Find the ground level where we were standing and the ground level where
- // we want to be standing
- //
- if (Find_Ground (expected_pos, &curr_ground_pos)) {
- //
- // Check to see if the character can step from the old position to the new one
- //
- float step_height = curr_ground_pos - start_ground_pos;
- if (step_height < m_StepHeight) {
- //
- // Find the ceiling
- //
- float curr_ceiling_pos = curr_ground_pos;
- Find_Ceiling (expected_pos, &curr_ceiling_pos);
- //
- // Can the character fit between the floor and ceiling without crouching?
- //
- if ((curr_ceiling_pos - curr_ground_pos) > m_SimBoundingBox.Z) {
- //
- // Success! Build a bounding box for the new position
- //
- real_pos->Extent.X = m_SimBoxExtents.X;
- real_pos->Extent.Y = m_SimBoxExtents.Y;
- real_pos->Extent.Z = m_SimBoxExtents.Z;
- real_pos->Center.X = expected_pos.X;
- real_pos->Center.Y = expected_pos.Y;
- real_pos->Center.Z = curr_ground_pos + m_SimBoxExtents.Z + WWMATH_EPSILON;
- is_valid = true;
- }
- }
- }
- return is_valid;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Try_Standing_Here
- //
- //////////////////////////////////////////////////////////////////////////
- bool
- PathfindSectorBuilderClass::Try_Standing_Here
- (
- const Vector3 & expected_pos,
- AABoxClass * real_pos
- )
- {
- bool is_valid = false;
- AABoxClass sweep_box;
- sweep_box.Center = expected_pos;
- sweep_box.Center.Z += m_StepHeight;
- sweep_box.Extent = m_SimSweepBox.Extent;
- sweep_box.Extent.Z -= m_StepHeight;
- //
- // Do a box cast to see if we can 'stand' here.
- //
- CastResultStruct result;
- PhysAABoxCollisionTestClass test( sweep_box,
- m_SimMovement,
- &result,
- STATIC_OBJ_COLLISION_GROUP,
- COLLISION_TYPE_PHYSICAL);
- test.CheckStaticObjs = true;
- test.CheckDynamicObjs = false;
- PhysicsSceneClass::Get_Instance ()->Cast_AABox (test);
- //
- // Is the start of the cast valid and is the polygon we
- // landed on flat enough to stand on?
- //
- if ((result.StartBad == false) && (result.Normal.Z > 0.71F)) {
- //
- // Are we standing on the ground? Is the ground a valid type?
- //
- bool on_ground = (result.Fraction < 1.0F);
- if (on_ground && (m_AllowWaterFloodfill || (result.SurfaceType != SURFACE_TYPE_WATER))) {
-
- //
- // Snap the x and y positions and calculate the z position
- // of the new box.
- //
- real_pos->Extent.X = sweep_box.Extent.X;
- real_pos->Extent.Y = sweep_box.Extent.Y;
- real_pos->Extent.Z = ((-m_SimMovement.Z * result.Fraction) * 0.5F) + (m_SimBoundingBox.Z * 0.5F);
- real_pos->Center.X = expected_pos.X;
- real_pos->Center.Y = expected_pos.Y;
- real_pos->Center.Z = (sweep_box.Center.Z + (m_SimBoundingBox.Z * 0.5F) - real_pos->Extent.Z) + 0.001F;
- is_valid = true;
- }
- }
- return is_valid;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Do_Physics_Sim
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Do_Physics_Sim
- (
- const Vector3 & start_pos,
- PATHFIND_DIR direction
- )
- {
- //
- // Determine where the next cell should be
- //
- Vector3 expected_pos = start_pos + m_DirInfo[direction].move;
- //
- // Do a quick-and-dirty test to see if we already 'know' about a
- // body-box in the requested direction.
- //
- bool found = false;
- FloodfillBoxClass *neighbor = m_CurrentSector->Peek_Neighbor (direction, false);
- if (neighbor != NULL) {
- m_SimSweepBox.Center = expected_pos;
- //
- // If the neighbor's bounding box completely CONTAINS the bounding
- // box we would have cast, then we can skip the cast and simply
- // mark the direction as 'traversible'
- //
- AABoxClass bounding_box = Get_Body_Box_Bounds (neighbor);
- found = bounding_box.Contains (m_SimSweepBox);
- float min1 = bounding_box.Center.Z - bounding_box.Extent.Z;
- float max1 = bounding_box.Center.Z + bounding_box.Extent.Z;
- float min2 = m_SimSweepBox.Center.Z - m_SimSweepBox.Extent.Z;
- float max2 = m_SimSweepBox.Center.Z + m_SimSweepBox.Extent.Z;
- found = (min1 <= min2) && (max1 >= max2);
- if (found) {
- m_CurrentSector->Set_Neighbor (direction, neighbor, true);
- }
- }
-
- //
- // Did the quick-and-dirty check fail? If so, then do the full box-cast
- //
- if (found == false) {
-
- Vector3 move_vector = (m_DirInfo[direction].move);
- Vector3 new_pos = start_pos + move_vector;
- AABoxClass new_box;
- //if (Try_Standing_Here (new_pos, &new_box)) {
- if (Try_Moving_Here (start_pos, new_pos, &new_box)) {
- Submit_Box (m_CurrentSector, new_box, direction);
- }
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Do_Real_Physics_Sim
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Do_Real_Physics_Sim
- (
- const Vector3 & start_pos,
- PATHFIND_DIR direction
- )
- {
- //
- // Determine where the next cell should be
- //
- Vector3 expected_pos = start_pos + m_DirInfo[direction].move;
- //
- // Do a quick-and-dirty test to see if we already 'know' about a
- // body-box in the requested direction.
- //
- bool found = false;
- FloodfillBoxClass *neighbor = m_CurrentSector->Peek_Neighbor (direction, false);
- if (neighbor != NULL) {
- m_SimSweepBox.Center = expected_pos;
- //
- // If the neighbor's bounding box completely CONTAINS the bounding
- // box we would have cast, then we can skip the cast and simply
- // mark the direction as 'traversible'
- //
- AABoxClass bounding_box = Get_Body_Box_Bounds (neighbor);
- found = bounding_box.Contains (m_SimSweepBox);
- float min1 = bounding_box.Center.Z - bounding_box.Extent.Z;
- float max1 = bounding_box.Center.Z + bounding_box.Extent.Z;
- float min2 = m_SimSweepBox.Center.Z - m_SimSweepBox.Extent.Z;
- float max2 = m_SimSweepBox.Center.Z + m_SimSweepBox.Extent.Z;
- found = (min1 <= min2) && (max1 >= max2);
- if (found) {
- m_CurrentSector->Set_Neighbor (direction, neighbor, true);
- }
- }
-
- //
- // Did the quick-and-dirty check fail? If so, then do the full box-cast
- //
- if (found == false) {
- Vector3 move_vector = (m_DirInfo[direction].move);
- Vector3 new_pos = start_pos + move_vector;
- AABoxClass test_box (start_pos, m_SimBoxExtents);
- test_box.Add_Box (AABoxClass (new_pos, m_SimBoxExtents));
- test_box.Center.Z += 0.1F;
- NonRefPhysListClass obj_list;
- PhysicsSceneClass::Get_Instance ()->Collect_Collideable_Objects (test_box, COLLISION_TYPE_PHYSICAL, true, false, &obj_list);
- if (obj_list.Count () == 0) {
- AABoxClass new_box;
- if (Try_Standing_Here (new_pos, &new_box)) {
- Submit_Box (m_CurrentSector, new_box, direction);
- }
- return ;
- } else {
-
- bool did_intersect = false;
- NonRefPhysListIterator it (&obj_list);
- for (it.First(); !it.Is_Done(); it.Next()) {
- PhysClass *phys_obj = it.Peek_Obj ();
- if (phys_obj != NULL) {
- RenderObjClass *model = phys_obj->Peek_Model ();
-
- AABoxIntersectionTestClass int_test (test_box, COLLISION_TYPE_PHYSICAL);
- if (model->Intersect_AABox (int_test)) {
- did_intersect = true;
- break;
- }
- }
- }
- if (did_intersect == false) {
- AABoxClass new_box;
- if (Try_Standing_Here (new_pos, &new_box)) {
- Submit_Box (m_CurrentSector, new_box, direction);
- }
-
- return ;
- }
- }
-
- _PhysSimObj->Set_Position (start_pos);
- _PhysSimObj->Set_Velocity (Vector3 (0, 0, 0));
- for (int attempt = 0; attempt < 20; attempt ++) {
- if (_PhysSimObj->Is_In_Contact ()) {
- break;
- }
- _PhysSimObj->Timestep (0.1F);
- }
- bool keep_going = true;
- for (attempt = 0; keep_going && (attempt < 20); attempt ++) {
- Vector3 curr_pos = _PhysSimObj->Get_Position ();
- Vector3 delta = (new_pos - curr_pos);
- delta.Z = 0;
- float delta_len = delta.Length ();
- if (delta_len < 0.05F && _PhysSimObj->Is_In_Contact ()) {
-
- AABoxClass new_box;
- new_box.Center = new_pos;
- new_box.Center.Z = curr_pos.Z;
- new_box.Extent = m_SimBoxExtents;
- Submit_Box (m_CurrentSector, new_box, direction);
- keep_going = false;
- } else {
-
- Vector3 x_axis = (new_pos - curr_pos);
- Vector3 z_axis = Vector3 (0, 0, 1);
- x_axis.Normalize ();
-
- Vector3 y_axis = Vector3::Cross_Product (x_axis, z_axis);
- Matrix3D new_tm (x_axis, y_axis, z_axis, curr_pos);
- _PhysSimObj->Set_Transform (new_tm);
- _PhysSimObj->Get_Controller ()->Reset ();
- _PhysSimObj->Get_Controller ()->Set_Move_Forward (0.09F);
- _PhysSimObj->Timestep (0.075F);
- }
- }
- /*AABoxClass new_box;
- if (Try_Standing_Here (new_pos, &new_box)) {
- Submit_Box (m_CurrentSector, new_box, direction);
- }*/
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Submit_Box
- //
- //////////////////////////////////////////////////////////////////////////
- FloodfillBoxClass *
- PathfindSectorBuilderClass::Submit_Box
- (
- FloodfillBoxClass * from_obj,
- const AABoxClass & new_box,
- PATHFIND_DIR direction
- )
- {
- //
- // Is this cell already marked?
- //
- Vector3 position = new_box.Center;
- position.Z = new_box.Center.Z - new_box.Extent.Z + (m_SimBoundingBox.Z * 0.5F);
- FloodfillBoxClass *occupant = Get_Sector_Occupant (position);
- if (occupant == NULL) {
-
- //
- // Mark this cell and add it to the list of sectors
- // that need to be recursed.
- //
- occupant = Mark_Sector (new_box);
- m_FloodFillProcessList.Add (occupant);
- //
- // Let the new occupant know where it came from (even if it can't get there itself).
- //
- occupant->Set_Neighbor (::Inverse_Pathfind_Dir (direction), from_obj, false);
- m_TotalBoxCount ++;
- }
- //
- // Let the sector know who its new neighbor is
- //
- if (occupant != from_obj) {
- from_obj->Set_Neighbor (direction, occupant, true);
- }
-
- return occupant;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Floodfill
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Floodfill (const Vector3 &start_pos)
- {
- //
- // Do a simulation in each of the four directions from the
- // current cell.
- //
- if (m_pDialog->Was_Cancelled () == false) {
-
- //
- // Loop through and check any neighbors we don't already know about
- //
- for (int index = 0; index < DIR_MAX; index ++) {
- if (m_CurrentSector->Peek_Neighbor (PATHFIND_DIR(index)) == NULL) {
- Do_Physics_Sim (start_pos, PATHFIND_DIR(index));
- m_BeforeUpdateCount ++;
- }
- }
- //
- // Check to see if we need to climb up any ladders, open doors, etc...
- //
- Check_For_Level_Feature (m_CurrentSector);
- //
- // Let the current sector 'know' its been completely processed
- //
- m_CurrentSector->Needs_Processing (false);
- //
- // Update the UI
- //
- if (m_BeforeUpdateCount > 512) {
- CString message;
- message.Format ("Floodfilled %d boxes. Approx total boxes: %d", m_TotalBoxCount, m_TotalBoxGuess);
- m_pDialog->Set_Status (message, float (m_TotalBoxCount) / float (m_TotalBoxGuess));
- m_BeforeUpdateCount = 0;
- }
- }
-
- //
- // Allow windows messages to be processed
- //
- static int message_pump = 0;
- message_pump++;
- if (message_pump > 5000) {
- General_Pump_Messages ();
- message_pump = 0;
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Get_Sector_Occupant
- //
- //////////////////////////////////////////////////////////////////////////
- FloodfillBoxClass *
- PathfindSectorBuilderClass::Get_Sector_Occupant (const Vector3 &pos)
- {
- //
- // If we found any objects in the culling system, then the sector is occupied
- //
- return m_BodyBoxCullingSystem.Find_Box (pos);
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Mark_Sector
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Mark_Sector (FloodfillBoxClass *body_box)
- {
- //
- // Add the culling object to our culling system. (This
- // effectively marks the cell as 'occupied').
- //
- body_box->Add_Ref ();
- m_BodyBoxCullingSystem.Add_Box (body_box);
- FloodfillBoxClass::Add (body_box);
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Mark_Sector
- //
- //////////////////////////////////////////////////////////////////////////
- FloodfillBoxClass *
- PathfindSectorBuilderClass::Mark_Sector (const AABoxClass &bounding_box)
- {
- //
- // Create a culling system object to represent this 'sector' and
- // add it to our AABTree culling system. (This effectively marks
- // the cell as 'occupied').
- //
- FloodfillBoxClass *body_box = new FloodfillBoxClass;
- body_box->Set_Position (bounding_box.Center);
- Mark_Sector (body_box);
- body_box->Release_Ref ();
- return body_box;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Determine_Height
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Determine_Height
- (
- FloodfillBoxClass * start_box,
- float * min_z_pos,
- float * max_z_pos
- )
- {
- AABoxClass box = Get_Body_Box_Bounds (start_box);
- float z_extent = box.Extent.Z;
- box.Extent.X -= WWMATH_EPSILON;
- box.Extent.Y -= WWMATH_EPSILON;
- box.Extent.Z = 500.0F;
- //
- // Loop over all the body-boxes that exist above or below the starting box
- //
- m_BodyBoxCullingSystem.Collect_Boxes (box);
- DynamicVectorClass<FloodfillBoxClass *> &list = m_BodyBoxCullingSystem.Get_Collection_List ();
- for (int index = 0; index < list.Count (); index ++) {
- FloodfillBoxClass *body_box = list[index];
- //
- // Only check 'other' boxes
- //
- if (body_box != start_box) {
- AABoxClass curr_box = Get_Body_Box_Bounds (body_box);
- //
- // Determine the min and max z-positions of the current box
- //
- float curr_min_z = curr_box.Center.Z - (curr_box.Extent.Z + WWMATH_EPSILON);
- float curr_max_z = curr_box.Center.Z + (curr_box.Extent.Z + WWMATH_EPSILON);
- //
- // Return new minimum and maximum
- //
- if (curr_max_z < box.Center.Z && curr_max_z > (*min_z_pos)) {
- (*min_z_pos) = curr_max_z;
- }
-
- if (curr_min_z > box.Center.Z && curr_min_z < (*max_z_pos)) {
- (*max_z_pos) = curr_min_z;
- }
- }
- }
- /*float delta_up = (*max_z_pos) - box.Center.Z;
- float delta_down = box.Center.Z - (*min_z_pos);
- delta_up = max (delta_up / 2.0F, (z_extent + WWMATH_EPSILON));
- delta_down = max (delta_down / 2.0F, (z_extent + WWMATH_EPSILON));
- (*max_z_pos) = box.Center.Z + delta_up;
- (*min_z_pos) = box.Center.Z - delta_down;*/
- //
- // Make sure a box's min position is at least the
- // bottom of its box.
- //
- float box_bottom = (box.Center.Z - z_extent);
- if ((*min_z_pos) > (box_bottom - 0.5F)) {
- (*min_z_pos) = (box_bottom - 0.5F);
- }
-
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Build_Height_Values
- //
- //////////////////////////////////////////////////////////////////////////
- int
- PathfindSectorBuilderClass::Build_Height_Values (void)
- {
- int before_ticks = ::GetTickCount ();
- int total_box_count = 0;
- int box_count = 0;
- //
- // Backup the body-box list to ensure we delete them all...
- //
- for ( FloodfillBoxClass *body_box = FloodfillBoxClass::Get_First ();
- body_box != NULL;
- body_box = body_box->Get_Next ())
- {
- m_BodyBoxReleaseList.Add (body_box);
- Vector3 pos = body_box->Get_Position ();
- float min_z = pos.Z - (m_SimBoundingBox.Z * 500.0F);
- float max_z = pos.Z + (m_SimBoundingBox.Z * 500.0F);
- Determine_Height (body_box, &min_z, &max_z);
- body_box->Set_Min_Z_Pos (min_z);
- body_box->Set_Max_Z_Pos (max_z);
- total_box_count ++;
- }
- int after_ticks = ::GetTickCount ();
- WWDEBUG_SAY(("Time spent generating z-values: %d secs.\r\n", (after_ticks-before_ticks)/1000));
- return total_box_count;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Can_Traverse
- //
- //////////////////////////////////////////////////////////////////////////
- inline bool
- Can_Traverse (FloodfillBoxClass *cell, PATHFIND_DIR dir)
- {
- //
- // Make sure the cell passes the basic 'traverse-requirements'
- // to move in the given direction
- //
- return ( cell != NULL &&
- cell->Needs_Processing () == false &&
- cell->Is_Taken () == false);
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Check_Directions
- //
- //////////////////////////////////////////////////////////////////////////
- inline bool
- Check_Directions (FloodfillBoxClass *cell, int dir_mask)
- {
- bool is_valid = true;
- //
- // Check to make sure we can walk from the cell to its
- // adjacent boxes (Only checking the requested directions).
- //
- for (int mask = 1; mask < MASK_MAX; mask <<= 1) {
- if (dir_mask & mask) {
- PATHFIND_DIR check_dir = ::Mask_to_Dir (DIRECTION_MASK(mask));
- is_valid &= cell->Is_Two_Way_Traversible (check_dir);
- }
- }
- return is_valid;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Move_Dir
- //
- //////////////////////////////////////////////////////////////////////////
- inline FloodfillBoxClass *
- PathfindSectorBuilderClass::Move_Dir (FloodfillBoxClass *start_box, PATHFIND_DIR dir, int dir_mask)
- {
- //
- // Peek a the cell in the given direction
- //
- FloodfillBoxClass *retval = NULL;
- FloodfillBoxClass *new_cell = start_box->Peek_Neighbor (dir);
- //
- // Does this cell pass our traversal requirements?
- //
- if ( start_box->Is_Two_Way_Traversible (dir) &&
- Can_Traverse (new_cell, dir) &&
- Check_Directions (new_cell, dir_mask))
- {
- //
- // Add this cell's min and max heights to the height-watcher.
- // This is done so we can break the sector before it intersects
- // a sector above or below it
- //
- m_HeightWatcher.Add_Lower_Bound (new_cell->Get_Min_Z_Pos ());
- m_HeightWatcher.Add_Upper_Bound (new_cell->Get_Max_Z_Pos ());
- //
- // Is this cell within the min and max height values?
- //
- AABoxClass box = Get_Body_Box_Bounds (new_cell);
- if ( m_HeightWatcher.Is_Current_Pos_Valid (box.Center.Z - box.Extent.Z) &&
- m_HeightWatcher.Is_Current_Pos_Valid (box.Center.Z + box.Extent.Z))
- {
- retval = new_cell;
- }
- }
- return retval;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Check_Edge
- //
- //////////////////////////////////////////////////////////////////////////
- inline bool
- PathfindSectorBuilderClass::Check_Edge
- (
- FloodfillBoxClass * start_box,
- int count_left,
- int count_right,
- int count_up,
- int count_down,
- PATHFIND_DIR move_dir
- )
- {
- bool retval = false;
- //
- // Check the first cell, can we move in the requested direction?
- //
- int dir_mask = 0;
- dir_mask |= (count_left > 0) ? MASK_LEFT : 0;
- dir_mask |= (count_right > 0) ? MASK_RIGHT : 0;
- dir_mask |= (count_up > 0) ? MASK_UP : 0;
- dir_mask |= (count_down > 0) ? MASK_DOWN : 0;
- if (Move_Dir (start_box, move_dir, dir_mask) != NULL) {
- retval = true;
- }
- //
- // Check the given number of cells in the left direction
- //
- FloodfillBoxClass *curr_cell = start_box;
- for (int x = 0; retval && x < count_left; x++) {
-
- //
- // Can we move one step in this direction?
- //
- curr_cell = Move_Dir (curr_cell, DIR_LEFT, 0);
- if (curr_cell != NULL) {
-
- //
- // Can this new cell move in the movement direction AND
- // can its new cell move right and, if necessary, left?
- //
- dir_mask = MASK_RIGHT;
- dir_mask |= ((x + 1) < count_left) ? MASK_LEFT : 0;
- retval = (Move_Dir (curr_cell, move_dir, dir_mask) != NULL);
-
- } else {
- retval = false;
- }
- }
- //
- // Check the given number of cells in the left direction
- //
- curr_cell = start_box;
- for (x = 0; retval && x < count_right; x++) {
-
- //
- // Can we move one step in this direction?
- //
- curr_cell = Move_Dir (curr_cell, DIR_RIGHT, 0);
- if (curr_cell != NULL) {
-
- //
- // Can this new cell move in the movement direction AND
- // can its new cell move left and, if necessary, right?
- //
- dir_mask = MASK_LEFT;
- dir_mask |= ((x + 1) < count_right) ? MASK_RIGHT : 0;
- retval = (Move_Dir (curr_cell, move_dir, dir_mask) != NULL);
-
- } else {
- retval = false;
- }
- }
- //
- // Check the given number of cells in the up direction
- //
- curr_cell = start_box;
- for (int y = 0; retval && y < count_up; y++) {
-
- //
- // Can we move one step in this direction?
- //
- curr_cell = Move_Dir (curr_cell, DIR_UP, 0);
- if (curr_cell != NULL) {
-
- //
- // Can this new cell move in the movement direction AND
- // can its new cell move down and, if necessary, up?
- //
- dir_mask = MASK_DOWN;
- dir_mask |= ((y + 1) < count_up) ? MASK_UP : 0;
- retval = (Move_Dir (curr_cell, move_dir, dir_mask) != NULL);
-
- } else {
- retval = false;
- }
- }
- //
- // Check the given number of cells in the down direction
- //
- curr_cell = start_box;
- for (y = 0; retval && y < count_down; y++) {
-
- //
- // Can we move one step in this direction?
- //
- curr_cell = Move_Dir (curr_cell, DIR_DOWN, 0);
- if (curr_cell != NULL) {
-
- //
- // Can this new cell move in the movement direction AND
- // can its new cell move up and, if necessary, down?
- //
- dir_mask = MASK_UP;
- dir_mask |= ((y + 1) < count_down) ? MASK_DOWN : 0;
- retval = (Move_Dir (curr_cell, move_dir, dir_mask) != NULL);
-
- } else {
- retval = false;
- }
- }
- return retval;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Find_Perimeter
- //
- //////////////////////////////////////////////////////////////////////////
- FloodfillBoxClass *
- PathfindSectorBuilderClass::Find_Perimeter (FloodfillBoxClass *start_box, BOX_PERIMETER *perimeter)
- {
- FloodfillBoxClass *up_cell = start_box;
- FloodfillBoxClass *down_cell = start_box;
- FloodfillBoxClass *left_cell = start_box;
- FloodfillBoxClass *right_cell = start_box;
-
- //
- // Determine what the maximum number of cells in a given direction can be
- //
- int max_dim = m_MaxSectorDim / max (m_SimBoundingBox.X, m_SimBoundingBox.Y);
- //
- // Create an object that will allow us to break the sector if
- // it would intersect with a sector above or below us.
- //
- Vector3 pos = start_box->Get_Position ();
- m_HeightWatcher.Initialize (pos.Z - (m_SimBoundingBox.Z * 500.0F), pos.Z + (m_SimBoundingBox.Z * 500.0F), pos.Z);
-
- do
- {
- //
- // Expand the box 'up' one row (if possible)
- //
- if (perimeter->stop_up == false) {
- perimeter->stop_up = true;
-
- FloodfillBoxClass *new_cell = Move_Dir (up_cell, DIR_UP, 0);
- if (new_cell != NULL) {
- if (Check_Edge (up_cell, perimeter->count_left, perimeter->count_right, 0, 0, DIR_UP)) {
- up_cell = new_cell;
- perimeter->count_up ++;
- perimeter->stop_up = false;
- }
- }
- }
- //
- // Expand the box 'down' one row (if possible)
- //
- if (perimeter->stop_down == false) {
- perimeter->stop_down = true;
- FloodfillBoxClass *new_cell = Move_Dir (down_cell, DIR_DOWN, 0);
- if (new_cell != NULL) {
- if (Check_Edge (down_cell, perimeter->count_left, perimeter->count_right, 0, 0, DIR_DOWN)) {
- down_cell = new_cell;
- perimeter->count_down ++;
- perimeter->stop_down = false;
- }
- }
- }
- //
- // Expand the box 'left' one column (if possible)
- //
- if (perimeter->stop_left == false) {
- perimeter->stop_left = true;
- FloodfillBoxClass *new_cell = Move_Dir (left_cell, DIR_LEFT, 0);
- if (new_cell != NULL) {
- if (Check_Edge (left_cell, 0, 0, perimeter->count_up, perimeter->count_down, DIR_LEFT)) {
- left_cell = new_cell;
- perimeter->count_left ++;
- perimeter->stop_left = false;
- }
- }
- }
- //
- // Expand the box 'right' one column (if possible)
- //
- if (perimeter->stop_right == false) {
- perimeter->stop_right = true;
- FloodfillBoxClass *new_cell = Move_Dir (right_cell, DIR_RIGHT, 0);
- if (new_cell != NULL) {
- if (Check_Edge (right_cell, 0, 0, perimeter->count_up, perimeter->count_down, DIR_RIGHT)) {
- right_cell = new_cell;
- perimeter->count_right ++;
- perimeter->stop_right = false;
- }
- }
- }
- //
- // Check to see if we are going to exceed the maximum sector size in either
- // direction.
- //
- if (perimeter->count_left + perimeter->count_right >= max_dim) {
- perimeter->stop_left = true;
- perimeter->stop_right = true;
- }
- if (perimeter->count_up + perimeter->count_down >= max_dim) {
- perimeter->stop_up = true;
- perimeter->stop_down = true;
- }
- }
- while ( perimeter->stop_up == false || perimeter->stop_down == false ||
- perimeter->stop_left == false || perimeter->stop_right == false);
-
- //
- // Some debug checking to make sure we built the region
- // correctly.
- //
- FloodfillBoxClass *upper_left1 = up_cell;
- FloodfillBoxClass *upper_left2 = left_cell;
- for (int index = 0; index < perimeter->count_left; index ++) {
- upper_left1 = upper_left1->Peek_Neighbor (DIR_LEFT);
- }
- for (index = 0; index < perimeter->count_up; index ++) {
- upper_left2 = upper_left2->Peek_Neighbor (DIR_UP);
- }
- WWASSERT (upper_left1 == upper_left2);
- if (upper_left1 != upper_left2) {
- CString message;
- message.Format ("upper_left1 = %d\nupper_left2 = %d\nup_cell = %d\nleft_cell = %d", upper_left1, upper_left2, up_cell, left_cell);
- ::MessageBox (NULL, message, "Info", MB_OK);
- }
- return upper_left1;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Compress_Sectors
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Compress_Sectors (DynamicVectorClass<AABoxClass> *box_list)
- {
- //
- // Generate a set of maximum and minimum height values
- // for each box
- //
- int total_box_count = Build_Height_Values ();
- int box_count = 0;
- bool keep_going = true;
- FloodfillBoxClass *start_box = NULL;
- FloodfillBoxClass *old_start_box = NULL;
- BOX_PERIMETER old_perimeter = { 0 };
- //
- // Loop over all the boxes and compress them into rectangular regions
- //
- while (keep_going && ((start_box = FloodfillBoxClass::Get_First ()) != NULL)) {
- //
- // Don't compress any boxes that still need processing
- //
- if (start_box->Needs_Processing ()) {
- start_box->Remove ();
- continue;
- }
- //
- // Perform a simple check to make sure we don't keep getting the same
- // box off the top of the list (this should never, ever, ever, happen).
- //
- if ( (start_box == old_start_box) &&
- (FloodfillBoxClass::Get_First () != FloodfillBoxClass::Get_Last ()))
- {
- ::MessageBox (::AfxGetMainWnd ()->m_hWnd, "Found the same box twice...", "Compression Error", MB_OK | MB_ICONERROR);
- keep_going = false;
- }
- old_start_box = start_box;
- //
- // Find the largest rectangular region that this box can be part of
- //
- BOX_PERIMETER perimeter = { 0 };
- FloodfillBoxClass *upper_left_cell = Find_Perimeter (start_box, &perimeter);
- old_perimeter = perimeter;
- //
- // How big is the new rectangular region?
- //
- int width = (perimeter.count_left + perimeter.count_right) + 1;
- int height = (perimeter.count_up + perimeter.count_down) + 1;
- //
- // If the area is of an exceptable size, then compress it into a sector
- //
- if (width > 2 || height > 2) {
-
- int skipped_count = start_box->Get_Compress_Skipped_Count ();
- int min_dim = min (width, height);
- //
- // Should we skip this box in hopes that we find a better sector later?
- //
- if (skipped_count <= (12 - min_dim)) {
- start_box->Inc_Compress_Skipped_Count ();
- start_box->Remove ();
- FloodfillBoxClass::Add (start_box);
- } else {
- //
- // Compress the region into a new pathfinding sector
- //
- PathfindSectorClass *sector = Build_Sector (upper_left_cell, width, height);
- if (sector != NULL) {
- //
- // Sumbit this sector
- //
- if (box_list != NULL) {
- AABoxClass bbox = sector->Get_Bounding_Box ();
- box_list->Add (bbox);
- MEMBER_RELEASE (sector);
- } else {
- PathfindClass::Get_Instance ()->Add_Sector (sector);
- }
- }
- //
- // Update the UI
- //
- box_count += (width * height);
- CString message;
- message.Format ("Compressed %d of %d boxes.", box_count, total_box_count);
- m_pDialog->Set_Status (message, ((float)box_count) / ((float)total_box_count));
- }
- } else {
-
- //
- // Sector is too small, so remove the box
- // from the system.
- //
- start_box->Set_Taken ();
- start_box->Remove ();
- }
- }
-
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Filter_Useless_Sectors
- //
- //////////////////////////////////////////////////////////////////////////
- /*void
- PathfindSectorBuilderClass::Filter_Useless_Sectors (DynamicVectorClass<PathfindSectorClass *> §or_list)
- {
- DynamicVectorClass<PathfindSectorClass *> final_sector_list;
- for (int index = 0; index < sector_list.Count (); index ++) {
- PathfindSectorClass *sector = sector_list[index];
- bool found_usefull_portal = false;
- int portal_count = sector->Get_Portal_Count ();
- for (int portal_index = 0; portal_index < portal_count; portal_index ++) {
-
- }
- if (found_usefull_portal) {
- final_sector_list.Add (sector);
- }
- }
- //
- // Add all the sectors to the pathfind system
- //
- for (index = 0; index < final_sector_list.Count (); index ++) {
- }
- return ;
- }*/
- //////////////////////////////////////////////////////////////////////////
- //
- // Scan_Edge
- //
- //////////////////////////////////////////////////////////////////////////
- void
- Scan_Edge
- (
- FloodfillBoxClass * start_obj,
- int cell_count,
- PATHFIND_DIR check_dir,
- PATHFIND_DIR move_dir,
- int * best_count
- )
- {
- FloodfillBoxClass * best_first_cell = 0;
- FloodfillBoxClass * first_cell = NULL;
- int count = 0;
- //
- // Go along the edge
- //
- FloodfillBoxClass *box_obj = start_obj;
- for (int box_index = 0; box_index < cell_count; box_index ++) {
- //
- // Can we traverse to the left and back?
- //
- if (box_obj->Is_Two_Way_Traversible (check_dir)) {
- //
- // Start recording this run
- //
- if (first_cell == NULL) {
- first_cell = box_obj;
- count = 1;
- } else {
- count ++;
- }
- } else {
-
- //
- // Is this the best run we've found?
- //
- if (count > (*best_count)) {
- best_first_cell = first_cell;
- (*best_count) = count;
- }
- //
- // Reset
- //
- first_cell = NULL;
- count = 0;
- }
- //
- // Move to the next edge cell
- //
- box_obj = box_obj->Peek_Neighbor (move_dir);
- }
- //
- // Is this the best run we've found?
- //
- if (count > (*best_count)) {
- best_first_cell = first_cell;
- (*best_count) = count;
- }
- return ;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Is_Valid_Sector
- //
- //////////////////////////////////////////////////////////////////////////
- bool
- PathfindSectorBuilderClass::Is_Valid_Sector
- (
- FloodfillBoxClass ** upper_left_ptr,
- int & cells_right,
- int & cells_down
- )
- {
- bool retval = true;
- //
- // Is this sector to small?
- //
- if (cells_right < 3 || cells_down < 3) {
- retval = false;
- if (cells_right < 3) {
- FloodfillBoxClass *ul_ptr = (*upper_left_ptr);
- FloodfillBoxClass *ur_ptr = (*upper_left_ptr)->Find_Relative (cells_right - 1, 0);
-
- //
- // Determine if either edge can enter an adjacent sector. This
- // would make the sector walkable
- //
- int best_count = 0;
- Scan_Edge (ul_ptr, cells_down, DIR_LEFT, DIR_DOWN, &best_count);
- Scan_Edge (ur_ptr, cells_down, DIR_RIGHT, DIR_DOWN, &best_count);
-
- //
- // Was this run good enough?
- //
- retval = (best_count >= 3);
- } else {
- FloodfillBoxClass *ul_ptr = (*upper_left_ptr);
- FloodfillBoxClass *ll_ptr = (*upper_left_ptr)->Find_Relative (0, cells_down - 1);
- //
- // Determine if either edge can enter an adjacent sector. This
- // would make the sector walkable
- //
- int best_count = 0;
- Scan_Edge (ul_ptr, cells_right, DIR_UP, DIR_RIGHT, &best_count);
- Scan_Edge (ll_ptr, cells_right, DIR_DOWN, DIR_RIGHT, &best_count);
-
- //
- // Was this run good enough?
- //
- retval = (best_count >= 3);
- }
- }
- return retval;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Build_Sector
- //
- //////////////////////////////////////////////////////////////////////////
- PathfindSectorClass *
- PathfindSectorBuilderClass::Build_Sector
- (
- FloodfillBoxClass * upper_left_ptr,
- int cells_right,
- int cells_down
- )
- {
- Vector3 min_point (100000.0F, 100000.0F, 100000.0F);
- Vector3 max_point (-100000.0F, -100000.0F, -100000.0F);
- //
- // Check to see if this sector meets are minimum requirements
- //
- bool is_valid = true;//Is_Valid_Sector (&upper_left_ptr, cells_right, cells_down);
- //
- // Allocate a new sector
- //
- PathfindSectorClass *sector = NULL;
- if (is_valid) {
- sector = new PathfindSectorClass;
- }
-
- //
- // Remove all the cells that compose this area from the list
- //
- FloodfillBoxClass *curr_cell = upper_left_ptr;
- for (int right = 0; (right < cells_right); right ++) {
-
- FloodfillBoxClass *down_obj = curr_cell;
- for (int down = 0; (down < cells_down); down ++) {
-
- AABoxClass bounding_box = Get_Body_Box_Bounds (down_obj);
-
- min_point.X = min (min_point.X, bounding_box.Center.X - bounding_box.Extent.X);
- min_point.Y = min (min_point.Y, bounding_box.Center.Y - bounding_box.Extent.Y);
- min_point.Z = min (min_point.Z, bounding_box.Center.Z - bounding_box.Extent.Z);
- max_point.X = max (max_point.X, bounding_box.Center.X + bounding_box.Extent.X);
- max_point.Y = max (max_point.Y, bounding_box.Center.Y + bounding_box.Extent.Y);
- max_point.Z = max (max_point.Z, bounding_box.Center.Z + bounding_box.Extent.Z);
-
- WWASSERT (down_obj->Is_Taken () == false);
- if (is_valid) {
- down_obj->Set_Sector (sector);
- }
- down_obj->Remove ();
- down_obj->Set_Taken ();
- //
- // Is this an edge case? (If so its a possible portal)
- //
- if ( (down == 0) ||
- (right == 0) ||
- (down == (cells_down - 1)) ||
- (right == (cells_right - 1)))
- {
- if (is_valid) {
- m_PossiblePortalList.Add (down_obj);
- }
- }
- //
- // Advance to the next box down
- //
- down_obj = down_obj->Peek_Neighbor (DIR_DOWN);
- }
- //
- // Advance to the next box right
- //
- curr_cell = curr_cell->Peek_Neighbor (DIR_RIGHT);
- }
- //
- // Calculate this sector's bounding box
- //
- if (is_valid) {
- AABoxClass bounding_box;
- bounding_box.Center = min_point + ((max_point - min_point) * 0.5F);
- bounding_box.Extent.X = (max_point.X - min_point.X) * 0.5F;
- bounding_box.Extent.Y = (max_point.Y - min_point.Y) * 0.5F;
- bounding_box.Extent.Z = (max_point.Z - min_point.Z) * 0.5F;
- sector->Set_Bounding_Box (bounding_box);
- }
- return sector;
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // Generate_Portals
- //
- //////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Generate_Portals (void)
- {
- //
- // Loop through all the body-boxes that are possible portals
- //
- for (int index = 0; index < m_PossiblePortalList.Count (); index ++) {
- FloodfillBoxClass *cull_obj = m_PossiblePortalList[index];
-
- PathfindSectorClass *sector = cull_obj->Peek_Sector ();
- if ((sector != NULL) && sector->Is_Valid ()) {
-
- const AABoxClass &box = sector->Get_Bounding_Box ();
- Vector3 portal_size = m_SimBoundingBox;
- portal_size.Z = box.Extent.Z * 2;
- float z_pos = box.Center.Z - box.Extent.Z;
- //
- // 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)) {
-
- //
- // Create the portal
- //
- cull_obj->Make_Portal ((PATHFIND_DIR)dir, portal_size, z_pos, 0.75F);
- }
- }
- }
- }
- m_PossiblePortalList.Delete_All ();
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Free_Floodfill_Boxes
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Free_Floodfill_Boxes (void)
- {
- //
- // Loop over all the floodfill boxes
- //
- for (int index = 0; index < m_BodyBoxReleaseList.Count (); index ++) {
-
- //
- // Remove the floodfill box from the culling system and
- // free our hold on it
- //
- FloodfillBoxClass *body_box = m_BodyBoxReleaseList[index];
- body_box->Reset_Portal_Info ();
- body_box->Set_Taken (false);
- body_box->Set_Sector (NULL);
- body_box->Remove ();
- REF_PTR_RELEASE (body_box);
- }
- //
- // Reset our systems
- //
- m_BodyBoxCullingSystem.Reset ();
- m_BodyBoxReleaseList.Delete_All ();
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Cleanup_Level_Features
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Cleanup_Level_Features (void)
- {
- //
- // Loop over all the transition objects and remove them from the
- // culling system
- //
- int count = m_LevelFeatureList.Count ();
- for (int index = 0; index < count; index ++) {
- LevelFeatureClass *cull_obj = m_LevelFeatureList[index];
- m_LevelFeatureCullingSystem.Remove_Object (cull_obj);
- MEMBER_RELEASE (cull_obj);
- }
- m_LevelFeatureList.Delete_All ();
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Detect_Level_Features
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Detect_Level_Features (void)
- {
- //
- // Detect the different types of level features
- //
- Detect_Doors ();
- Detect_Elevators ();
- Detect_Level_Transitions ();
- //
- // Optimize the level feature culling system
- //
- m_LevelFeatureCullingSystem.Re_Partition ();
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Detect_Elevators
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Detect_Elevators (void)
- {
- //
- // Get the list of all static objects from the physics scene
- //
- RefPhysListIterator iterator = ::Get_Scene_Editor ()->Get_Static_Object_Iterator ();
- for (iterator.First (); !iterator.Is_Done (); iterator.Next ()) {
- //
- // Is this object an elevator?
- //
- PhysClass *phys_obj = iterator.Peek_Obj ();
- ElevatorPhysClass *elevator = phys_obj->As_ElevatorPhysClass ();
- if (elevator != NULL) {
-
- const ElevatorPhysDefClass *definition = elevator->Get_ElevatorPhysDef ();
- //
- // Get information about the elevator
- //
- OBBoxClass lower_call;
- OBBoxClass upper_call;
- OBBoxClass lower_inside;
- OBBoxClass upper_inside;
- const Matrix3D &tm = elevator->Get_Transform ();
- OBBoxClass::Transform (tm, definition->Get_Zone (ZONE_LOWER_CALL), &lower_call);
- OBBoxClass::Transform (tm, definition->Get_Zone (ZONE_UPPER_CALL), &upper_call);
- OBBoxClass::Transform (tm, definition->Get_Zone (ZONE_LOWER_INSIDE), &lower_inside);
- OBBoxClass::Transform (tm, definition->Get_Zone (ZONE_UPPER_INSIDE), &upper_inside);
- //
- // Create a box that bounds the area the unit will actually be 'moving' in
- //
- AABoxClass bottom_box;
- AABoxClass top_box;
- bottom_box.Center = lower_inside.Center;
- top_box.Center = upper_inside.Center;
- top_box.Center.Z += m_SimBoxExtents.Z;
- lower_inside.Compute_Axis_Aligned_Extent (&bottom_box.Extent);
- upper_inside.Compute_Axis_Aligned_Extent (&top_box.Extent);
- AABoxClass teleport_zone = bottom_box;
- teleport_zone.Add_Box (top_box);
- //
- // Create a level feature for going UP the elevator
- //
- LevelFeatureClass *up_feature = new LevelFeatureClass;
- up_feature->Set_Type (LevelFeatureClass::TYPE_ELEVATOR);
- up_feature->Set_Start (lower_call);
- up_feature->Set_End (upper_call);
- up_feature->Set_End_TM (Matrix3D (upper_call.Center));
- up_feature->Set_Teleport_Zone (teleport_zone);
- up_feature->Set_Mechanism_ID (elevator->Get_ID ());
- //
- // Create a level feature for going DOWN the elevator
- //
- LevelFeatureClass *down_feature = new LevelFeatureClass;
- down_feature->Set_Type (LevelFeatureClass::TYPE_ELEVATOR);
- down_feature->Set_Start (upper_call);
- down_feature->Set_End (lower_call);
- down_feature->Set_End_TM (Matrix3D (lower_call.Center));
- down_feature->Set_Teleport_Zone (teleport_zone);
- down_feature->Set_Mechanism_ID (elevator->Get_ID ());
- //
- // Add the level features to the culling system
- //
- m_LevelFeatureCullingSystem.Add_Object (up_feature);
- m_LevelFeatureCullingSystem.Add_Object (down_feature);
- m_LevelFeatureList.Add (up_feature);
- m_LevelFeatureList.Add (down_feature);
- }
- }
-
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Detect_Doors
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Detect_Doors (void)
- {
- //
- // Get the list of all static objects from the physics scene
- //
- RefPhysListIterator iterator = ::Get_Scene_Editor ()->Get_Static_Object_Iterator ();
- for (iterator.First (); !iterator.Is_Done (); iterator.Next ()) {
- //
- // Is this object an elevator?
- //
- PhysClass *phys_obj = iterator.Peek_Obj ();
- DoorPhysClass *door = phys_obj->As_DoorPhysClass ();
- if ( door != NULL &&
- door->Get_DoorPhysDef () != NULL &&
- door->Get_DoorPhysDef ()->Is_Vehicle_Door () == false)
- {
- const DoorPhysDefClass *definition = door->Get_DoorPhysDef ();
- //
- // Get the door's trigger zones
- //
- const Matrix3D &tm = door->Get_Transform ();
- OBBoxClass trigger_zone1;
- OBBoxClass trigger_zone2;
- OBBoxClass::Transform (tm, definition->Get_Trigger_Zone1 (), &trigger_zone1);
- OBBoxClass::Transform (tm, definition->Get_Trigger_Zone2 (), &trigger_zone2);
- //
- // Create a box that bounds the area the unit will actually be 'moving' in
- //
- AABoxClass box1;
- AABoxClass box2;
- box1.Center = trigger_zone1.Center;
- box2.Center = trigger_zone2.Center;
- trigger_zone1.Compute_Axis_Aligned_Extent (&box1.Extent);
- trigger_zone2.Compute_Axis_Aligned_Extent (&box2.Extent);
- AABoxClass teleport_zone = box1;
- teleport_zone.Add_Box (box2);
- //
- // Create a level feature for going one direction through the door
- //
- LevelFeatureClass *feature1 = new LevelFeatureClass;
- feature1->Set_Type (LevelFeatureClass::TYPE_DOOR);
- feature1->Set_Start (trigger_zone1);
- feature1->Set_End (trigger_zone2);
- feature1->Set_End_TM (Matrix3D (trigger_zone2.Center));
- feature1->Set_Teleport_Zone (teleport_zone);
- feature1->Set_Mechanism_ID (door->Get_ID ());
- //
- // Create a level feature for going the other direction through the door
- //
- LevelFeatureClass *feature2 = new LevelFeatureClass;
- feature2->Set_Type (LevelFeatureClass::TYPE_DOOR);
- feature2->Set_Start (trigger_zone2);
- feature2->Set_End (trigger_zone1);
- feature2->Set_End_TM (Matrix3D (trigger_zone1.Center));
- feature2->Set_Teleport_Zone (teleport_zone);
- feature2->Set_Mechanism_ID (door->Get_ID ());
- //
- // Add the level features to the culling system
- //
- m_LevelFeatureCullingSystem.Add_Object (feature1);
- m_LevelFeatureCullingSystem.Add_Object (feature2);
- m_LevelFeatureList.Add (feature1);
- m_LevelFeatureList.Add (feature2);
- }
- }
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Detect_Level_Transitions
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Detect_Level_Transitions (void)
- {
- int ladder_index = 0;
- //
- // Loop through all the transitions in the level
- //
- TransitionNodeClass *node = NULL;
- for (node = (TransitionNodeClass *)NodeMgrClass::Get_First (NODE_TYPE_TRANSITION);
- node != NULL;
- node = (TransitionNodeClass *)NodeMgrClass::Get_Next (node, NODE_TYPE_TRANSITION))
- {
- //
- // Loop through all the different transitions in this node
- //
- bool need_new_ladder_index = true;
- int count = node->Get_Transition_Count ();
- for (int index = 0; index < count; index ++) {
-
- TransitionInstanceClass *transition = node->Get_Transition (index);
- if (transition != NULL) {
- //
- // Build an AABox from the zone this transition uses
- //
- OBBoxClass zone = transition->Get_Zone ();
- //
- // We handle each type of transition differently
- //
- switch (transition->Get_Type ())
- {
- //
- // For ladders, we need to find the 'exit' point
- //
- case TransitionDataClass::LADDER_ENTER_TOP:
- case TransitionDataClass::LADDER_ENTER_BOTTOM:
- {
- Vector3 pos = zone.Center;
- //
- // Insert this transition into our culling system
- //
- LevelFeatureClass *level_feature = new LevelFeatureClass;
- level_feature->Set_Start (zone);
- //
- // Search for the exit transition
- //
- TransitionInstanceClass *exit_transition = NULL;
- TransitionNodeClass *exit_node = NULL;
- if (transition->Get_Type () == TransitionDataClass::LADDER_ENTER_BOTTOM) {
- exit_transition = Find_Transition (TransitionDataClass::LADDER_EXIT_TOP, pos, 100.0F, &exit_node);
- } else {
- exit_transition = Find_Transition (TransitionDataClass::LADDER_EXIT_BOTTOM, pos, -100.0F, &exit_node);
- }
- //
- // Pass the exit zone onto the level feature object
- //
- if (exit_transition != NULL) {
- level_feature->Set_End (exit_transition->Get_Zone ());
- level_feature->Set_End_TM (exit_transition->Get_Ending_TM ());
- AABoxClass box;
- box.Center = pos;
- box.Extent = m_SimBoxExtents;
- box.Extent.X *= 4.0F;
- box.Extent.Y *= 4.0F;
- //
- // Create a box that encompasses the start position and end position
- //
- AABoxClass teleport_box (box);
- box.Center = exit_transition->Get_Ending_TM ().Get_Translation ();
- box.Center.Z += m_SimBoxExtents.Z;
- teleport_box.Add_Box (box);
- //
- // Pass the teleport area onto the level feature
- //
- level_feature->Set_Teleport_Zone (teleport_box);
- }
- //
- // Set the level feature's type
- //
- if (transition->Get_Type () == TransitionDataClass::LADDER_ENTER_BOTTOM) {
- level_feature->Set_Type (LevelFeatureClass::TYPE_LADDER_BOTTOM);
- } else {
- level_feature->Set_Type (LevelFeatureClass::TYPE_LADDER_TOP);
- }
- int new_ladder_index = -1;
- //
- // Can we reuse the same ladder index that the exit portal uses?
- //
- if (exit_node != NULL && exit_node->Get_Transition_Game_Obj () != NULL) {
- new_ladder_index = exit_node->Get_Transition_Game_Obj ()->Get_Ladder_Index ();
- if (new_ladder_index != -1) {
- need_new_ladder_index = false;
- }
- }
- //
- // Increment the ladder counter as necessary
- //
- if (need_new_ladder_index) {
- need_new_ladder_index = false;
- ladder_index ++;
- new_ladder_index = ladder_index;
- }
- //
- // Give the level feature a unique identifier
- //
- level_feature->Set_Mechanism_ID (ladder_index);
- if (node->Get_Transition_Game_Obj () != NULL) {
- node->Get_Transition_Game_Obj ()->Set_Ladder_Index (ladder_index);
- }
- //
- // Attempt to tie the bottom and top transitions to the same value
- //
- if (exit_node != NULL && exit_node->Get_Transition_Game_Obj () != NULL) {
- exit_node->Get_Transition_Game_Obj ()->Set_Ladder_Index (ladder_index);
- }
- //
- // Add the level feature to the culling systems
- //
- m_LevelFeatureCullingSystem.Add_Object (level_feature);
- m_LevelFeatureList.Add (level_feature);
- }
- break;
- default:
- break;
- }
- }
- }
- }
-
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Post_Process_Floodfill_For_Level_Features
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Post_Process_Floodfill_For_Level_Features (void)
- {
- //
- // Loop over all the level features
- //
- for (int index = 0; index < m_LevelFeatureList.Count (); index ++) {
- LevelFeatureClass *level_feature = m_LevelFeatureList[index];
- if (level_feature != NULL) {
- //
- // Get the area where the player will be moving
- //
- AABoxClass box = level_feature->Get_Teleport_Zone ();
- //
- // Loop over all the body-boxes that exist in this area
- //
- m_BodyBoxCullingSystem.Collect_Boxes (box);
- DynamicVectorClass<FloodfillBoxClass *> &list = m_BodyBoxCullingSystem.Get_Collection_List ();
- for (int index = 0; index < list.Count (); index ++) {
- FloodfillBoxClass *body_box = list[index];
- //
- // Force the test to pass in the z-component
- //
- box.Extent.Z = 1000.0F;
- //
- // Remove this box from the system if its completely contained
- // inside the teleport zone
- //
- AABoxClass test_box = Get_Body_Box_Bounds (body_box);
- if (CollisionMath::Overlap_Test (box, test_box) == CollisionMath::INSIDE) {
- //
- // Remove the box from the possible portal list (if necessary)
- //
- int portal_list_index = m_PossiblePortalList.ID (body_box);
- if (portal_list_index != -1) {
- m_PossiblePortalList.Delete (portal_list_index);
- }
-
- //
- // Remove this box from the system
- //
- m_BodyBoxReleaseList.Add (body_box);
- body_box->Unlink ();
- m_BodyBoxCullingSystem.Remove_Box (body_box);
- }
- }
- }
- }
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Apply_Level_Features
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Apply_Level_Features (void)
- {
- //
- // Loop over all the level features and create sectors and portals
- // for them
- //
- for (int index = 0; index < m_LevelFeatureList.Count (); index ++) {
- LevelFeatureClass *level_feature = m_LevelFeatureList[index];
- if (level_feature != NULL) {
- //
- // Integrate this feature into the pathfind data
- //
- Build_Sector_For_Level_Feature (level_feature);
- }
- }
-
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Find_Transition
- //
- ///////////////////////////////////////////////////////////////////////////
- TransitionInstanceClass *
- PathfindSectorBuilderClass::Find_Transition
- (
- TransitionDataClass::StyleType transition_type,
- const Vector3 & start_pos,
- float z_delta,
- TransitionNodeClass ** transition_node
- )
- {
- TransitionInstanceClass *retval = NULL;
- (*transition_node) = NULL;
- float start_z = start_pos.Z;
- float closest_z = 1000000;
- //
- // Loop over all the transitions in the level and find the one
- // that most closely matches what we are looking for
- //
- TransitionNodeClass *node = NULL;
- for (node = (TransitionNodeClass *)NodeMgrClass::Get_First (NODE_TYPE_TRANSITION);
- node != NULL;
- node = (TransitionNodeClass *)NodeMgrClass::Get_Next (node, NODE_TYPE_TRANSITION))
- {
- //
- // See if we can find a transition game object inside the node
- // that is the type we are looking for.
- //
- int index = node->Find_Transition (transition_type);
- if (index >= 0) {
-
- //
- // Get the transition game object
- //
- TransitionInstanceClass *transition = node->Get_Transition (index);
- if (transition != NULL) {
- const OBBoxClass &zone = transition->Get_Zone ();
- //
- // Determine how 'far' we are from this transition
- //
- float curr_z_min = zone.Center.Z - zone.Extent.Z;
- float curr_z_max = zone.Center.Z + zone.Extent.Z;
- float curr_delta = min (WWMath::Fabs (start_z - curr_z_min), WWMath::Fabs (start_z - curr_z_max));
-
- //
- // Is this transition zone the one we are looking for?
- //
- if ( (curr_delta < closest_z) &&
- (WWMath::Fabs (start_pos.X - zone.Center.X) < 1.0F) &&
- (WWMath::Fabs (start_pos.Y - zone.Center.Y) < 1.0F))
- {
- (*transition_node) = node;
- retval = transition;
- closest_z = curr_delta;
- }
- }
- }
- }
- return retval;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Find_Sector
- //
- ///////////////////////////////////////////////////////////////////////////
- PathfindSectorClass *
- PathfindSectorBuilderClass::Find_Sector
- (
- const Vector3 & point,
- const AABoxClass & box
- )
- {
- PathfindSectorClass *sector = PathfindClass::Get_Instance ()->Find_Sector (point, 1.0F);
- if (sector == NULL) {
- sector = PathfindClass::Get_Instance ()->Find_Sector (box.Center, 1.0F);
- }
- if (sector == NULL) {
- Vector3 box_point = box.Center;
- box_point.X += box.Extent.X;
- box_point.Y += box.Extent.Y;
- sector = PathfindClass::Get_Instance ()->Find_Sector (box_point, 1.0F);
- }
- if (sector == NULL) {
- Vector3 box_point = box.Center;
- box_point.X -= box.Extent.X;
- box_point.Y -= box.Extent.Y;
- sector = PathfindClass::Get_Instance ()->Find_Sector (box_point, 1.0F);
- }
- if (sector == NULL) {
- Vector3 box_point = box.Center;
- box_point.X += box.Extent.X;
- box_point.Y -= box.Extent.Y;
- sector = PathfindClass::Get_Instance ()->Find_Sector (box_point, 1.0F);
- }
- if (sector == NULL) {
- Vector3 box_point = box.Center;
- box_point.X -= box.Extent.X;
- box_point.Y += box.Extent.Y;
- sector = PathfindClass::Get_Instance ()->Find_Sector (box_point, 1.0F);
- }
- return sector;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Build_Sector_For_Level_Feature
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Build_Sector_For_Level_Feature (LevelFeatureClass *level_feature)
- {
- if (level_feature == NULL) {
- return ;
- }
-
- //
- // Get the starting and ending positions
- //
- Matrix3D end_tm = level_feature->Get_End_TM ();
- Vector3 end_pos = end_tm.Get_Translation ();
- Vector3 start_pos = level_feature->Get_Start ().Center;
-
- //
- // Get the starting and ending AABox's for this feature
- //
- AABoxClass start_box;
- AABoxClass end_box;
- level_feature->Get_Start_AABox (start_box);
- level_feature->Get_End_AABox (end_box);
- Vector3 sector_end_pos = end_pos;
-
- //
- // Assume the player will want to exit "away" from where (s)he entered
- //
- if (level_feature->Get_Type () == LevelFeatureClass::TYPE_DOOR) {
- Vector3 offset = end_box.Center - start_box.Center;
- offset.Normalize ();
- sector_end_pos = end_pos + offset;
- Clip_Point (§or_end_pos, end_box);
- }
- //
- // Are there any pathfinding sectors intersecting the
- // start and ending regions?
- //
- PathfindSectorClass *start_sector = Find_Sector (start_pos, start_box);
- PathfindSectorClass *end_sector = Find_Sector (sector_end_pos, end_box);
- if ( level_feature->Get_Type () == LevelFeatureClass::TYPE_LADDER_BOTTOM ||
- level_feature->Get_Type () == LevelFeatureClass::TYPE_LADDER_TOP)
- {
- if (end_sector != NULL) {
- end_box = end_sector->Get_Bounding_Box ();
- }
- }
- //
- // Expand the end box by a little bit
- //
- /*end_box.Extent.X += 0.25F;
- end_box.Extent.Y += 0.25F;
- end_box.Extent.Z += 0.25F;
- //
- // Build a list of sectors that the exit should connect to
- //
- DynamicVectorClass<PathfindSectorClass *> end_sector_list;
- PathfindClass::Get_Instance ()->Collect_Sectors (end_sector_list, end_box, start_sector);*/
- //
- // Were we successful?
- //
- if ((start_sector != NULL) && (end_sector != NULL)) {
- //
- // Create a sector from scratch
- //
- PathfindSectorClass *new_sector = new PathfindSectorClass;
- new_sector->Set_Bounding_Box (AABoxClass (Vector3 (0, 0, 0), Vector3 (0, 0, 0)));
- PathfindClass::Get_Instance ()->Add_Sector (new_sector);
- new_sector->Release_Ref ();
- //
- // Create the starting portal
- //
- PathfindActionPortalClass *enter_portal = new PathfindActionPortalClass;
- enter_portal->Set_Bounding_Box (start_box);
- enter_portal->Add_Dest_Sector (new_sector);
- enter_portal->Set_Destination (end_pos);
- //
- // Create the ending portal
- //
- PathfindActionPortalClass *exit_portal = new PathfindActionPortalClass;
- exit_portal->Set_Bounding_Box (end_box);
- exit_portal->Add_Dest_Sector (end_sector);
- //
- // Determine which type of action should be performed at this portal
- //
- switch (level_feature->Get_Type ())
- {
- case LevelFeatureClass::TYPE_LADDER_BOTTOM:
- case LevelFeatureClass::TYPE_LADDER_TOP:
- {
- AABoxClass end_trigger_zone;
- level_feature->Get_End_AABox (end_trigger_zone);
- enter_portal->Set_Destination (end_trigger_zone.Center);
- enter_portal->Set_Action_Type (PathClass::ACTION_LADDER);
- enter_portal->Set_Mechanism_ID (level_feature->Get_Mechanism_ID ());
- exit_portal->Set_Action_Type (PathClass::ACTION_NONE);
- break;
- }
- case LevelFeatureClass::TYPE_DOOR:
- case LevelFeatureClass::TYPE_ELEVATOR:
- enter_portal->Set_Action_Type (PathClass::ACTION_MECHANISM);
- enter_portal->Set_Mechanism_ID (level_feature->Get_Mechanism_ID ());
- exit_portal->Set_Action_Type (PathClass::ACTION_NONE);
- break;
- }
- //
- // Let the enter portal "know" where its going to end up...
- //
- enter_portal->Set_Exit_Portal (exit_portal);
- exit_portal->Set_Enter_Portal (enter_portal);
-
- //
- // Register the new portals with the pathfinding system,
- // and let the sectors know they can access these portals.
- //
- int enter_portal_index = PathfindClass::Get_Instance ()->Add_Portal (enter_portal);
- int exit_portal_index = PathfindClass::Get_Instance ()->Add_Portal (exit_portal);
- start_sector->Add_Portal (enter_portal_index);
- new_sector->Add_Portal (exit_portal_index);
- REF_PTR_RELEASE (enter_portal);
- REF_PTR_RELEASE (exit_portal);
- }
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Check_For_Level_Feature
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Check_For_Level_Feature (FloodfillBoxClass *body_box)
- {
- if (m_LevelFeatureCullingSystem.Object_Count () > 0) {
- AABoxClass bounding_box = Get_Body_Box_Bounds (body_box);
- //
- // Find all level features that intersect our current position
- //
- m_LevelFeatureCullingSystem.Reset_Collection ();
- m_LevelFeatureCullingSystem.Collect_Objects (bounding_box);
- //
- // Find all the features this body box intersects
- //
- DynamicVectorClass<LevelFeatureClass *> feature_list;
- LevelFeatureClass *level_feature = NULL;
- for ( level_feature = m_LevelFeatureCullingSystem.Get_First_Collected_Object ();
- level_feature != NULL;
- level_feature = m_LevelFeatureCullingSystem.Get_Next_Collected_Object (level_feature))
- {
- feature_list.Add (level_feature);
- }
- //
- // Loop through all the features in our list and process any 'portals' (ladders, doors, etc)
- //
- for (int index = 0; index < feature_list.Count (); index ++) {
- level_feature = feature_list[index];
-
- //
- // Get the bounding box for the pathfind object and the level feature's 'start-zone'
- //
- AABoxClass pathfind_box = Get_Body_Box_Bounds (body_box);
- AABoxClass feature_box;
- level_feature->Get_Start_AABox (feature_box);
- //
- // Do these boxe's intersect?
- //
- if ( (pathfind_box.Center.X + pathfind_box.Extent.X < feature_box.Center.X + feature_box.Extent.X) &&
- (pathfind_box.Center.X - pathfind_box.Extent.X > feature_box.Center.X - feature_box.Extent.X) &&
- (pathfind_box.Center.Y + pathfind_box.Extent.Y < feature_box.Center.Y + feature_box.Extent.Y) &&
- (pathfind_box.Center.Y - pathfind_box.Extent.Y > feature_box.Center.Y - feature_box.Extent.Y))
- {
- //
- // Continue our pathfind across this feature (i.e. up the ladder, down the elevator, etc)
- //
- Path_Across_Feature (level_feature);
- }
- }
- }
- return ;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Path_Across_Feature
- //
- ///////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Path_Across_Feature (LevelFeatureClass *level_feature)
- {
- //
- // Get the point where we think this feature will 'teleport' us to
- //
- Vector3 expected_pos = level_feature->Get_End_TM ().Get_Translation ();
- expected_pos.Z += m_SimBoxExtents.Z;
-
- //
- // Snap this position to our pathfind grid
- //
- Vector3 normalized_pos = expected_pos;
- normalized_pos.X = (int(expected_pos.X / m_SimBoundingBox.X)) * m_SimBoundingBox.X;
- normalized_pos.Y = (int(expected_pos.Y / m_SimBoundingBox.Y)) * m_SimBoundingBox.Y;
-
- //
- // Can we stand at this new position?
- //
- AABoxClass new_box;
- if (Try_Standing_Here (normalized_pos, &new_box)) {
- //
- // Is this cell already marked?
- //
- Vector3 position = new_box.Center;
- position.Z = new_box.Center.Z;
- FloodfillBoxClass *occupant = Get_Sector_Occupant (position);
- if (occupant == NULL) {
- //
- // Mark this cell and add it to the list of sectors
- // that need to be recursed.
- //
- occupant = Mark_Sector (new_box);
- m_FloodFillProcessList.Add (occupant);
- }
- }
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // fnPathfindDialogThread
- //
- ////////////////////////////////////////////////////////////////////////////
- UINT
- fnPathfindDialogThread
- (
- DWORD dwparam1,
- DWORD dwparam2,
- DWORD /*dwparam3*/,
- HRESULT* /*presult*/,
- HWND* /*phmain_wnd*/
- )
- {
- GeneratingPathfindDialogClass *dialog = new GeneratingPathfindDialogClass (::AfxGetMainWnd ());
- dialog->ShowWindow (SW_SHOW);
- //
- // Return the dialog object to the caller
- //
- GeneratingPathfindDialogClass **return_val = (GeneratingPathfindDialogClass **)dwparam2;
- if (return_val != NULL) {
- (*return_val) = dialog;
- }
- return 1;
- }
- ////////////////////////////////////////////////////////////////////////////
- //
- // Show_Dialog
- //
- ////////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Show_Dialog (void)
- {
- ::Create_UI_Thread (fnPathfindDialogThread, 0, (DWORD)&m_pDialog, 0, NULL, NULL);
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////
- //
- // Close_Dialog
- //
- ////////////////////////////////////////////////////////////////////////////
- void
- PathfindSectorBuilderClass::Close_Dialog (void)
- {
- if (m_pDialog != NULL) {
- ::PostMessage (m_pDialog->m_hWnd, WM_USER+101, 0, 0L);
- }
- return ;
- }
|