PathfindSectorBuilder.cpp 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : LevelEdit *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/LevelEdit/PathfindSectorBuilder.cpp $Modtime:: 5/27/00 4:10p $*
  25. * *
  26. * $Revision:: 56 $*
  27. * *
  28. *---------------------------------------------------------------------------------------------*
  29. * Functions: *
  30. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  31. #include "stdafx.h"
  32. #include "pathfindsectorbuilder.h"
  33. #include "phys3.h"
  34. #include "editorassetmgr.h"
  35. #include "humanphys.h"
  36. #include "phys3.h"
  37. #include "boxrobj.h"
  38. #include "pathfind.h"
  39. #include "pscene.h"
  40. #include "physcoltest.h"
  41. #include "filemgr.h"
  42. #include "_assetmgr.h"
  43. #include "utils.h"
  44. #include "nodemgr.h"
  45. #include "filelocations.h"
  46. #include "transitionnode.h"
  47. #include "collisiongroups.h"
  48. #include "pathfindportal.h"
  49. #include "GeneratingPathfindDialog.h"
  50. #include "terrainnode.h"
  51. #include "sceneeditor.h"
  52. #include "staticanimphys.h"
  53. #include "elevator.h"
  54. #include "doors.h"
  55. #include "soldier.h"
  56. #include "humanphys.h"
  57. #include "combatchunkid.h"
  58. //////////////////////////////////////////////////////////////////////////
  59. // Local Prototypes
  60. //////////////////////////////////////////////////////////////////////////
  61. UINT fnPathfindDialogThread (DWORD dwparam1, DWORD dwparam2, DWORD, HRESULT *, HWND *);
  62. ///////////////////////////////////////////////////////////////////////////
  63. // Local inlines
  64. ///////////////////////////////////////////////////////////////////////////
  65. static inline bool
  66. Clip_Point (Vector3 *point, const AABoxClass &box)
  67. {
  68. Vector3 temp_point = *point;
  69. //
  70. // Clip the temporary point
  71. //
  72. temp_point.X = max (temp_point.X, box.Center.X - box.Extent.X);
  73. temp_point.Y = max (temp_point.Y, box.Center.Y - box.Extent.Y);
  74. temp_point.Z = max (temp_point.Z, box.Center.Z - box.Extent.Z);
  75. temp_point.X = min (temp_point.X, box.Center.X + box.Extent.X);
  76. temp_point.Y = min (temp_point.Y, box.Center.Y + box.Extent.Y);
  77. temp_point.Z = min (temp_point.Z, box.Center.Z + box.Extent.Z);
  78. //
  79. // Did the clip change the point?
  80. //
  81. bool retval = (point->X != temp_point.X);
  82. retval |= (point->Y != temp_point.Y);
  83. retval |= (point->Z != temp_point.Z);
  84. //
  85. // Pass the new point back to the caller
  86. //
  87. (*point) = temp_point;
  88. return retval;
  89. }
  90. //////////////////////////////////////////////////////////////////////////
  91. // Local constants
  92. //////////////////////////////////////////////////////////////////////////
  93. const float ONE_SEC_FALL_DIST = 4.9F;
  94. class SimDirInfoClass
  95. {
  96. public:
  97. SimDirInfoClass (void) { }
  98. SimDirInfoClass (float _heading, float _speed, const Vector3 &_move, const Vector3 &_quadmove)
  99. : heading (_heading), speed (_speed), move (_move), quad_move (_quadmove) { }
  100. float heading;
  101. float speed;
  102. Vector3 move;
  103. Vector3 quad_move;
  104. };
  105. //
  106. // Note: The vector members are in "percentage of bounding box" units.
  107. //
  108. static const SimDirInfoClass DIR_INFO[DIR_MAX] =
  109. {
  110. SimDirInfoClass ( 0.0F, 0, Vector3 ( 1.0F, 0, 0), Vector3 ( 1.5F, -0.5F, 0) ),
  111. SimDirInfoClass ( (float)DEG_TO_RAD (90), 0, Vector3 ( 0, 1.0F, 0), Vector3 ( 0.5F, 1.5F, 0) ),
  112. SimDirInfoClass ( (float)DEG_TO_RAD (180), 0, Vector3 (-1.0F, 0, 0), Vector3 (-1.5F, 0.5F, 0) ),
  113. SimDirInfoClass ( (float)DEG_TO_RAD (270), 0, Vector3 ( 0, -1.0F, 0), Vector3 (-0.5F, -1.5F, 0) )
  114. };
  115. static HumanPhysClass *_PhysSimObj = NULL;
  116. static SoldierGameObj *_GameSimObj = NULL;
  117. //////////////////////////////////////////////////////////////////////////
  118. //
  119. // PathfindSectorBuilderClass
  120. //
  121. //////////////////////////////////////////////////////////////////////////
  122. PathfindSectorBuilderClass::PathfindSectorBuilderClass (void)
  123. : m_CurrentSector (NULL),
  124. m_SimBoundingBox (Vector3 (0.5F, 0.5F, 1.8F)),
  125. m_SimBoxExtents (Vector3 (0.25F, 0.25F, 0.9F)),
  126. m_DirInfo (NULL),
  127. m_StepHeight (0),
  128. m_TotalBoxCount (0),
  129. m_TotalBoxGuess (0),
  130. m_BeforeUpdateCount (0),
  131. m_AllowWaterFloodfill (false),
  132. m_MaxSectorDim (28000.0F)
  133. {
  134. RenderObjClass *commando_obj = NULL;
  135. //
  136. // Create an instance of the commando render object we can
  137. // use to simulate character movement
  138. //
  139. SoldierGameObjDef *definition = (SoldierGameObjDef *)DefinitionMgrClass::Find_Typed_Definition ("Commando", CLASSID_GAME_OBJECT_DEF_SOLDIER, false);
  140. if (definition != NULL) {
  141. SoldierGameObj *game_obj = new SoldierGameObj;
  142. game_obj->Init (*definition);
  143. REF_PTR_SET (commando_obj, game_obj->Peek_Model ());
  144. game_obj->Set_Delete_Pending ();
  145. }
  146. if (commando_obj != NULL) {
  147. //
  148. // Attempt to find the collision box for this physics object
  149. //
  150. RenderObjClass *collision_box = NULL;
  151. if (commando_obj->Class_ID () == RenderObjClass::CLASSID_DISTLOD) {
  152. RenderObjClass *lod0 = commando_obj->Get_Sub_Object(0);
  153. collision_box = lod0->Get_Sub_Object_By_Name ("WORLDBOX");
  154. REF_PTR_RELEASE (lod0);
  155. } else {
  156. collision_box = commando_obj->Get_Sub_Object_By_Name ("WORLDBOX");
  157. }
  158. //
  159. // Store the exents of the collision box for use in our simulation
  160. //
  161. if (collision_box != NULL) {
  162. const AABoxClass &box = collision_box->Get_Bounding_Box ();
  163. m_SimBoundingBox = box.Extent;
  164. m_SimBoundingBox.Z = (box.Extent.Z * 2);
  165. m_SimBoxExtents = m_SimBoundingBox * 0.5F;
  166. m_StepHeight = 0.25F;
  167. REF_PTR_RELEASE (collision_box);
  168. }
  169. //
  170. // Build an array of simulation information (specific to this
  171. // physics object).
  172. //
  173. m_DirInfo = new SimDirInfoClass[DIR_MAX];
  174. for (int index = 0; index < DIR_MAX; index ++) {
  175. m_DirInfo[index] = DIR_INFO[index];
  176. m_DirInfo[index].move.X *= m_SimBoundingBox.X;
  177. m_DirInfo[index].move.Y *= m_SimBoundingBox.Y;
  178. m_DirInfo[index].move.Z *= m_SimBoundingBox.Z;
  179. m_DirInfo[index].quad_move.X *= m_SimBoundingBox.X;
  180. m_DirInfo[index].quad_move.Y *= m_SimBoundingBox.Y;
  181. m_DirInfo[index].quad_move.Z *= m_SimBoundingBox.Z;
  182. m_DirInfo[index].speed = m_DirInfo[index].move.Length ();
  183. }
  184. REF_PTR_RELEASE (commando_obj);
  185. //
  186. // Configure the body box culling system
  187. //
  188. Vector3 lev_min;
  189. Vector3 lev_max;
  190. PhysicsSceneClass::Get_Instance ()->Get_Level_Extents (lev_min, lev_max);
  191. m_BodyBoxCullingSystem.Initialize (m_SimBoxExtents, lev_min, lev_max);
  192. //
  193. // Setup the simulation constants
  194. //
  195. m_SimMovement = Vector3 (0, 0, -(ONE_SEC_FALL_DIST + (m_SimBoundingBox.Z * 0.75F)));
  196. m_SimSweepBox.Extent = m_SimBoxExtents;
  197. }
  198. Detect_Level_Features ();
  199. /*AABoxClass collision_box;
  200. collision_box.Center.Set (0, 0, 0);
  201. collision_box.Extent = m_SimBoxExtents;
  202. _PhysSimObj->Set_Collision_Box (collision_box);*/
  203. return ;
  204. }
  205. //////////////////////////////////////////////////////////////////////////
  206. //
  207. // ~PathfindSectorBuilderClass
  208. //
  209. //////////////////////////////////////////////////////////////////////////
  210. PathfindSectorBuilderClass::~PathfindSectorBuilderClass (void)
  211. {
  212. /*if (_GameSimObj != NULL) {
  213. _GameSimObj->Destroy ();
  214. _GameSimObj = NULL;
  215. }*/
  216. if (m_DirInfo != NULL) {
  217. delete [] m_DirInfo;
  218. m_DirInfo = NULL;
  219. }
  220. return ;
  221. }
  222. //////////////////////////////////////////////////////////////////////////
  223. //
  224. // Prepare_Level
  225. //
  226. //////////////////////////////////////////////////////////////////////////
  227. void
  228. PathfindSectorBuilderClass::Prepare_Level (void)
  229. {
  230. ::Get_Scene_Editor ()->Display_Static_Anim_Phys (true);
  231. //
  232. // Get the list of all static objects from the physics scene
  233. //
  234. RefPhysListIterator iterator = ::Get_Scene_Editor ()->Get_Static_Object_Iterator ();
  235. for (iterator.First (); !iterator.Is_Done (); iterator.Next ()) {
  236. //
  237. // Is this object a static anim phys?
  238. //
  239. PhysClass *phys_obj = iterator.Peek_Obj ();
  240. StaticAnimPhysClass *static_phys_obj = phys_obj->As_StaticAnimPhysClass ();
  241. if (static_phys_obj != NULL) {
  242. //
  243. // Should we disable collisions with this object during pathfind?
  244. //
  245. StaticAnimPhysDefClass *definition = static_phys_obj->Get_StaticAnimPhysDef ();
  246. if (definition->Does_Collide_In_Pathfind () == false) {
  247. phys_obj->Inc_Ignore_Counter ();
  248. } else {
  249. while (phys_obj->Is_Ignore_Me ()) {
  250. phys_obj->Dec_Ignore_Counter ();
  251. }
  252. }
  253. }
  254. }
  255. //
  256. // Make sure that tile's use collision group 15...
  257. //
  258. for ( NodeClass *node = NodeMgrClass::Get_First (NODE_TYPE_TILE);
  259. node != NULL;
  260. node = NodeMgrClass::Get_Next (node, NODE_TYPE_TILE))
  261. {
  262. PhysClass *phys_obj = node->Peek_Physics_Obj ();
  263. if (phys_obj != NULL) {
  264. phys_obj->Set_Collision_Group (15);
  265. }
  266. }
  267. return ;
  268. }
  269. //////////////////////////////////////////////////////////////////////////
  270. //
  271. // Restore_Level
  272. //
  273. //////////////////////////////////////////////////////////////////////////
  274. void
  275. PathfindSectorBuilderClass::Restore_Level (void)
  276. {
  277. //
  278. // Restore each tile's collision group...
  279. //
  280. for ( NodeClass *node = NodeMgrClass::Get_First (NODE_TYPE_TILE);
  281. node != NULL;
  282. node = NodeMgrClass::Get_Next (node, NODE_TYPE_TILE))
  283. {
  284. PhysClass *phys_obj = node->Peek_Physics_Obj ();
  285. if (phys_obj != NULL) {
  286. phys_obj->Set_Collision_Group (EDITOR_COLLISION_GROUP);
  287. }
  288. }
  289. //
  290. // Get the list of all static objects from the physics scene
  291. //
  292. RefPhysListIterator iterator = ::Get_Scene_Editor ()->Get_Static_Object_Iterator ();
  293. for (iterator.First (); !iterator.Is_Done (); iterator.Next ()) {
  294. //
  295. // Is this object a static anim phys?
  296. //
  297. PhysClass *phys_obj = iterator.Peek_Obj ();
  298. StaticAnimPhysClass *static_phys_obj = phys_obj->As_StaticAnimPhysClass ();
  299. if (static_phys_obj != NULL) {
  300. //
  301. // Do we need to re-enable collisions with this object?
  302. //
  303. StaticAnimPhysDefClass *definition = static_phys_obj->Get_StaticAnimPhysDef ();
  304. if (definition->Does_Collide_In_Pathfind () == false) {
  305. phys_obj->Dec_Ignore_Counter ();
  306. }
  307. }
  308. }
  309. return ;
  310. }
  311. //////////////////////////////////////////////////////////////////////////
  312. //
  313. // Initialize
  314. //
  315. //////////////////////////////////////////////////////////////////////////
  316. void
  317. PathfindSectorBuilderClass::Initialize (void)
  318. {
  319. Prepare_Level ();
  320. //
  321. // Turn off sector display
  322. //
  323. PathfindClass::Get_Instance ()->Display_Sectors (false);
  324. PathfindClass::Get_Instance ()->Display_Portals (false);
  325. //
  326. // Initialize the dynamic vector array's so they will resize
  327. // in appropriate size steps (to decrease the total number of resizes)
  328. //
  329. m_FloodFillProcessList.Set_Growth_Step (20000);
  330. m_PossiblePortalList.Set_Growth_Step (20000);
  331. m_BodyBoxReleaseList.Set_Growth_Step (100000);
  332. //
  333. // Make a guess at the total number of boxes in the world based on
  334. // its size
  335. //
  336. Vector3 lev_min;
  337. Vector3 lev_max;
  338. PhysicsSceneClass::Get_Instance ()->Get_Level_Extents (lev_min, lev_max);
  339. int width = (lev_max.X - lev_min.X) / m_SimBoundingBox.X;
  340. int height = (lev_max.Y - lev_min.Y) / m_SimBoundingBox.Y;
  341. m_TotalBoxGuess = width * height;
  342. //
  343. // Show some UI
  344. //
  345. Show_Dialog ();
  346. return ;
  347. }
  348. //////////////////////////////////////////////////////////////////////////
  349. //
  350. // Shutdown
  351. //
  352. //////////////////////////////////////////////////////////////////////////
  353. void
  354. PathfindSectorBuilderClass::Shutdown (void)
  355. {
  356. //
  357. // Do some cleanup
  358. //
  359. Free_Floodfill_Boxes ();
  360. Cleanup_Level_Features ();
  361. //
  362. // Make sure we re-partition the sector culling system so
  363. // it does us some good... :)
  364. //
  365. PathfindClass::Get_Instance ()->Re_Partition_Sector_Tree ();
  366. //
  367. // Shutdown the UI and restore any level objects we modified
  368. //
  369. Close_Dialog ();
  370. Restore_Level ();
  371. return ;
  372. }
  373. //////////////////////////////////////////////////////////////////////////
  374. //
  375. // Compress_Sectors_For_Dyna_Culling
  376. //
  377. //////////////////////////////////////////////////////////////////////////
  378. void
  379. PathfindSectorBuilderClass::Compress_Sectors_For_Dyna_Culling (void)
  380. {
  381. const float MAX_DYNAMIC_VIS_CELL_DIMENSION = 20.0f;
  382. //
  383. // Change the dialog's checkmark so the user knows we are comprssing sectors
  384. //
  385. m_pDialog->Set_State(GeneratingPathfindDialogClass::STATE_COMPRESS);
  386. //
  387. // Floodfill the level and compress the floodfill into sectors
  388. //
  389. DynamicVectorClass<AABoxClass> sectors;
  390. Set_Max_Sector_Size(MAX_DYNAMIC_VIS_CELL_DIMENSION);
  391. Compress_Sectors(&sectors);
  392. //
  393. // Hand the sectors into the scene (NOTE: this will have to reset the
  394. // VIS system)
  395. //
  396. PhysicsSceneClass::Get_Instance()->Re_Partition_Dynamic_Culling_System(sectors);
  397. return;
  398. }
  399. //////////////////////////////////////////////////////////////////////////
  400. //
  401. // Compress_Sectors_For_Pathfind
  402. //
  403. //////////////////////////////////////////////////////////////////////////
  404. void
  405. PathfindSectorBuilderClass::Compress_Sectors_For_Pathfind (void)
  406. {
  407. //
  408. // Discard any previously generated data
  409. //
  410. PathfindClass::Get_Instance ()->Reset_Sectors ();
  411. PathfindClass::Get_Instance ()->Reset_Portals ();
  412. //
  413. // Change the dialog's checkmark so the user knows we are comprssing sectors
  414. //
  415. m_pDialog->Set_State (GeneratingPathfindDialogClass::STATE_COMPRESS);
  416. //
  417. // Compress the sectors into the largest possible rectangular regions
  418. //
  419. DWORD before_ticks = ::GetTickCount ();
  420. Post_Process_Floodfill_For_Level_Features ();
  421. Compress_Sectors ();
  422. Generate_Portals ();
  423. DWORD after_ticks = ::GetTickCount ();
  424. WWDEBUG_SAY(("Time spent compressing: %d secs.\r\n", (after_ticks-before_ticks)/1000));
  425. //
  426. // Loop through the level and create any portals around
  427. // ladders, doors, etc that may be needed.
  428. //
  429. Apply_Level_Features ();
  430. return ;
  431. }
  432. //////////////////////////////////////////////////////////////////////////
  433. //
  434. // Generate_Sectors
  435. //
  436. //////////////////////////////////////////////////////////////////////////
  437. void
  438. PathfindSectorBuilderClass::Generate_Sectors (void)
  439. {
  440. //
  441. // Start floodfilling from each of the start points
  442. //
  443. for (int index = 0; index < m_StartPointList.Count (); index ++) {
  444. Vector3 start_pos = m_StartPointList[index];
  445. //
  446. // Normalize the starting position. We do this so that all the different
  447. // generation points will match up perfectly.
  448. //
  449. start_pos.X = (int(start_pos.X / m_SimBoundingBox.X)) * m_SimBoundingBox.X;
  450. start_pos.Y = (int(start_pos.Y / m_SimBoundingBox.Y)) * m_SimBoundingBox.Y;
  451. start_pos.Z += (m_SimBoundingBox.Z * 0.5F);
  452. //
  453. // Start floodfilling from this position
  454. //
  455. AABoxClass new_box;
  456. if (Try_Standing_Here (start_pos, &new_box)) {
  457. m_CurrentSector = Mark_Sector (new_box);
  458. Floodfill (start_pos);
  459. }
  460. }
  461. //
  462. // Process all the floodfill boxes that have been queued up
  463. //
  464. int compress_count = 0;
  465. while (m_FloodFillProcessList.Count () > 0) {
  466. //
  467. // Pop a floodfill box off the list and process its neighbors
  468. //
  469. m_CurrentSector = m_FloodFillProcessList[0];
  470. m_FloodFillProcessList.Delete (0);
  471. AABoxClass box = Get_Body_Box_Bounds (m_CurrentSector);
  472. Vector3 pos = box.Center;
  473. pos.Z = box.Center.Z - box.Extent.Z + (m_SimBoundingBox.Z * 0.5F);
  474. Floodfill (pos);
  475. }
  476. return ;
  477. }
  478. //////////////////////////////////////////////////////////////////////////
  479. //
  480. // Find_Ground
  481. //
  482. //////////////////////////////////////////////////////////////////////////
  483. bool
  484. PathfindSectorBuilderClass::Find_Ground (const Vector3 &pos, float *ground_pos)
  485. {
  486. bool retval = false;
  487. AABoxClass sweep_box;
  488. sweep_box.Center = pos;
  489. sweep_box.Center.Z += m_StepHeight;
  490. sweep_box.Extent = m_SimBoxExtents;
  491. sweep_box.Extent.Z = 0.1F;
  492. //
  493. // Sweep a very short box downwards to see where the ground is
  494. //
  495. CastResultStruct result;
  496. Vector3 sweep_vector (0, 0, -6.5F);
  497. PhysAABoxCollisionTestClass test( sweep_box,
  498. sweep_vector,
  499. &result,
  500. STATIC_OBJ_COLLISION_GROUP,
  501. COLLISION_TYPE_PHYSICAL);
  502. PhysicsSceneClass::Get_Instance ()->Cast_AABox (test);
  503. //
  504. // Check to see if we found a floor, and its valid to stand on.
  505. //
  506. if ( (result.StartBad == false) &&
  507. (result.Fraction < 1.0F) &&
  508. (result.Normal.Z > 0.71F) &&
  509. (m_AllowWaterFloodfill || (result.SurfaceType != SURFACE_TYPE_WATER)))
  510. {
  511. //
  512. // Calculate what z-position the ground is
  513. //
  514. (*ground_pos) = (sweep_box.Center.Z + (sweep_vector.Z * result.Fraction)) - sweep_box.Extent.Z;
  515. retval = true;
  516. }
  517. return retval;
  518. }
  519. //////////////////////////////////////////////////////////////////////////
  520. //
  521. // Find_Ceiling
  522. //
  523. //////////////////////////////////////////////////////////////////////////
  524. bool
  525. PathfindSectorBuilderClass::Find_Ceiling (const Vector3 &pos, float *ceiling_pos)
  526. {
  527. bool retval = false;
  528. AABoxClass sweep_box;
  529. sweep_box.Center = pos;
  530. sweep_box.Center.Z += m_StepHeight;
  531. sweep_box.Extent = m_SimBoxExtents;
  532. sweep_box.Extent.Z = 0.1F;
  533. //
  534. // Sweep a very short box downwards to see where the ground is
  535. //
  536. CastResultStruct result;
  537. Vector3 sweep_vector (0, 0, 6.5F);
  538. PhysAABoxCollisionTestClass test( sweep_box,
  539. sweep_vector,
  540. &result,
  541. STATIC_OBJ_COLLISION_GROUP,
  542. COLLISION_TYPE_PHYSICAL);
  543. PhysicsSceneClass::Get_Instance ()->Cast_AABox (test);
  544. //
  545. // Check to ensure we didn't start the cast intersecting a poly
  546. //
  547. if (result.StartBad == false) {
  548. //
  549. // Calculate what the z-position of the ceiling is
  550. //
  551. (*ceiling_pos) = (sweep_box.Center.Z + (sweep_vector.Z * result.Fraction)) + sweep_box.Extent.Z;
  552. retval = true;
  553. }
  554. return retval;
  555. }
  556. //////////////////////////////////////////////////////////////////////////
  557. //
  558. // Try_Moving_Here
  559. //
  560. //////////////////////////////////////////////////////////////////////////
  561. bool
  562. PathfindSectorBuilderClass::Try_Moving_Here
  563. (
  564. const Vector3 & start_pos,
  565. const Vector3 & expected_pos,
  566. AABoxClass * real_pos
  567. )
  568. {
  569. bool is_valid = false;
  570. float start_ground_pos = start_pos.Z - m_SimBoxExtents.Z;
  571. float curr_ground_pos = 0;
  572. //
  573. // Find the ground level where we were standing and the ground level where
  574. // we want to be standing
  575. //
  576. if (Find_Ground (expected_pos, &curr_ground_pos)) {
  577. //
  578. // Check to see if the character can step from the old position to the new one
  579. //
  580. float step_height = curr_ground_pos - start_ground_pos;
  581. if (step_height < m_StepHeight) {
  582. //
  583. // Find the ceiling
  584. //
  585. float curr_ceiling_pos = curr_ground_pos;
  586. Find_Ceiling (expected_pos, &curr_ceiling_pos);
  587. //
  588. // Can the character fit between the floor and ceiling without crouching?
  589. //
  590. if ((curr_ceiling_pos - curr_ground_pos) > m_SimBoundingBox.Z) {
  591. //
  592. // Success! Build a bounding box for the new position
  593. //
  594. real_pos->Extent.X = m_SimBoxExtents.X;
  595. real_pos->Extent.Y = m_SimBoxExtents.Y;
  596. real_pos->Extent.Z = m_SimBoxExtents.Z;
  597. real_pos->Center.X = expected_pos.X;
  598. real_pos->Center.Y = expected_pos.Y;
  599. real_pos->Center.Z = curr_ground_pos + m_SimBoxExtents.Z + WWMATH_EPSILON;
  600. is_valid = true;
  601. }
  602. }
  603. }
  604. return is_valid;
  605. }
  606. //////////////////////////////////////////////////////////////////////////
  607. //
  608. // Try_Standing_Here
  609. //
  610. //////////////////////////////////////////////////////////////////////////
  611. bool
  612. PathfindSectorBuilderClass::Try_Standing_Here
  613. (
  614. const Vector3 & expected_pos,
  615. AABoxClass * real_pos
  616. )
  617. {
  618. bool is_valid = false;
  619. AABoxClass sweep_box;
  620. sweep_box.Center = expected_pos;
  621. sweep_box.Center.Z += m_StepHeight;
  622. sweep_box.Extent = m_SimSweepBox.Extent;
  623. sweep_box.Extent.Z -= m_StepHeight;
  624. //
  625. // Do a box cast to see if we can 'stand' here.
  626. //
  627. CastResultStruct result;
  628. PhysAABoxCollisionTestClass test( sweep_box,
  629. m_SimMovement,
  630. &result,
  631. STATIC_OBJ_COLLISION_GROUP,
  632. COLLISION_TYPE_PHYSICAL);
  633. test.CheckStaticObjs = true;
  634. test.CheckDynamicObjs = false;
  635. PhysicsSceneClass::Get_Instance ()->Cast_AABox (test);
  636. //
  637. // Is the start of the cast valid and is the polygon we
  638. // landed on flat enough to stand on?
  639. //
  640. if ((result.StartBad == false) && (result.Normal.Z > 0.71F)) {
  641. //
  642. // Are we standing on the ground? Is the ground a valid type?
  643. //
  644. bool on_ground = (result.Fraction < 1.0F);
  645. if (on_ground && (m_AllowWaterFloodfill || (result.SurfaceType != SURFACE_TYPE_WATER))) {
  646. //
  647. // Snap the x and y positions and calculate the z position
  648. // of the new box.
  649. //
  650. real_pos->Extent.X = sweep_box.Extent.X;
  651. real_pos->Extent.Y = sweep_box.Extent.Y;
  652. real_pos->Extent.Z = ((-m_SimMovement.Z * result.Fraction) * 0.5F) + (m_SimBoundingBox.Z * 0.5F);
  653. real_pos->Center.X = expected_pos.X;
  654. real_pos->Center.Y = expected_pos.Y;
  655. real_pos->Center.Z = (sweep_box.Center.Z + (m_SimBoundingBox.Z * 0.5F) - real_pos->Extent.Z) + 0.001F;
  656. is_valid = true;
  657. }
  658. }
  659. return is_valid;
  660. }
  661. //////////////////////////////////////////////////////////////////////////
  662. //
  663. // Do_Physics_Sim
  664. //
  665. //////////////////////////////////////////////////////////////////////////
  666. void
  667. PathfindSectorBuilderClass::Do_Physics_Sim
  668. (
  669. const Vector3 & start_pos,
  670. PATHFIND_DIR direction
  671. )
  672. {
  673. //
  674. // Determine where the next cell should be
  675. //
  676. Vector3 expected_pos = start_pos + m_DirInfo[direction].move;
  677. //
  678. // Do a quick-and-dirty test to see if we already 'know' about a
  679. // body-box in the requested direction.
  680. //
  681. bool found = false;
  682. FloodfillBoxClass *neighbor = m_CurrentSector->Peek_Neighbor (direction, false);
  683. if (neighbor != NULL) {
  684. m_SimSweepBox.Center = expected_pos;
  685. //
  686. // If the neighbor's bounding box completely CONTAINS the bounding
  687. // box we would have cast, then we can skip the cast and simply
  688. // mark the direction as 'traversible'
  689. //
  690. AABoxClass bounding_box = Get_Body_Box_Bounds (neighbor);
  691. found = bounding_box.Contains (m_SimSweepBox);
  692. float min1 = bounding_box.Center.Z - bounding_box.Extent.Z;
  693. float max1 = bounding_box.Center.Z + bounding_box.Extent.Z;
  694. float min2 = m_SimSweepBox.Center.Z - m_SimSweepBox.Extent.Z;
  695. float max2 = m_SimSweepBox.Center.Z + m_SimSweepBox.Extent.Z;
  696. found = (min1 <= min2) && (max1 >= max2);
  697. if (found) {
  698. m_CurrentSector->Set_Neighbor (direction, neighbor, true);
  699. }
  700. }
  701. //
  702. // Did the quick-and-dirty check fail? If so, then do the full box-cast
  703. //
  704. if (found == false) {
  705. Vector3 move_vector = (m_DirInfo[direction].move);
  706. Vector3 new_pos = start_pos + move_vector;
  707. AABoxClass new_box;
  708. //if (Try_Standing_Here (new_pos, &new_box)) {
  709. if (Try_Moving_Here (start_pos, new_pos, &new_box)) {
  710. Submit_Box (m_CurrentSector, new_box, direction);
  711. }
  712. }
  713. return ;
  714. }
  715. //////////////////////////////////////////////////////////////////////////
  716. //
  717. // Do_Real_Physics_Sim
  718. //
  719. //////////////////////////////////////////////////////////////////////////
  720. void
  721. PathfindSectorBuilderClass::Do_Real_Physics_Sim
  722. (
  723. const Vector3 & start_pos,
  724. PATHFIND_DIR direction
  725. )
  726. {
  727. //
  728. // Determine where the next cell should be
  729. //
  730. Vector3 expected_pos = start_pos + m_DirInfo[direction].move;
  731. //
  732. // Do a quick-and-dirty test to see if we already 'know' about a
  733. // body-box in the requested direction.
  734. //
  735. bool found = false;
  736. FloodfillBoxClass *neighbor = m_CurrentSector->Peek_Neighbor (direction, false);
  737. if (neighbor != NULL) {
  738. m_SimSweepBox.Center = expected_pos;
  739. //
  740. // If the neighbor's bounding box completely CONTAINS the bounding
  741. // box we would have cast, then we can skip the cast and simply
  742. // mark the direction as 'traversible'
  743. //
  744. AABoxClass bounding_box = Get_Body_Box_Bounds (neighbor);
  745. found = bounding_box.Contains (m_SimSweepBox);
  746. float min1 = bounding_box.Center.Z - bounding_box.Extent.Z;
  747. float max1 = bounding_box.Center.Z + bounding_box.Extent.Z;
  748. float min2 = m_SimSweepBox.Center.Z - m_SimSweepBox.Extent.Z;
  749. float max2 = m_SimSweepBox.Center.Z + m_SimSweepBox.Extent.Z;
  750. found = (min1 <= min2) && (max1 >= max2);
  751. if (found) {
  752. m_CurrentSector->Set_Neighbor (direction, neighbor, true);
  753. }
  754. }
  755. //
  756. // Did the quick-and-dirty check fail? If so, then do the full box-cast
  757. //
  758. if (found == false) {
  759. Vector3 move_vector = (m_DirInfo[direction].move);
  760. Vector3 new_pos = start_pos + move_vector;
  761. AABoxClass test_box (start_pos, m_SimBoxExtents);
  762. test_box.Add_Box (AABoxClass (new_pos, m_SimBoxExtents));
  763. test_box.Center.Z += 0.1F;
  764. NonRefPhysListClass obj_list;
  765. PhysicsSceneClass::Get_Instance ()->Collect_Collideable_Objects (test_box, COLLISION_TYPE_PHYSICAL, true, false, &obj_list);
  766. if (obj_list.Count () == 0) {
  767. AABoxClass new_box;
  768. if (Try_Standing_Here (new_pos, &new_box)) {
  769. Submit_Box (m_CurrentSector, new_box, direction);
  770. }
  771. return ;
  772. } else {
  773. bool did_intersect = false;
  774. NonRefPhysListIterator it (&obj_list);
  775. for (it.First(); !it.Is_Done(); it.Next()) {
  776. PhysClass *phys_obj = it.Peek_Obj ();
  777. if (phys_obj != NULL) {
  778. RenderObjClass *model = phys_obj->Peek_Model ();
  779. AABoxIntersectionTestClass int_test (test_box, COLLISION_TYPE_PHYSICAL);
  780. if (model->Intersect_AABox (int_test)) {
  781. did_intersect = true;
  782. break;
  783. }
  784. }
  785. }
  786. if (did_intersect == false) {
  787. AABoxClass new_box;
  788. if (Try_Standing_Here (new_pos, &new_box)) {
  789. Submit_Box (m_CurrentSector, new_box, direction);
  790. }
  791. return ;
  792. }
  793. }
  794. _PhysSimObj->Set_Position (start_pos);
  795. _PhysSimObj->Set_Velocity (Vector3 (0, 0, 0));
  796. for (int attempt = 0; attempt < 20; attempt ++) {
  797. if (_PhysSimObj->Is_In_Contact ()) {
  798. break;
  799. }
  800. _PhysSimObj->Timestep (0.1F);
  801. }
  802. bool keep_going = true;
  803. for (attempt = 0; keep_going && (attempt < 20); attempt ++) {
  804. Vector3 curr_pos = _PhysSimObj->Get_Position ();
  805. Vector3 delta = (new_pos - curr_pos);
  806. delta.Z = 0;
  807. float delta_len = delta.Length ();
  808. if (delta_len < 0.05F && _PhysSimObj->Is_In_Contact ()) {
  809. AABoxClass new_box;
  810. new_box.Center = new_pos;
  811. new_box.Center.Z = curr_pos.Z;
  812. new_box.Extent = m_SimBoxExtents;
  813. Submit_Box (m_CurrentSector, new_box, direction);
  814. keep_going = false;
  815. } else {
  816. Vector3 x_axis = (new_pos - curr_pos);
  817. Vector3 z_axis = Vector3 (0, 0, 1);
  818. x_axis.Normalize ();
  819. Vector3 y_axis = Vector3::Cross_Product (x_axis, z_axis);
  820. Matrix3D new_tm (x_axis, y_axis, z_axis, curr_pos);
  821. _PhysSimObj->Set_Transform (new_tm);
  822. _PhysSimObj->Get_Controller ()->Reset ();
  823. _PhysSimObj->Get_Controller ()->Set_Move_Forward (0.09F);
  824. _PhysSimObj->Timestep (0.075F);
  825. }
  826. }
  827. /*AABoxClass new_box;
  828. if (Try_Standing_Here (new_pos, &new_box)) {
  829. Submit_Box (m_CurrentSector, new_box, direction);
  830. }*/
  831. }
  832. return ;
  833. }
  834. //////////////////////////////////////////////////////////////////////////
  835. //
  836. // Submit_Box
  837. //
  838. //////////////////////////////////////////////////////////////////////////
  839. FloodfillBoxClass *
  840. PathfindSectorBuilderClass::Submit_Box
  841. (
  842. FloodfillBoxClass * from_obj,
  843. const AABoxClass & new_box,
  844. PATHFIND_DIR direction
  845. )
  846. {
  847. //
  848. // Is this cell already marked?
  849. //
  850. Vector3 position = new_box.Center;
  851. position.Z = new_box.Center.Z - new_box.Extent.Z + (m_SimBoundingBox.Z * 0.5F);
  852. FloodfillBoxClass *occupant = Get_Sector_Occupant (position);
  853. if (occupant == NULL) {
  854. //
  855. // Mark this cell and add it to the list of sectors
  856. // that need to be recursed.
  857. //
  858. occupant = Mark_Sector (new_box);
  859. m_FloodFillProcessList.Add (occupant);
  860. //
  861. // Let the new occupant know where it came from (even if it can't get there itself).
  862. //
  863. occupant->Set_Neighbor (::Inverse_Pathfind_Dir (direction), from_obj, false);
  864. m_TotalBoxCount ++;
  865. }
  866. //
  867. // Let the sector know who its new neighbor is
  868. //
  869. if (occupant != from_obj) {
  870. from_obj->Set_Neighbor (direction, occupant, true);
  871. }
  872. return occupant;
  873. }
  874. //////////////////////////////////////////////////////////////////////////
  875. //
  876. // Floodfill
  877. //
  878. //////////////////////////////////////////////////////////////////////////
  879. void
  880. PathfindSectorBuilderClass::Floodfill (const Vector3 &start_pos)
  881. {
  882. //
  883. // Do a simulation in each of the four directions from the
  884. // current cell.
  885. //
  886. if (m_pDialog->Was_Cancelled () == false) {
  887. //
  888. // Loop through and check any neighbors we don't already know about
  889. //
  890. for (int index = 0; index < DIR_MAX; index ++) {
  891. if (m_CurrentSector->Peek_Neighbor (PATHFIND_DIR(index)) == NULL) {
  892. Do_Physics_Sim (start_pos, PATHFIND_DIR(index));
  893. m_BeforeUpdateCount ++;
  894. }
  895. }
  896. //
  897. // Check to see if we need to climb up any ladders, open doors, etc...
  898. //
  899. Check_For_Level_Feature (m_CurrentSector);
  900. //
  901. // Let the current sector 'know' its been completely processed
  902. //
  903. m_CurrentSector->Needs_Processing (false);
  904. //
  905. // Update the UI
  906. //
  907. if (m_BeforeUpdateCount > 512) {
  908. CString message;
  909. message.Format ("Floodfilled %d boxes. Approx total boxes: %d", m_TotalBoxCount, m_TotalBoxGuess);
  910. m_pDialog->Set_Status (message, float (m_TotalBoxCount) / float (m_TotalBoxGuess));
  911. m_BeforeUpdateCount = 0;
  912. }
  913. }
  914. //
  915. // Allow windows messages to be processed
  916. //
  917. static int message_pump = 0;
  918. message_pump++;
  919. if (message_pump > 5000) {
  920. General_Pump_Messages ();
  921. message_pump = 0;
  922. }
  923. return ;
  924. }
  925. //////////////////////////////////////////////////////////////////////////
  926. //
  927. // Get_Sector_Occupant
  928. //
  929. //////////////////////////////////////////////////////////////////////////
  930. FloodfillBoxClass *
  931. PathfindSectorBuilderClass::Get_Sector_Occupant (const Vector3 &pos)
  932. {
  933. //
  934. // If we found any objects in the culling system, then the sector is occupied
  935. //
  936. return m_BodyBoxCullingSystem.Find_Box (pos);
  937. }
  938. //////////////////////////////////////////////////////////////////////////
  939. //
  940. // Mark_Sector
  941. //
  942. //////////////////////////////////////////////////////////////////////////
  943. void
  944. PathfindSectorBuilderClass::Mark_Sector (FloodfillBoxClass *body_box)
  945. {
  946. //
  947. // Add the culling object to our culling system. (This
  948. // effectively marks the cell as 'occupied').
  949. //
  950. body_box->Add_Ref ();
  951. m_BodyBoxCullingSystem.Add_Box (body_box);
  952. FloodfillBoxClass::Add (body_box);
  953. return ;
  954. }
  955. //////////////////////////////////////////////////////////////////////////
  956. //
  957. // Mark_Sector
  958. //
  959. //////////////////////////////////////////////////////////////////////////
  960. FloodfillBoxClass *
  961. PathfindSectorBuilderClass::Mark_Sector (const AABoxClass &bounding_box)
  962. {
  963. //
  964. // Create a culling system object to represent this 'sector' and
  965. // add it to our AABTree culling system. (This effectively marks
  966. // the cell as 'occupied').
  967. //
  968. FloodfillBoxClass *body_box = new FloodfillBoxClass;
  969. body_box->Set_Position (bounding_box.Center);
  970. Mark_Sector (body_box);
  971. body_box->Release_Ref ();
  972. return body_box;
  973. }
  974. ///////////////////////////////////////////////////////////////////////////
  975. //
  976. // Determine_Height
  977. //
  978. ///////////////////////////////////////////////////////////////////////////
  979. void
  980. PathfindSectorBuilderClass::Determine_Height
  981. (
  982. FloodfillBoxClass * start_box,
  983. float * min_z_pos,
  984. float * max_z_pos
  985. )
  986. {
  987. AABoxClass box = Get_Body_Box_Bounds (start_box);
  988. float z_extent = box.Extent.Z;
  989. box.Extent.X -= WWMATH_EPSILON;
  990. box.Extent.Y -= WWMATH_EPSILON;
  991. box.Extent.Z = 500.0F;
  992. //
  993. // Loop over all the body-boxes that exist above or below the starting box
  994. //
  995. m_BodyBoxCullingSystem.Collect_Boxes (box);
  996. DynamicVectorClass<FloodfillBoxClass *> &list = m_BodyBoxCullingSystem.Get_Collection_List ();
  997. for (int index = 0; index < list.Count (); index ++) {
  998. FloodfillBoxClass *body_box = list[index];
  999. //
  1000. // Only check 'other' boxes
  1001. //
  1002. if (body_box != start_box) {
  1003. AABoxClass curr_box = Get_Body_Box_Bounds (body_box);
  1004. //
  1005. // Determine the min and max z-positions of the current box
  1006. //
  1007. float curr_min_z = curr_box.Center.Z - (curr_box.Extent.Z + WWMATH_EPSILON);
  1008. float curr_max_z = curr_box.Center.Z + (curr_box.Extent.Z + WWMATH_EPSILON);
  1009. //
  1010. // Return new minimum and maximum
  1011. //
  1012. if (curr_max_z < box.Center.Z && curr_max_z > (*min_z_pos)) {
  1013. (*min_z_pos) = curr_max_z;
  1014. }
  1015. if (curr_min_z > box.Center.Z && curr_min_z < (*max_z_pos)) {
  1016. (*max_z_pos) = curr_min_z;
  1017. }
  1018. }
  1019. }
  1020. /*float delta_up = (*max_z_pos) - box.Center.Z;
  1021. float delta_down = box.Center.Z - (*min_z_pos);
  1022. delta_up = max (delta_up / 2.0F, (z_extent + WWMATH_EPSILON));
  1023. delta_down = max (delta_down / 2.0F, (z_extent + WWMATH_EPSILON));
  1024. (*max_z_pos) = box.Center.Z + delta_up;
  1025. (*min_z_pos) = box.Center.Z - delta_down;*/
  1026. //
  1027. // Make sure a box's min position is at least the
  1028. // bottom of its box.
  1029. //
  1030. float box_bottom = (box.Center.Z - z_extent);
  1031. if ((*min_z_pos) > (box_bottom - 0.5F)) {
  1032. (*min_z_pos) = (box_bottom - 0.5F);
  1033. }
  1034. return ;
  1035. }
  1036. //////////////////////////////////////////////////////////////////////////
  1037. //
  1038. // Build_Height_Values
  1039. //
  1040. //////////////////////////////////////////////////////////////////////////
  1041. int
  1042. PathfindSectorBuilderClass::Build_Height_Values (void)
  1043. {
  1044. int before_ticks = ::GetTickCount ();
  1045. int total_box_count = 0;
  1046. int box_count = 0;
  1047. //
  1048. // Backup the body-box list to ensure we delete them all...
  1049. //
  1050. for ( FloodfillBoxClass *body_box = FloodfillBoxClass::Get_First ();
  1051. body_box != NULL;
  1052. body_box = body_box->Get_Next ())
  1053. {
  1054. m_BodyBoxReleaseList.Add (body_box);
  1055. Vector3 pos = body_box->Get_Position ();
  1056. float min_z = pos.Z - (m_SimBoundingBox.Z * 500.0F);
  1057. float max_z = pos.Z + (m_SimBoundingBox.Z * 500.0F);
  1058. Determine_Height (body_box, &min_z, &max_z);
  1059. body_box->Set_Min_Z_Pos (min_z);
  1060. body_box->Set_Max_Z_Pos (max_z);
  1061. total_box_count ++;
  1062. }
  1063. int after_ticks = ::GetTickCount ();
  1064. WWDEBUG_SAY(("Time spent generating z-values: %d secs.\r\n", (after_ticks-before_ticks)/1000));
  1065. return total_box_count;
  1066. }
  1067. //////////////////////////////////////////////////////////////////////////
  1068. //
  1069. // Can_Traverse
  1070. //
  1071. //////////////////////////////////////////////////////////////////////////
  1072. inline bool
  1073. Can_Traverse (FloodfillBoxClass *cell, PATHFIND_DIR dir)
  1074. {
  1075. //
  1076. // Make sure the cell passes the basic 'traverse-requirements'
  1077. // to move in the given direction
  1078. //
  1079. return ( cell != NULL &&
  1080. cell->Needs_Processing () == false &&
  1081. cell->Is_Taken () == false);
  1082. }
  1083. //////////////////////////////////////////////////////////////////////////
  1084. //
  1085. // Check_Directions
  1086. //
  1087. //////////////////////////////////////////////////////////////////////////
  1088. inline bool
  1089. Check_Directions (FloodfillBoxClass *cell, int dir_mask)
  1090. {
  1091. bool is_valid = true;
  1092. //
  1093. // Check to make sure we can walk from the cell to its
  1094. // adjacent boxes (Only checking the requested directions).
  1095. //
  1096. for (int mask = 1; mask < MASK_MAX; mask <<= 1) {
  1097. if (dir_mask & mask) {
  1098. PATHFIND_DIR check_dir = ::Mask_to_Dir (DIRECTION_MASK(mask));
  1099. is_valid &= cell->Is_Two_Way_Traversible (check_dir);
  1100. }
  1101. }
  1102. return is_valid;
  1103. }
  1104. //////////////////////////////////////////////////////////////////////////
  1105. //
  1106. // Move_Dir
  1107. //
  1108. //////////////////////////////////////////////////////////////////////////
  1109. inline FloodfillBoxClass *
  1110. PathfindSectorBuilderClass::Move_Dir (FloodfillBoxClass *start_box, PATHFIND_DIR dir, int dir_mask)
  1111. {
  1112. //
  1113. // Peek a the cell in the given direction
  1114. //
  1115. FloodfillBoxClass *retval = NULL;
  1116. FloodfillBoxClass *new_cell = start_box->Peek_Neighbor (dir);
  1117. //
  1118. // Does this cell pass our traversal requirements?
  1119. //
  1120. if ( start_box->Is_Two_Way_Traversible (dir) &&
  1121. Can_Traverse (new_cell, dir) &&
  1122. Check_Directions (new_cell, dir_mask))
  1123. {
  1124. //
  1125. // Add this cell's min and max heights to the height-watcher.
  1126. // This is done so we can break the sector before it intersects
  1127. // a sector above or below it
  1128. //
  1129. m_HeightWatcher.Add_Lower_Bound (new_cell->Get_Min_Z_Pos ());
  1130. m_HeightWatcher.Add_Upper_Bound (new_cell->Get_Max_Z_Pos ());
  1131. //
  1132. // Is this cell within the min and max height values?
  1133. //
  1134. AABoxClass box = Get_Body_Box_Bounds (new_cell);
  1135. if ( m_HeightWatcher.Is_Current_Pos_Valid (box.Center.Z - box.Extent.Z) &&
  1136. m_HeightWatcher.Is_Current_Pos_Valid (box.Center.Z + box.Extent.Z))
  1137. {
  1138. retval = new_cell;
  1139. }
  1140. }
  1141. return retval;
  1142. }
  1143. //////////////////////////////////////////////////////////////////////////
  1144. //
  1145. // Check_Edge
  1146. //
  1147. //////////////////////////////////////////////////////////////////////////
  1148. inline bool
  1149. PathfindSectorBuilderClass::Check_Edge
  1150. (
  1151. FloodfillBoxClass * start_box,
  1152. int count_left,
  1153. int count_right,
  1154. int count_up,
  1155. int count_down,
  1156. PATHFIND_DIR move_dir
  1157. )
  1158. {
  1159. bool retval = false;
  1160. //
  1161. // Check the first cell, can we move in the requested direction?
  1162. //
  1163. int dir_mask = 0;
  1164. dir_mask |= (count_left > 0) ? MASK_LEFT : 0;
  1165. dir_mask |= (count_right > 0) ? MASK_RIGHT : 0;
  1166. dir_mask |= (count_up > 0) ? MASK_UP : 0;
  1167. dir_mask |= (count_down > 0) ? MASK_DOWN : 0;
  1168. if (Move_Dir (start_box, move_dir, dir_mask) != NULL) {
  1169. retval = true;
  1170. }
  1171. //
  1172. // Check the given number of cells in the left direction
  1173. //
  1174. FloodfillBoxClass *curr_cell = start_box;
  1175. for (int x = 0; retval && x < count_left; x++) {
  1176. //
  1177. // Can we move one step in this direction?
  1178. //
  1179. curr_cell = Move_Dir (curr_cell, DIR_LEFT, 0);
  1180. if (curr_cell != NULL) {
  1181. //
  1182. // Can this new cell move in the movement direction AND
  1183. // can its new cell move right and, if necessary, left?
  1184. //
  1185. dir_mask = MASK_RIGHT;
  1186. dir_mask |= ((x + 1) < count_left) ? MASK_LEFT : 0;
  1187. retval = (Move_Dir (curr_cell, move_dir, dir_mask) != NULL);
  1188. } else {
  1189. retval = false;
  1190. }
  1191. }
  1192. //
  1193. // Check the given number of cells in the left direction
  1194. //
  1195. curr_cell = start_box;
  1196. for (x = 0; retval && x < count_right; x++) {
  1197. //
  1198. // Can we move one step in this direction?
  1199. //
  1200. curr_cell = Move_Dir (curr_cell, DIR_RIGHT, 0);
  1201. if (curr_cell != NULL) {
  1202. //
  1203. // Can this new cell move in the movement direction AND
  1204. // can its new cell move left and, if necessary, right?
  1205. //
  1206. dir_mask = MASK_LEFT;
  1207. dir_mask |= ((x + 1) < count_right) ? MASK_RIGHT : 0;
  1208. retval = (Move_Dir (curr_cell, move_dir, dir_mask) != NULL);
  1209. } else {
  1210. retval = false;
  1211. }
  1212. }
  1213. //
  1214. // Check the given number of cells in the up direction
  1215. //
  1216. curr_cell = start_box;
  1217. for (int y = 0; retval && y < count_up; y++) {
  1218. //
  1219. // Can we move one step in this direction?
  1220. //
  1221. curr_cell = Move_Dir (curr_cell, DIR_UP, 0);
  1222. if (curr_cell != NULL) {
  1223. //
  1224. // Can this new cell move in the movement direction AND
  1225. // can its new cell move down and, if necessary, up?
  1226. //
  1227. dir_mask = MASK_DOWN;
  1228. dir_mask |= ((y + 1) < count_up) ? MASK_UP : 0;
  1229. retval = (Move_Dir (curr_cell, move_dir, dir_mask) != NULL);
  1230. } else {
  1231. retval = false;
  1232. }
  1233. }
  1234. //
  1235. // Check the given number of cells in the down direction
  1236. //
  1237. curr_cell = start_box;
  1238. for (y = 0; retval && y < count_down; y++) {
  1239. //
  1240. // Can we move one step in this direction?
  1241. //
  1242. curr_cell = Move_Dir (curr_cell, DIR_DOWN, 0);
  1243. if (curr_cell != NULL) {
  1244. //
  1245. // Can this new cell move in the movement direction AND
  1246. // can its new cell move up and, if necessary, down?
  1247. //
  1248. dir_mask = MASK_UP;
  1249. dir_mask |= ((y + 1) < count_down) ? MASK_DOWN : 0;
  1250. retval = (Move_Dir (curr_cell, move_dir, dir_mask) != NULL);
  1251. } else {
  1252. retval = false;
  1253. }
  1254. }
  1255. return retval;
  1256. }
  1257. //////////////////////////////////////////////////////////////////////////
  1258. //
  1259. // Find_Perimeter
  1260. //
  1261. //////////////////////////////////////////////////////////////////////////
  1262. FloodfillBoxClass *
  1263. PathfindSectorBuilderClass::Find_Perimeter (FloodfillBoxClass *start_box, BOX_PERIMETER *perimeter)
  1264. {
  1265. FloodfillBoxClass *up_cell = start_box;
  1266. FloodfillBoxClass *down_cell = start_box;
  1267. FloodfillBoxClass *left_cell = start_box;
  1268. FloodfillBoxClass *right_cell = start_box;
  1269. //
  1270. // Determine what the maximum number of cells in a given direction can be
  1271. //
  1272. int max_dim = m_MaxSectorDim / max (m_SimBoundingBox.X, m_SimBoundingBox.Y);
  1273. //
  1274. // Create an object that will allow us to break the sector if
  1275. // it would intersect with a sector above or below us.
  1276. //
  1277. Vector3 pos = start_box->Get_Position ();
  1278. m_HeightWatcher.Initialize (pos.Z - (m_SimBoundingBox.Z * 500.0F), pos.Z + (m_SimBoundingBox.Z * 500.0F), pos.Z);
  1279. do
  1280. {
  1281. //
  1282. // Expand the box 'up' one row (if possible)
  1283. //
  1284. if (perimeter->stop_up == false) {
  1285. perimeter->stop_up = true;
  1286. FloodfillBoxClass *new_cell = Move_Dir (up_cell, DIR_UP, 0);
  1287. if (new_cell != NULL) {
  1288. if (Check_Edge (up_cell, perimeter->count_left, perimeter->count_right, 0, 0, DIR_UP)) {
  1289. up_cell = new_cell;
  1290. perimeter->count_up ++;
  1291. perimeter->stop_up = false;
  1292. }
  1293. }
  1294. }
  1295. //
  1296. // Expand the box 'down' one row (if possible)
  1297. //
  1298. if (perimeter->stop_down == false) {
  1299. perimeter->stop_down = true;
  1300. FloodfillBoxClass *new_cell = Move_Dir (down_cell, DIR_DOWN, 0);
  1301. if (new_cell != NULL) {
  1302. if (Check_Edge (down_cell, perimeter->count_left, perimeter->count_right, 0, 0, DIR_DOWN)) {
  1303. down_cell = new_cell;
  1304. perimeter->count_down ++;
  1305. perimeter->stop_down = false;
  1306. }
  1307. }
  1308. }
  1309. //
  1310. // Expand the box 'left' one column (if possible)
  1311. //
  1312. if (perimeter->stop_left == false) {
  1313. perimeter->stop_left = true;
  1314. FloodfillBoxClass *new_cell = Move_Dir (left_cell, DIR_LEFT, 0);
  1315. if (new_cell != NULL) {
  1316. if (Check_Edge (left_cell, 0, 0, perimeter->count_up, perimeter->count_down, DIR_LEFT)) {
  1317. left_cell = new_cell;
  1318. perimeter->count_left ++;
  1319. perimeter->stop_left = false;
  1320. }
  1321. }
  1322. }
  1323. //
  1324. // Expand the box 'right' one column (if possible)
  1325. //
  1326. if (perimeter->stop_right == false) {
  1327. perimeter->stop_right = true;
  1328. FloodfillBoxClass *new_cell = Move_Dir (right_cell, DIR_RIGHT, 0);
  1329. if (new_cell != NULL) {
  1330. if (Check_Edge (right_cell, 0, 0, perimeter->count_up, perimeter->count_down, DIR_RIGHT)) {
  1331. right_cell = new_cell;
  1332. perimeter->count_right ++;
  1333. perimeter->stop_right = false;
  1334. }
  1335. }
  1336. }
  1337. //
  1338. // Check to see if we are going to exceed the maximum sector size in either
  1339. // direction.
  1340. //
  1341. if (perimeter->count_left + perimeter->count_right >= max_dim) {
  1342. perimeter->stop_left = true;
  1343. perimeter->stop_right = true;
  1344. }
  1345. if (perimeter->count_up + perimeter->count_down >= max_dim) {
  1346. perimeter->stop_up = true;
  1347. perimeter->stop_down = true;
  1348. }
  1349. }
  1350. while ( perimeter->stop_up == false || perimeter->stop_down == false ||
  1351. perimeter->stop_left == false || perimeter->stop_right == false);
  1352. //
  1353. // Some debug checking to make sure we built the region
  1354. // correctly.
  1355. //
  1356. FloodfillBoxClass *upper_left1 = up_cell;
  1357. FloodfillBoxClass *upper_left2 = left_cell;
  1358. for (int index = 0; index < perimeter->count_left; index ++) {
  1359. upper_left1 = upper_left1->Peek_Neighbor (DIR_LEFT);
  1360. }
  1361. for (index = 0; index < perimeter->count_up; index ++) {
  1362. upper_left2 = upper_left2->Peek_Neighbor (DIR_UP);
  1363. }
  1364. WWASSERT (upper_left1 == upper_left2);
  1365. if (upper_left1 != upper_left2) {
  1366. CString message;
  1367. message.Format ("upper_left1 = %d\nupper_left2 = %d\nup_cell = %d\nleft_cell = %d", upper_left1, upper_left2, up_cell, left_cell);
  1368. ::MessageBox (NULL, message, "Info", MB_OK);
  1369. }
  1370. return upper_left1;
  1371. }
  1372. //////////////////////////////////////////////////////////////////////////
  1373. //
  1374. // Compress_Sectors
  1375. //
  1376. //////////////////////////////////////////////////////////////////////////
  1377. void
  1378. PathfindSectorBuilderClass::Compress_Sectors (DynamicVectorClass<AABoxClass> *box_list)
  1379. {
  1380. //
  1381. // Generate a set of maximum and minimum height values
  1382. // for each box
  1383. //
  1384. int total_box_count = Build_Height_Values ();
  1385. int box_count = 0;
  1386. bool keep_going = true;
  1387. FloodfillBoxClass *start_box = NULL;
  1388. FloodfillBoxClass *old_start_box = NULL;
  1389. BOX_PERIMETER old_perimeter = { 0 };
  1390. //
  1391. // Loop over all the boxes and compress them into rectangular regions
  1392. //
  1393. while (keep_going && ((start_box = FloodfillBoxClass::Get_First ()) != NULL)) {
  1394. //
  1395. // Don't compress any boxes that still need processing
  1396. //
  1397. if (start_box->Needs_Processing ()) {
  1398. start_box->Remove ();
  1399. continue;
  1400. }
  1401. //
  1402. // Perform a simple check to make sure we don't keep getting the same
  1403. // box off the top of the list (this should never, ever, ever, happen).
  1404. //
  1405. if ( (start_box == old_start_box) &&
  1406. (FloodfillBoxClass::Get_First () != FloodfillBoxClass::Get_Last ()))
  1407. {
  1408. ::MessageBox (::AfxGetMainWnd ()->m_hWnd, "Found the same box twice...", "Compression Error", MB_OK | MB_ICONERROR);
  1409. keep_going = false;
  1410. }
  1411. old_start_box = start_box;
  1412. //
  1413. // Find the largest rectangular region that this box can be part of
  1414. //
  1415. BOX_PERIMETER perimeter = { 0 };
  1416. FloodfillBoxClass *upper_left_cell = Find_Perimeter (start_box, &perimeter);
  1417. old_perimeter = perimeter;
  1418. //
  1419. // How big is the new rectangular region?
  1420. //
  1421. int width = (perimeter.count_left + perimeter.count_right) + 1;
  1422. int height = (perimeter.count_up + perimeter.count_down) + 1;
  1423. //
  1424. // If the area is of an exceptable size, then compress it into a sector
  1425. //
  1426. if (width > 2 || height > 2) {
  1427. int skipped_count = start_box->Get_Compress_Skipped_Count ();
  1428. int min_dim = min (width, height);
  1429. //
  1430. // Should we skip this box in hopes that we find a better sector later?
  1431. //
  1432. if (skipped_count <= (12 - min_dim)) {
  1433. start_box->Inc_Compress_Skipped_Count ();
  1434. start_box->Remove ();
  1435. FloodfillBoxClass::Add (start_box);
  1436. } else {
  1437. //
  1438. // Compress the region into a new pathfinding sector
  1439. //
  1440. PathfindSectorClass *sector = Build_Sector (upper_left_cell, width, height);
  1441. if (sector != NULL) {
  1442. //
  1443. // Sumbit this sector
  1444. //
  1445. if (box_list != NULL) {
  1446. AABoxClass bbox = sector->Get_Bounding_Box ();
  1447. box_list->Add (bbox);
  1448. MEMBER_RELEASE (sector);
  1449. } else {
  1450. PathfindClass::Get_Instance ()->Add_Sector (sector);
  1451. }
  1452. }
  1453. //
  1454. // Update the UI
  1455. //
  1456. box_count += (width * height);
  1457. CString message;
  1458. message.Format ("Compressed %d of %d boxes.", box_count, total_box_count);
  1459. m_pDialog->Set_Status (message, ((float)box_count) / ((float)total_box_count));
  1460. }
  1461. } else {
  1462. //
  1463. // Sector is too small, so remove the box
  1464. // from the system.
  1465. //
  1466. start_box->Set_Taken ();
  1467. start_box->Remove ();
  1468. }
  1469. }
  1470. return ;
  1471. }
  1472. //////////////////////////////////////////////////////////////////////////
  1473. //
  1474. // Filter_Useless_Sectors
  1475. //
  1476. //////////////////////////////////////////////////////////////////////////
  1477. /*void
  1478. PathfindSectorBuilderClass::Filter_Useless_Sectors (DynamicVectorClass<PathfindSectorClass *> &sector_list)
  1479. {
  1480. DynamicVectorClass<PathfindSectorClass *> final_sector_list;
  1481. for (int index = 0; index < sector_list.Count (); index ++) {
  1482. PathfindSectorClass *sector = sector_list[index];
  1483. bool found_usefull_portal = false;
  1484. int portal_count = sector->Get_Portal_Count ();
  1485. for (int portal_index = 0; portal_index < portal_count; portal_index ++) {
  1486. }
  1487. if (found_usefull_portal) {
  1488. final_sector_list.Add (sector);
  1489. }
  1490. }
  1491. //
  1492. // Add all the sectors to the pathfind system
  1493. //
  1494. for (index = 0; index < final_sector_list.Count (); index ++) {
  1495. }
  1496. return ;
  1497. }*/
  1498. //////////////////////////////////////////////////////////////////////////
  1499. //
  1500. // Scan_Edge
  1501. //
  1502. //////////////////////////////////////////////////////////////////////////
  1503. void
  1504. Scan_Edge
  1505. (
  1506. FloodfillBoxClass * start_obj,
  1507. int cell_count,
  1508. PATHFIND_DIR check_dir,
  1509. PATHFIND_DIR move_dir,
  1510. int * best_count
  1511. )
  1512. {
  1513. FloodfillBoxClass * best_first_cell = 0;
  1514. FloodfillBoxClass * first_cell = NULL;
  1515. int count = 0;
  1516. //
  1517. // Go along the edge
  1518. //
  1519. FloodfillBoxClass *box_obj = start_obj;
  1520. for (int box_index = 0; box_index < cell_count; box_index ++) {
  1521. //
  1522. // Can we traverse to the left and back?
  1523. //
  1524. if (box_obj->Is_Two_Way_Traversible (check_dir)) {
  1525. //
  1526. // Start recording this run
  1527. //
  1528. if (first_cell == NULL) {
  1529. first_cell = box_obj;
  1530. count = 1;
  1531. } else {
  1532. count ++;
  1533. }
  1534. } else {
  1535. //
  1536. // Is this the best run we've found?
  1537. //
  1538. if (count > (*best_count)) {
  1539. best_first_cell = first_cell;
  1540. (*best_count) = count;
  1541. }
  1542. //
  1543. // Reset
  1544. //
  1545. first_cell = NULL;
  1546. count = 0;
  1547. }
  1548. //
  1549. // Move to the next edge cell
  1550. //
  1551. box_obj = box_obj->Peek_Neighbor (move_dir);
  1552. }
  1553. //
  1554. // Is this the best run we've found?
  1555. //
  1556. if (count > (*best_count)) {
  1557. best_first_cell = first_cell;
  1558. (*best_count) = count;
  1559. }
  1560. return ;
  1561. }
  1562. //////////////////////////////////////////////////////////////////////////
  1563. //
  1564. // Is_Valid_Sector
  1565. //
  1566. //////////////////////////////////////////////////////////////////////////
  1567. bool
  1568. PathfindSectorBuilderClass::Is_Valid_Sector
  1569. (
  1570. FloodfillBoxClass ** upper_left_ptr,
  1571. int & cells_right,
  1572. int & cells_down
  1573. )
  1574. {
  1575. bool retval = true;
  1576. //
  1577. // Is this sector to small?
  1578. //
  1579. if (cells_right < 3 || cells_down < 3) {
  1580. retval = false;
  1581. if (cells_right < 3) {
  1582. FloodfillBoxClass *ul_ptr = (*upper_left_ptr);
  1583. FloodfillBoxClass *ur_ptr = (*upper_left_ptr)->Find_Relative (cells_right - 1, 0);
  1584. //
  1585. // Determine if either edge can enter an adjacent sector. This
  1586. // would make the sector walkable
  1587. //
  1588. int best_count = 0;
  1589. Scan_Edge (ul_ptr, cells_down, DIR_LEFT, DIR_DOWN, &best_count);
  1590. Scan_Edge (ur_ptr, cells_down, DIR_RIGHT, DIR_DOWN, &best_count);
  1591. //
  1592. // Was this run good enough?
  1593. //
  1594. retval = (best_count >= 3);
  1595. } else {
  1596. FloodfillBoxClass *ul_ptr = (*upper_left_ptr);
  1597. FloodfillBoxClass *ll_ptr = (*upper_left_ptr)->Find_Relative (0, cells_down - 1);
  1598. //
  1599. // Determine if either edge can enter an adjacent sector. This
  1600. // would make the sector walkable
  1601. //
  1602. int best_count = 0;
  1603. Scan_Edge (ul_ptr, cells_right, DIR_UP, DIR_RIGHT, &best_count);
  1604. Scan_Edge (ll_ptr, cells_right, DIR_DOWN, DIR_RIGHT, &best_count);
  1605. //
  1606. // Was this run good enough?
  1607. //
  1608. retval = (best_count >= 3);
  1609. }
  1610. }
  1611. return retval;
  1612. }
  1613. //////////////////////////////////////////////////////////////////////////
  1614. //
  1615. // Build_Sector
  1616. //
  1617. //////////////////////////////////////////////////////////////////////////
  1618. PathfindSectorClass *
  1619. PathfindSectorBuilderClass::Build_Sector
  1620. (
  1621. FloodfillBoxClass * upper_left_ptr,
  1622. int cells_right,
  1623. int cells_down
  1624. )
  1625. {
  1626. Vector3 min_point (100000.0F, 100000.0F, 100000.0F);
  1627. Vector3 max_point (-100000.0F, -100000.0F, -100000.0F);
  1628. //
  1629. // Check to see if this sector meets are minimum requirements
  1630. //
  1631. bool is_valid = true;//Is_Valid_Sector (&upper_left_ptr, cells_right, cells_down);
  1632. //
  1633. // Allocate a new sector
  1634. //
  1635. PathfindSectorClass *sector = NULL;
  1636. if (is_valid) {
  1637. sector = new PathfindSectorClass;
  1638. }
  1639. //
  1640. // Remove all the cells that compose this area from the list
  1641. //
  1642. FloodfillBoxClass *curr_cell = upper_left_ptr;
  1643. for (int right = 0; (right < cells_right); right ++) {
  1644. FloodfillBoxClass *down_obj = curr_cell;
  1645. for (int down = 0; (down < cells_down); down ++) {
  1646. AABoxClass bounding_box = Get_Body_Box_Bounds (down_obj);
  1647. min_point.X = min (min_point.X, bounding_box.Center.X - bounding_box.Extent.X);
  1648. min_point.Y = min (min_point.Y, bounding_box.Center.Y - bounding_box.Extent.Y);
  1649. min_point.Z = min (min_point.Z, bounding_box.Center.Z - bounding_box.Extent.Z);
  1650. max_point.X = max (max_point.X, bounding_box.Center.X + bounding_box.Extent.X);
  1651. max_point.Y = max (max_point.Y, bounding_box.Center.Y + bounding_box.Extent.Y);
  1652. max_point.Z = max (max_point.Z, bounding_box.Center.Z + bounding_box.Extent.Z);
  1653. WWASSERT (down_obj->Is_Taken () == false);
  1654. if (is_valid) {
  1655. down_obj->Set_Sector (sector);
  1656. }
  1657. down_obj->Remove ();
  1658. down_obj->Set_Taken ();
  1659. //
  1660. // Is this an edge case? (If so its a possible portal)
  1661. //
  1662. if ( (down == 0) ||
  1663. (right == 0) ||
  1664. (down == (cells_down - 1)) ||
  1665. (right == (cells_right - 1)))
  1666. {
  1667. if (is_valid) {
  1668. m_PossiblePortalList.Add (down_obj);
  1669. }
  1670. }
  1671. //
  1672. // Advance to the next box down
  1673. //
  1674. down_obj = down_obj->Peek_Neighbor (DIR_DOWN);
  1675. }
  1676. //
  1677. // Advance to the next box right
  1678. //
  1679. curr_cell = curr_cell->Peek_Neighbor (DIR_RIGHT);
  1680. }
  1681. //
  1682. // Calculate this sector's bounding box
  1683. //
  1684. if (is_valid) {
  1685. AABoxClass bounding_box;
  1686. bounding_box.Center = min_point + ((max_point - min_point) * 0.5F);
  1687. bounding_box.Extent.X = (max_point.X - min_point.X) * 0.5F;
  1688. bounding_box.Extent.Y = (max_point.Y - min_point.Y) * 0.5F;
  1689. bounding_box.Extent.Z = (max_point.Z - min_point.Z) * 0.5F;
  1690. sector->Set_Bounding_Box (bounding_box);
  1691. }
  1692. return sector;
  1693. }
  1694. //////////////////////////////////////////////////////////////////////////
  1695. //
  1696. // Generate_Portals
  1697. //
  1698. //////////////////////////////////////////////////////////////////////////
  1699. void
  1700. PathfindSectorBuilderClass::Generate_Portals (void)
  1701. {
  1702. //
  1703. // Loop through all the body-boxes that are possible portals
  1704. //
  1705. for (int index = 0; index < m_PossiblePortalList.Count (); index ++) {
  1706. FloodfillBoxClass *cull_obj = m_PossiblePortalList[index];
  1707. PathfindSectorClass *sector = cull_obj->Peek_Sector ();
  1708. if ((sector != NULL) && sector->Is_Valid ()) {
  1709. const AABoxClass &box = sector->Get_Bounding_Box ();
  1710. Vector3 portal_size = m_SimBoundingBox;
  1711. portal_size.Z = box.Extent.Z * 2;
  1712. float z_pos = box.Center.Z - box.Extent.Z;
  1713. //
  1714. // Make portals out of this box for any of the four directions
  1715. //
  1716. for (int dir = 0; dir < DIR_MAX; dir ++) {
  1717. if (cull_obj->Is_New_Portal ((PATHFIND_DIR)dir)) {
  1718. //
  1719. // Create the portal
  1720. //
  1721. cull_obj->Make_Portal ((PATHFIND_DIR)dir, portal_size, z_pos, 0.75F);
  1722. }
  1723. }
  1724. }
  1725. }
  1726. m_PossiblePortalList.Delete_All ();
  1727. return ;
  1728. }
  1729. ///////////////////////////////////////////////////////////////////////////
  1730. //
  1731. // Free_Floodfill_Boxes
  1732. //
  1733. ///////////////////////////////////////////////////////////////////////////
  1734. void
  1735. PathfindSectorBuilderClass::Free_Floodfill_Boxes (void)
  1736. {
  1737. //
  1738. // Loop over all the floodfill boxes
  1739. //
  1740. for (int index = 0; index < m_BodyBoxReleaseList.Count (); index ++) {
  1741. //
  1742. // Remove the floodfill box from the culling system and
  1743. // free our hold on it
  1744. //
  1745. FloodfillBoxClass *body_box = m_BodyBoxReleaseList[index];
  1746. body_box->Reset_Portal_Info ();
  1747. body_box->Set_Taken (false);
  1748. body_box->Set_Sector (NULL);
  1749. body_box->Remove ();
  1750. REF_PTR_RELEASE (body_box);
  1751. }
  1752. //
  1753. // Reset our systems
  1754. //
  1755. m_BodyBoxCullingSystem.Reset ();
  1756. m_BodyBoxReleaseList.Delete_All ();
  1757. return ;
  1758. }
  1759. ///////////////////////////////////////////////////////////////////////////
  1760. //
  1761. // Cleanup_Level_Features
  1762. //
  1763. ///////////////////////////////////////////////////////////////////////////
  1764. void
  1765. PathfindSectorBuilderClass::Cleanup_Level_Features (void)
  1766. {
  1767. //
  1768. // Loop over all the transition objects and remove them from the
  1769. // culling system
  1770. //
  1771. int count = m_LevelFeatureList.Count ();
  1772. for (int index = 0; index < count; index ++) {
  1773. LevelFeatureClass *cull_obj = m_LevelFeatureList[index];
  1774. m_LevelFeatureCullingSystem.Remove_Object (cull_obj);
  1775. MEMBER_RELEASE (cull_obj);
  1776. }
  1777. m_LevelFeatureList.Delete_All ();
  1778. return ;
  1779. }
  1780. ///////////////////////////////////////////////////////////////////////////
  1781. //
  1782. // Detect_Level_Features
  1783. //
  1784. ///////////////////////////////////////////////////////////////////////////
  1785. void
  1786. PathfindSectorBuilderClass::Detect_Level_Features (void)
  1787. {
  1788. //
  1789. // Detect the different types of level features
  1790. //
  1791. Detect_Doors ();
  1792. Detect_Elevators ();
  1793. Detect_Level_Transitions ();
  1794. //
  1795. // Optimize the level feature culling system
  1796. //
  1797. m_LevelFeatureCullingSystem.Re_Partition ();
  1798. return ;
  1799. }
  1800. ///////////////////////////////////////////////////////////////////////////
  1801. //
  1802. // Detect_Elevators
  1803. //
  1804. ///////////////////////////////////////////////////////////////////////////
  1805. void
  1806. PathfindSectorBuilderClass::Detect_Elevators (void)
  1807. {
  1808. //
  1809. // Get the list of all static objects from the physics scene
  1810. //
  1811. RefPhysListIterator iterator = ::Get_Scene_Editor ()->Get_Static_Object_Iterator ();
  1812. for (iterator.First (); !iterator.Is_Done (); iterator.Next ()) {
  1813. //
  1814. // Is this object an elevator?
  1815. //
  1816. PhysClass *phys_obj = iterator.Peek_Obj ();
  1817. ElevatorPhysClass *elevator = phys_obj->As_ElevatorPhysClass ();
  1818. if (elevator != NULL) {
  1819. const ElevatorPhysDefClass *definition = elevator->Get_ElevatorPhysDef ();
  1820. //
  1821. // Get information about the elevator
  1822. //
  1823. OBBoxClass lower_call;
  1824. OBBoxClass upper_call;
  1825. OBBoxClass lower_inside;
  1826. OBBoxClass upper_inside;
  1827. const Matrix3D &tm = elevator->Get_Transform ();
  1828. OBBoxClass::Transform (tm, definition->Get_Zone (ZONE_LOWER_CALL), &lower_call);
  1829. OBBoxClass::Transform (tm, definition->Get_Zone (ZONE_UPPER_CALL), &upper_call);
  1830. OBBoxClass::Transform (tm, definition->Get_Zone (ZONE_LOWER_INSIDE), &lower_inside);
  1831. OBBoxClass::Transform (tm, definition->Get_Zone (ZONE_UPPER_INSIDE), &upper_inside);
  1832. //
  1833. // Create a box that bounds the area the unit will actually be 'moving' in
  1834. //
  1835. AABoxClass bottom_box;
  1836. AABoxClass top_box;
  1837. bottom_box.Center = lower_inside.Center;
  1838. top_box.Center = upper_inside.Center;
  1839. top_box.Center.Z += m_SimBoxExtents.Z;
  1840. lower_inside.Compute_Axis_Aligned_Extent (&bottom_box.Extent);
  1841. upper_inside.Compute_Axis_Aligned_Extent (&top_box.Extent);
  1842. AABoxClass teleport_zone = bottom_box;
  1843. teleport_zone.Add_Box (top_box);
  1844. //
  1845. // Create a level feature for going UP the elevator
  1846. //
  1847. LevelFeatureClass *up_feature = new LevelFeatureClass;
  1848. up_feature->Set_Type (LevelFeatureClass::TYPE_ELEVATOR);
  1849. up_feature->Set_Start (lower_call);
  1850. up_feature->Set_End (upper_call);
  1851. up_feature->Set_End_TM (Matrix3D (upper_call.Center));
  1852. up_feature->Set_Teleport_Zone (teleport_zone);
  1853. up_feature->Set_Mechanism_ID (elevator->Get_ID ());
  1854. //
  1855. // Create a level feature for going DOWN the elevator
  1856. //
  1857. LevelFeatureClass *down_feature = new LevelFeatureClass;
  1858. down_feature->Set_Type (LevelFeatureClass::TYPE_ELEVATOR);
  1859. down_feature->Set_Start (upper_call);
  1860. down_feature->Set_End (lower_call);
  1861. down_feature->Set_End_TM (Matrix3D (lower_call.Center));
  1862. down_feature->Set_Teleport_Zone (teleport_zone);
  1863. down_feature->Set_Mechanism_ID (elevator->Get_ID ());
  1864. //
  1865. // Add the level features to the culling system
  1866. //
  1867. m_LevelFeatureCullingSystem.Add_Object (up_feature);
  1868. m_LevelFeatureCullingSystem.Add_Object (down_feature);
  1869. m_LevelFeatureList.Add (up_feature);
  1870. m_LevelFeatureList.Add (down_feature);
  1871. }
  1872. }
  1873. return ;
  1874. }
  1875. ///////////////////////////////////////////////////////////////////////////
  1876. //
  1877. // Detect_Doors
  1878. //
  1879. ///////////////////////////////////////////////////////////////////////////
  1880. void
  1881. PathfindSectorBuilderClass::Detect_Doors (void)
  1882. {
  1883. //
  1884. // Get the list of all static objects from the physics scene
  1885. //
  1886. RefPhysListIterator iterator = ::Get_Scene_Editor ()->Get_Static_Object_Iterator ();
  1887. for (iterator.First (); !iterator.Is_Done (); iterator.Next ()) {
  1888. //
  1889. // Is this object an elevator?
  1890. //
  1891. PhysClass *phys_obj = iterator.Peek_Obj ();
  1892. DoorPhysClass *door = phys_obj->As_DoorPhysClass ();
  1893. if ( door != NULL &&
  1894. door->Get_DoorPhysDef () != NULL &&
  1895. door->Get_DoorPhysDef ()->Is_Vehicle_Door () == false)
  1896. {
  1897. const DoorPhysDefClass *definition = door->Get_DoorPhysDef ();
  1898. //
  1899. // Get the door's trigger zones
  1900. //
  1901. const Matrix3D &tm = door->Get_Transform ();
  1902. OBBoxClass trigger_zone1;
  1903. OBBoxClass trigger_zone2;
  1904. OBBoxClass::Transform (tm, definition->Get_Trigger_Zone1 (), &trigger_zone1);
  1905. OBBoxClass::Transform (tm, definition->Get_Trigger_Zone2 (), &trigger_zone2);
  1906. //
  1907. // Create a box that bounds the area the unit will actually be 'moving' in
  1908. //
  1909. AABoxClass box1;
  1910. AABoxClass box2;
  1911. box1.Center = trigger_zone1.Center;
  1912. box2.Center = trigger_zone2.Center;
  1913. trigger_zone1.Compute_Axis_Aligned_Extent (&box1.Extent);
  1914. trigger_zone2.Compute_Axis_Aligned_Extent (&box2.Extent);
  1915. AABoxClass teleport_zone = box1;
  1916. teleport_zone.Add_Box (box2);
  1917. //
  1918. // Create a level feature for going one direction through the door
  1919. //
  1920. LevelFeatureClass *feature1 = new LevelFeatureClass;
  1921. feature1->Set_Type (LevelFeatureClass::TYPE_DOOR);
  1922. feature1->Set_Start (trigger_zone1);
  1923. feature1->Set_End (trigger_zone2);
  1924. feature1->Set_End_TM (Matrix3D (trigger_zone2.Center));
  1925. feature1->Set_Teleport_Zone (teleport_zone);
  1926. feature1->Set_Mechanism_ID (door->Get_ID ());
  1927. //
  1928. // Create a level feature for going the other direction through the door
  1929. //
  1930. LevelFeatureClass *feature2 = new LevelFeatureClass;
  1931. feature2->Set_Type (LevelFeatureClass::TYPE_DOOR);
  1932. feature2->Set_Start (trigger_zone2);
  1933. feature2->Set_End (trigger_zone1);
  1934. feature2->Set_End_TM (Matrix3D (trigger_zone1.Center));
  1935. feature2->Set_Teleport_Zone (teleport_zone);
  1936. feature2->Set_Mechanism_ID (door->Get_ID ());
  1937. //
  1938. // Add the level features to the culling system
  1939. //
  1940. m_LevelFeatureCullingSystem.Add_Object (feature1);
  1941. m_LevelFeatureCullingSystem.Add_Object (feature2);
  1942. m_LevelFeatureList.Add (feature1);
  1943. m_LevelFeatureList.Add (feature2);
  1944. }
  1945. }
  1946. return ;
  1947. }
  1948. ///////////////////////////////////////////////////////////////////////////
  1949. //
  1950. // Detect_Level_Transitions
  1951. //
  1952. ///////////////////////////////////////////////////////////////////////////
  1953. void
  1954. PathfindSectorBuilderClass::Detect_Level_Transitions (void)
  1955. {
  1956. int ladder_index = 0;
  1957. //
  1958. // Loop through all the transitions in the level
  1959. //
  1960. TransitionNodeClass *node = NULL;
  1961. for (node = (TransitionNodeClass *)NodeMgrClass::Get_First (NODE_TYPE_TRANSITION);
  1962. node != NULL;
  1963. node = (TransitionNodeClass *)NodeMgrClass::Get_Next (node, NODE_TYPE_TRANSITION))
  1964. {
  1965. //
  1966. // Loop through all the different transitions in this node
  1967. //
  1968. bool need_new_ladder_index = true;
  1969. int count = node->Get_Transition_Count ();
  1970. for (int index = 0; index < count; index ++) {
  1971. TransitionInstanceClass *transition = node->Get_Transition (index);
  1972. if (transition != NULL) {
  1973. //
  1974. // Build an AABox from the zone this transition uses
  1975. //
  1976. OBBoxClass zone = transition->Get_Zone ();
  1977. //
  1978. // We handle each type of transition differently
  1979. //
  1980. switch (transition->Get_Type ())
  1981. {
  1982. //
  1983. // For ladders, we need to find the 'exit' point
  1984. //
  1985. case TransitionDataClass::LADDER_ENTER_TOP:
  1986. case TransitionDataClass::LADDER_ENTER_BOTTOM:
  1987. {
  1988. Vector3 pos = zone.Center;
  1989. //
  1990. // Insert this transition into our culling system
  1991. //
  1992. LevelFeatureClass *level_feature = new LevelFeatureClass;
  1993. level_feature->Set_Start (zone);
  1994. //
  1995. // Search for the exit transition
  1996. //
  1997. TransitionInstanceClass *exit_transition = NULL;
  1998. TransitionNodeClass *exit_node = NULL;
  1999. if (transition->Get_Type () == TransitionDataClass::LADDER_ENTER_BOTTOM) {
  2000. exit_transition = Find_Transition (TransitionDataClass::LADDER_EXIT_TOP, pos, 100.0F, &exit_node);
  2001. } else {
  2002. exit_transition = Find_Transition (TransitionDataClass::LADDER_EXIT_BOTTOM, pos, -100.0F, &exit_node);
  2003. }
  2004. //
  2005. // Pass the exit zone onto the level feature object
  2006. //
  2007. if (exit_transition != NULL) {
  2008. level_feature->Set_End (exit_transition->Get_Zone ());
  2009. level_feature->Set_End_TM (exit_transition->Get_Ending_TM ());
  2010. AABoxClass box;
  2011. box.Center = pos;
  2012. box.Extent = m_SimBoxExtents;
  2013. box.Extent.X *= 4.0F;
  2014. box.Extent.Y *= 4.0F;
  2015. //
  2016. // Create a box that encompasses the start position and end position
  2017. //
  2018. AABoxClass teleport_box (box);
  2019. box.Center = exit_transition->Get_Ending_TM ().Get_Translation ();
  2020. box.Center.Z += m_SimBoxExtents.Z;
  2021. teleport_box.Add_Box (box);
  2022. //
  2023. // Pass the teleport area onto the level feature
  2024. //
  2025. level_feature->Set_Teleport_Zone (teleport_box);
  2026. }
  2027. //
  2028. // Set the level feature's type
  2029. //
  2030. if (transition->Get_Type () == TransitionDataClass::LADDER_ENTER_BOTTOM) {
  2031. level_feature->Set_Type (LevelFeatureClass::TYPE_LADDER_BOTTOM);
  2032. } else {
  2033. level_feature->Set_Type (LevelFeatureClass::TYPE_LADDER_TOP);
  2034. }
  2035. int new_ladder_index = -1;
  2036. //
  2037. // Can we reuse the same ladder index that the exit portal uses?
  2038. //
  2039. if (exit_node != NULL && exit_node->Get_Transition_Game_Obj () != NULL) {
  2040. new_ladder_index = exit_node->Get_Transition_Game_Obj ()->Get_Ladder_Index ();
  2041. if (new_ladder_index != -1) {
  2042. need_new_ladder_index = false;
  2043. }
  2044. }
  2045. //
  2046. // Increment the ladder counter as necessary
  2047. //
  2048. if (need_new_ladder_index) {
  2049. need_new_ladder_index = false;
  2050. ladder_index ++;
  2051. new_ladder_index = ladder_index;
  2052. }
  2053. //
  2054. // Give the level feature a unique identifier
  2055. //
  2056. level_feature->Set_Mechanism_ID (ladder_index);
  2057. if (node->Get_Transition_Game_Obj () != NULL) {
  2058. node->Get_Transition_Game_Obj ()->Set_Ladder_Index (ladder_index);
  2059. }
  2060. //
  2061. // Attempt to tie the bottom and top transitions to the same value
  2062. //
  2063. if (exit_node != NULL && exit_node->Get_Transition_Game_Obj () != NULL) {
  2064. exit_node->Get_Transition_Game_Obj ()->Set_Ladder_Index (ladder_index);
  2065. }
  2066. //
  2067. // Add the level feature to the culling systems
  2068. //
  2069. m_LevelFeatureCullingSystem.Add_Object (level_feature);
  2070. m_LevelFeatureList.Add (level_feature);
  2071. }
  2072. break;
  2073. default:
  2074. break;
  2075. }
  2076. }
  2077. }
  2078. }
  2079. return ;
  2080. }
  2081. ///////////////////////////////////////////////////////////////////////////
  2082. //
  2083. // Post_Process_Floodfill_For_Level_Features
  2084. //
  2085. ///////////////////////////////////////////////////////////////////////////
  2086. void
  2087. PathfindSectorBuilderClass::Post_Process_Floodfill_For_Level_Features (void)
  2088. {
  2089. //
  2090. // Loop over all the level features
  2091. //
  2092. for (int index = 0; index < m_LevelFeatureList.Count (); index ++) {
  2093. LevelFeatureClass *level_feature = m_LevelFeatureList[index];
  2094. if (level_feature != NULL) {
  2095. //
  2096. // Get the area where the player will be moving
  2097. //
  2098. AABoxClass box = level_feature->Get_Teleport_Zone ();
  2099. //
  2100. // Loop over all the body-boxes that exist in this area
  2101. //
  2102. m_BodyBoxCullingSystem.Collect_Boxes (box);
  2103. DynamicVectorClass<FloodfillBoxClass *> &list = m_BodyBoxCullingSystem.Get_Collection_List ();
  2104. for (int index = 0; index < list.Count (); index ++) {
  2105. FloodfillBoxClass *body_box = list[index];
  2106. //
  2107. // Force the test to pass in the z-component
  2108. //
  2109. box.Extent.Z = 1000.0F;
  2110. //
  2111. // Remove this box from the system if its completely contained
  2112. // inside the teleport zone
  2113. //
  2114. AABoxClass test_box = Get_Body_Box_Bounds (body_box);
  2115. if (CollisionMath::Overlap_Test (box, test_box) == CollisionMath::INSIDE) {
  2116. //
  2117. // Remove the box from the possible portal list (if necessary)
  2118. //
  2119. int portal_list_index = m_PossiblePortalList.ID (body_box);
  2120. if (portal_list_index != -1) {
  2121. m_PossiblePortalList.Delete (portal_list_index);
  2122. }
  2123. //
  2124. // Remove this box from the system
  2125. //
  2126. m_BodyBoxReleaseList.Add (body_box);
  2127. body_box->Unlink ();
  2128. m_BodyBoxCullingSystem.Remove_Box (body_box);
  2129. }
  2130. }
  2131. }
  2132. }
  2133. return ;
  2134. }
  2135. ///////////////////////////////////////////////////////////////////////////
  2136. //
  2137. // Apply_Level_Features
  2138. //
  2139. ///////////////////////////////////////////////////////////////////////////
  2140. void
  2141. PathfindSectorBuilderClass::Apply_Level_Features (void)
  2142. {
  2143. //
  2144. // Loop over all the level features and create sectors and portals
  2145. // for them
  2146. //
  2147. for (int index = 0; index < m_LevelFeatureList.Count (); index ++) {
  2148. LevelFeatureClass *level_feature = m_LevelFeatureList[index];
  2149. if (level_feature != NULL) {
  2150. //
  2151. // Integrate this feature into the pathfind data
  2152. //
  2153. Build_Sector_For_Level_Feature (level_feature);
  2154. }
  2155. }
  2156. return ;
  2157. }
  2158. ///////////////////////////////////////////////////////////////////////////
  2159. //
  2160. // Find_Transition
  2161. //
  2162. ///////////////////////////////////////////////////////////////////////////
  2163. TransitionInstanceClass *
  2164. PathfindSectorBuilderClass::Find_Transition
  2165. (
  2166. TransitionDataClass::StyleType transition_type,
  2167. const Vector3 & start_pos,
  2168. float z_delta,
  2169. TransitionNodeClass ** transition_node
  2170. )
  2171. {
  2172. TransitionInstanceClass *retval = NULL;
  2173. (*transition_node) = NULL;
  2174. float start_z = start_pos.Z;
  2175. float closest_z = 1000000;
  2176. //
  2177. // Loop over all the transitions in the level and find the one
  2178. // that most closely matches what we are looking for
  2179. //
  2180. TransitionNodeClass *node = NULL;
  2181. for (node = (TransitionNodeClass *)NodeMgrClass::Get_First (NODE_TYPE_TRANSITION);
  2182. node != NULL;
  2183. node = (TransitionNodeClass *)NodeMgrClass::Get_Next (node, NODE_TYPE_TRANSITION))
  2184. {
  2185. //
  2186. // See if we can find a transition game object inside the node
  2187. // that is the type we are looking for.
  2188. //
  2189. int index = node->Find_Transition (transition_type);
  2190. if (index >= 0) {
  2191. //
  2192. // Get the transition game object
  2193. //
  2194. TransitionInstanceClass *transition = node->Get_Transition (index);
  2195. if (transition != NULL) {
  2196. const OBBoxClass &zone = transition->Get_Zone ();
  2197. //
  2198. // Determine how 'far' we are from this transition
  2199. //
  2200. float curr_z_min = zone.Center.Z - zone.Extent.Z;
  2201. float curr_z_max = zone.Center.Z + zone.Extent.Z;
  2202. float curr_delta = min (WWMath::Fabs (start_z - curr_z_min), WWMath::Fabs (start_z - curr_z_max));
  2203. //
  2204. // Is this transition zone the one we are looking for?
  2205. //
  2206. if ( (curr_delta < closest_z) &&
  2207. (WWMath::Fabs (start_pos.X - zone.Center.X) < 1.0F) &&
  2208. (WWMath::Fabs (start_pos.Y - zone.Center.Y) < 1.0F))
  2209. {
  2210. (*transition_node) = node;
  2211. retval = transition;
  2212. closest_z = curr_delta;
  2213. }
  2214. }
  2215. }
  2216. }
  2217. return retval;
  2218. }
  2219. ///////////////////////////////////////////////////////////////////////////
  2220. //
  2221. // Find_Sector
  2222. //
  2223. ///////////////////////////////////////////////////////////////////////////
  2224. PathfindSectorClass *
  2225. PathfindSectorBuilderClass::Find_Sector
  2226. (
  2227. const Vector3 & point,
  2228. const AABoxClass & box
  2229. )
  2230. {
  2231. PathfindSectorClass *sector = PathfindClass::Get_Instance ()->Find_Sector (point, 1.0F);
  2232. if (sector == NULL) {
  2233. sector = PathfindClass::Get_Instance ()->Find_Sector (box.Center, 1.0F);
  2234. }
  2235. if (sector == NULL) {
  2236. Vector3 box_point = box.Center;
  2237. box_point.X += box.Extent.X;
  2238. box_point.Y += box.Extent.Y;
  2239. sector = PathfindClass::Get_Instance ()->Find_Sector (box_point, 1.0F);
  2240. }
  2241. if (sector == NULL) {
  2242. Vector3 box_point = box.Center;
  2243. box_point.X -= box.Extent.X;
  2244. box_point.Y -= box.Extent.Y;
  2245. sector = PathfindClass::Get_Instance ()->Find_Sector (box_point, 1.0F);
  2246. }
  2247. if (sector == NULL) {
  2248. Vector3 box_point = box.Center;
  2249. box_point.X += box.Extent.X;
  2250. box_point.Y -= box.Extent.Y;
  2251. sector = PathfindClass::Get_Instance ()->Find_Sector (box_point, 1.0F);
  2252. }
  2253. if (sector == NULL) {
  2254. Vector3 box_point = box.Center;
  2255. box_point.X -= box.Extent.X;
  2256. box_point.Y += box.Extent.Y;
  2257. sector = PathfindClass::Get_Instance ()->Find_Sector (box_point, 1.0F);
  2258. }
  2259. return sector;
  2260. }
  2261. ///////////////////////////////////////////////////////////////////////////
  2262. //
  2263. // Build_Sector_For_Level_Feature
  2264. //
  2265. ///////////////////////////////////////////////////////////////////////////
  2266. void
  2267. PathfindSectorBuilderClass::Build_Sector_For_Level_Feature (LevelFeatureClass *level_feature)
  2268. {
  2269. if (level_feature == NULL) {
  2270. return ;
  2271. }
  2272. //
  2273. // Get the starting and ending positions
  2274. //
  2275. Matrix3D end_tm = level_feature->Get_End_TM ();
  2276. Vector3 end_pos = end_tm.Get_Translation ();
  2277. Vector3 start_pos = level_feature->Get_Start ().Center;
  2278. //
  2279. // Get the starting and ending AABox's for this feature
  2280. //
  2281. AABoxClass start_box;
  2282. AABoxClass end_box;
  2283. level_feature->Get_Start_AABox (start_box);
  2284. level_feature->Get_End_AABox (end_box);
  2285. Vector3 sector_end_pos = end_pos;
  2286. //
  2287. // Assume the player will want to exit "away" from where (s)he entered
  2288. //
  2289. if (level_feature->Get_Type () == LevelFeatureClass::TYPE_DOOR) {
  2290. Vector3 offset = end_box.Center - start_box.Center;
  2291. offset.Normalize ();
  2292. sector_end_pos = end_pos + offset;
  2293. Clip_Point (&sector_end_pos, end_box);
  2294. }
  2295. //
  2296. // Are there any pathfinding sectors intersecting the
  2297. // start and ending regions?
  2298. //
  2299. PathfindSectorClass *start_sector = Find_Sector (start_pos, start_box);
  2300. PathfindSectorClass *end_sector = Find_Sector (sector_end_pos, end_box);
  2301. if ( level_feature->Get_Type () == LevelFeatureClass::TYPE_LADDER_BOTTOM ||
  2302. level_feature->Get_Type () == LevelFeatureClass::TYPE_LADDER_TOP)
  2303. {
  2304. if (end_sector != NULL) {
  2305. end_box = end_sector->Get_Bounding_Box ();
  2306. }
  2307. }
  2308. //
  2309. // Expand the end box by a little bit
  2310. //
  2311. /*end_box.Extent.X += 0.25F;
  2312. end_box.Extent.Y += 0.25F;
  2313. end_box.Extent.Z += 0.25F;
  2314. //
  2315. // Build a list of sectors that the exit should connect to
  2316. //
  2317. DynamicVectorClass<PathfindSectorClass *> end_sector_list;
  2318. PathfindClass::Get_Instance ()->Collect_Sectors (end_sector_list, end_box, start_sector);*/
  2319. //
  2320. // Were we successful?
  2321. //
  2322. if ((start_sector != NULL) && (end_sector != NULL)) {
  2323. //
  2324. // Create a sector from scratch
  2325. //
  2326. PathfindSectorClass *new_sector = new PathfindSectorClass;
  2327. new_sector->Set_Bounding_Box (AABoxClass (Vector3 (0, 0, 0), Vector3 (0, 0, 0)));
  2328. PathfindClass::Get_Instance ()->Add_Sector (new_sector);
  2329. new_sector->Release_Ref ();
  2330. //
  2331. // Create the starting portal
  2332. //
  2333. PathfindActionPortalClass *enter_portal = new PathfindActionPortalClass;
  2334. enter_portal->Set_Bounding_Box (start_box);
  2335. enter_portal->Add_Dest_Sector (new_sector);
  2336. enter_portal->Set_Destination (end_pos);
  2337. //
  2338. // Create the ending portal
  2339. //
  2340. PathfindActionPortalClass *exit_portal = new PathfindActionPortalClass;
  2341. exit_portal->Set_Bounding_Box (end_box);
  2342. exit_portal->Add_Dest_Sector (end_sector);
  2343. //
  2344. // Determine which type of action should be performed at this portal
  2345. //
  2346. switch (level_feature->Get_Type ())
  2347. {
  2348. case LevelFeatureClass::TYPE_LADDER_BOTTOM:
  2349. case LevelFeatureClass::TYPE_LADDER_TOP:
  2350. {
  2351. AABoxClass end_trigger_zone;
  2352. level_feature->Get_End_AABox (end_trigger_zone);
  2353. enter_portal->Set_Destination (end_trigger_zone.Center);
  2354. enter_portal->Set_Action_Type (PathClass::ACTION_LADDER);
  2355. enter_portal->Set_Mechanism_ID (level_feature->Get_Mechanism_ID ());
  2356. exit_portal->Set_Action_Type (PathClass::ACTION_NONE);
  2357. break;
  2358. }
  2359. case LevelFeatureClass::TYPE_DOOR:
  2360. case LevelFeatureClass::TYPE_ELEVATOR:
  2361. enter_portal->Set_Action_Type (PathClass::ACTION_MECHANISM);
  2362. enter_portal->Set_Mechanism_ID (level_feature->Get_Mechanism_ID ());
  2363. exit_portal->Set_Action_Type (PathClass::ACTION_NONE);
  2364. break;
  2365. }
  2366. //
  2367. // Let the enter portal "know" where its going to end up...
  2368. //
  2369. enter_portal->Set_Exit_Portal (exit_portal);
  2370. exit_portal->Set_Enter_Portal (enter_portal);
  2371. //
  2372. // Register the new portals with the pathfinding system,
  2373. // and let the sectors know they can access these portals.
  2374. //
  2375. int enter_portal_index = PathfindClass::Get_Instance ()->Add_Portal (enter_portal);
  2376. int exit_portal_index = PathfindClass::Get_Instance ()->Add_Portal (exit_portal);
  2377. start_sector->Add_Portal (enter_portal_index);
  2378. new_sector->Add_Portal (exit_portal_index);
  2379. REF_PTR_RELEASE (enter_portal);
  2380. REF_PTR_RELEASE (exit_portal);
  2381. }
  2382. return ;
  2383. }
  2384. ///////////////////////////////////////////////////////////////////////////
  2385. //
  2386. // Check_For_Level_Feature
  2387. //
  2388. ///////////////////////////////////////////////////////////////////////////
  2389. void
  2390. PathfindSectorBuilderClass::Check_For_Level_Feature (FloodfillBoxClass *body_box)
  2391. {
  2392. if (m_LevelFeatureCullingSystem.Object_Count () > 0) {
  2393. AABoxClass bounding_box = Get_Body_Box_Bounds (body_box);
  2394. //
  2395. // Find all level features that intersect our current position
  2396. //
  2397. m_LevelFeatureCullingSystem.Reset_Collection ();
  2398. m_LevelFeatureCullingSystem.Collect_Objects (bounding_box);
  2399. //
  2400. // Find all the features this body box intersects
  2401. //
  2402. DynamicVectorClass<LevelFeatureClass *> feature_list;
  2403. LevelFeatureClass *level_feature = NULL;
  2404. for ( level_feature = m_LevelFeatureCullingSystem.Get_First_Collected_Object ();
  2405. level_feature != NULL;
  2406. level_feature = m_LevelFeatureCullingSystem.Get_Next_Collected_Object (level_feature))
  2407. {
  2408. feature_list.Add (level_feature);
  2409. }
  2410. //
  2411. // Loop through all the features in our list and process any 'portals' (ladders, doors, etc)
  2412. //
  2413. for (int index = 0; index < feature_list.Count (); index ++) {
  2414. level_feature = feature_list[index];
  2415. //
  2416. // Get the bounding box for the pathfind object and the level feature's 'start-zone'
  2417. //
  2418. AABoxClass pathfind_box = Get_Body_Box_Bounds (body_box);
  2419. AABoxClass feature_box;
  2420. level_feature->Get_Start_AABox (feature_box);
  2421. //
  2422. // Do these boxe's intersect?
  2423. //
  2424. if ( (pathfind_box.Center.X + pathfind_box.Extent.X < feature_box.Center.X + feature_box.Extent.X) &&
  2425. (pathfind_box.Center.X - pathfind_box.Extent.X > feature_box.Center.X - feature_box.Extent.X) &&
  2426. (pathfind_box.Center.Y + pathfind_box.Extent.Y < feature_box.Center.Y + feature_box.Extent.Y) &&
  2427. (pathfind_box.Center.Y - pathfind_box.Extent.Y > feature_box.Center.Y - feature_box.Extent.Y))
  2428. {
  2429. //
  2430. // Continue our pathfind across this feature (i.e. up the ladder, down the elevator, etc)
  2431. //
  2432. Path_Across_Feature (level_feature);
  2433. }
  2434. }
  2435. }
  2436. return ;
  2437. }
  2438. ///////////////////////////////////////////////////////////////////////////
  2439. //
  2440. // Path_Across_Feature
  2441. //
  2442. ///////////////////////////////////////////////////////////////////////////
  2443. void
  2444. PathfindSectorBuilderClass::Path_Across_Feature (LevelFeatureClass *level_feature)
  2445. {
  2446. //
  2447. // Get the point where we think this feature will 'teleport' us to
  2448. //
  2449. Vector3 expected_pos = level_feature->Get_End_TM ().Get_Translation ();
  2450. expected_pos.Z += m_SimBoxExtents.Z;
  2451. //
  2452. // Snap this position to our pathfind grid
  2453. //
  2454. Vector3 normalized_pos = expected_pos;
  2455. normalized_pos.X = (int(expected_pos.X / m_SimBoundingBox.X)) * m_SimBoundingBox.X;
  2456. normalized_pos.Y = (int(expected_pos.Y / m_SimBoundingBox.Y)) * m_SimBoundingBox.Y;
  2457. //
  2458. // Can we stand at this new position?
  2459. //
  2460. AABoxClass new_box;
  2461. if (Try_Standing_Here (normalized_pos, &new_box)) {
  2462. //
  2463. // Is this cell already marked?
  2464. //
  2465. Vector3 position = new_box.Center;
  2466. position.Z = new_box.Center.Z;
  2467. FloodfillBoxClass *occupant = Get_Sector_Occupant (position);
  2468. if (occupant == NULL) {
  2469. //
  2470. // Mark this cell and add it to the list of sectors
  2471. // that need to be recursed.
  2472. //
  2473. occupant = Mark_Sector (new_box);
  2474. m_FloodFillProcessList.Add (occupant);
  2475. }
  2476. }
  2477. return ;
  2478. }
  2479. /////////////////////////////////////////////////////////////////////////////
  2480. //
  2481. // fnPathfindDialogThread
  2482. //
  2483. ////////////////////////////////////////////////////////////////////////////
  2484. UINT
  2485. fnPathfindDialogThread
  2486. (
  2487. DWORD dwparam1,
  2488. DWORD dwparam2,
  2489. DWORD /*dwparam3*/,
  2490. HRESULT* /*presult*/,
  2491. HWND* /*phmain_wnd*/
  2492. )
  2493. {
  2494. GeneratingPathfindDialogClass *dialog = new GeneratingPathfindDialogClass (::AfxGetMainWnd ());
  2495. dialog->ShowWindow (SW_SHOW);
  2496. //
  2497. // Return the dialog object to the caller
  2498. //
  2499. GeneratingPathfindDialogClass **return_val = (GeneratingPathfindDialogClass **)dwparam2;
  2500. if (return_val != NULL) {
  2501. (*return_val) = dialog;
  2502. }
  2503. return 1;
  2504. }
  2505. ////////////////////////////////////////////////////////////////////////////
  2506. //
  2507. // Show_Dialog
  2508. //
  2509. ////////////////////////////////////////////////////////////////////////////
  2510. void
  2511. PathfindSectorBuilderClass::Show_Dialog (void)
  2512. {
  2513. ::Create_UI_Thread (fnPathfindDialogThread, 0, (DWORD)&m_pDialog, 0, NULL, NULL);
  2514. return ;
  2515. }
  2516. ////////////////////////////////////////////////////////////////////////////
  2517. //
  2518. // Close_Dialog
  2519. //
  2520. ////////////////////////////////////////////////////////////////////////////
  2521. void
  2522. PathfindSectorBuilderClass::Close_Dialog (void)
  2523. {
  2524. if (m_pDialog != NULL) {
  2525. ::PostMessage (m_pDialog->m_hWnd, WM_USER+101, 0, 0L);
  2526. }
  2527. return ;
  2528. }