floodfillbox.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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/wwphys/floodfillbox.h $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 5/03/01 10:27a $*
  29. * *
  30. * $Revision:: 3 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #if defined(_MSC_VER)
  36. #pragma once
  37. #endif
  38. #ifndef __FLOODFILLBOX_H
  39. #define __FLOODFILLBOX_H
  40. #include "vector3.h"
  41. #include "matrix3d.h"
  42. #include "vector.h"
  43. #include "refcount.h"
  44. #include "bittype.h"
  45. //////////////////////////////////////////////////////////////////////////
  46. // Forward delcarations
  47. //////////////////////////////////////////////////////////////////////////
  48. class FloodfillBoxClass;
  49. class PathfindSectorClass;
  50. class PathfindPortalClass;
  51. //////////////////////////////////////////////////////////////////////////
  52. // Data types
  53. //////////////////////////////////////////////////////////////////////////
  54. typedef DynamicVectorClass<FloodfillBoxClass *> BODY_BOX_LIST;
  55. typedef enum
  56. {
  57. DIR_FORWARD = 0,
  58. DIR_LEFT,
  59. DIR_BACKWARD,
  60. DIR_RIGHT,
  61. DIR_MAX,
  62. DIR_UP = DIR_FORWARD,
  63. DIR_DOWN = DIR_BACKWARD,
  64. } PATHFIND_DIR;
  65. typedef enum
  66. {
  67. MASK_NONE = 0,
  68. MASK_FORWARD = 1,
  69. MASK_LEFT = 2,
  70. MASK_BACKWARD = 4,
  71. MASK_RIGHT = 8,
  72. MASK_MAX,
  73. MASK_UP = MASK_FORWARD,
  74. MASK_DOWN = MASK_BACKWARD,
  75. } DIRECTION_MASK;
  76. inline PATHFIND_DIR
  77. Mask_to_Dir (DIRECTION_MASK mask)
  78. {
  79. for (int dir = 0; dir < DIR_MAX; dir ++) {
  80. if ((1 << dir) == mask) {
  81. return PATHFIND_DIR(dir);
  82. }
  83. }
  84. return DIR_MAX;
  85. }
  86. inline PATHFIND_DIR
  87. Inverse_Pathfind_Dir (PATHFIND_DIR dir)
  88. {
  89. if (dir < 2) return PATHFIND_DIR(dir + 2);
  90. return PATHFIND_DIR(dir - 2);
  91. }
  92. inline PATHFIND_DIR
  93. Clockwise_Pathfind_Dir (PATHFIND_DIR dir)
  94. {
  95. return PATHFIND_DIR((dir + 3) % DIR_MAX);
  96. }
  97. //////////////////////////////////////////////////////////////////////////
  98. //
  99. // FloodfillBoxClass
  100. //
  101. //////////////////////////////////////////////////////////////////////////
  102. class FloodfillBoxClass : public RefCountClass
  103. {
  104. public:
  105. //////////////////////////////////////////////////////////////////////
  106. // Public constructors/destructors
  107. //////////////////////////////////////////////////////////////////////
  108. FloodfillBoxClass (void)
  109. : m_Sector (NULL),
  110. m_Flags (NeedsProcessing),
  111. m_DirectionInfo (0),
  112. m_CompressedSkipCount (0),
  113. m_MinZPos (0),
  114. m_MaxZPos (0),
  115. m_GridLink (NULL),
  116. m_Prev (NULL),
  117. m_Next (NULL) { ::memset (m_Neighbors, 0, sizeof (m_Neighbors)); }
  118. virtual ~FloodfillBoxClass (void) { Remove (); }
  119. //////////////////////////////////////////////////////////////////////
  120. // Access to the Position/Orientation state of the object
  121. //////////////////////////////////////////////////////////////////////
  122. Vector3 Get_Position (void) const { return m_Position; }
  123. void Set_Position (const Vector3 &pos) { m_Position = pos; }
  124. float Get_Min_Z_Pos (void) const { return m_MinZPos; }
  125. float Get_Max_Z_Pos (void) const { return m_MaxZPos; }
  126. void Set_Min_Z_Pos (float pos) { m_MinZPos = pos; }
  127. void Set_Max_Z_Pos (float pos) { m_MaxZPos = pos; }
  128. Vector3 Get_Center (void) const;
  129. Vector3 Get_Extent (void) const;
  130. //////////////////////////////////////////////////////////////////////
  131. // Timestep methods
  132. //////////////////////////////////////////////////////////////////////
  133. void Timestep (float dt) {}
  134. //////////////////////////////////////////////////////////////////////
  135. // Adjacent sector methods
  136. //////////////////////////////////////////////////////////////////////
  137. FloodfillBoxClass * Peek_Neighbor (PATHFIND_DIR dir, bool only_traversible = true);
  138. void Set_Neighbor (PATHFIND_DIR dir, FloodfillBoxClass *obj, bool traversible);
  139. FloodfillBoxClass * Find_Relative (int x, int y);
  140. bool Is_Two_Way_Traversible (PATHFIND_DIR dir);
  141. void Set_Taken (bool onoff = true) { Set_Flag (IsTaken, onoff); }
  142. bool Is_Taken (void) { return bool((m_Flags & IsTaken) == IsTaken); }
  143. uint8 Get_Compress_Skipped_Count (void) { return m_CompressedSkipCount; }
  144. void Inc_Compress_Skipped_Count (void) { m_CompressedSkipCount ++; }
  145. //////////////////////////////////////////////////////////////////////
  146. // Delayed processing methods
  147. //////////////////////////////////////////////////////////////////////
  148. bool Needs_Processing (void) const { return bool((m_Flags & NeedsProcessing) == NeedsProcessing); }
  149. void Needs_Processing (bool needs_it) { Set_Flag (NeedsProcessing, needs_it); }
  150. //////////////////////////////////////////////////////////////////////
  151. // Linked list methods
  152. //////////////////////////////////////////////////////////////////////
  153. static FloodfillBoxClass * Get_First (void) { return m_First; }
  154. static FloodfillBoxClass * Get_Last (void) { return m_Last; }
  155. FloodfillBoxClass * Get_Next (void) { return m_Next; }
  156. FloodfillBoxClass * Get_Prev (void) { return m_Prev; }
  157. void Set_Next (FloodfillBoxClass *next) { m_Next = next; }
  158. void Set_Prev (FloodfillBoxClass *prev) { m_Prev = prev; }
  159. static void Add (FloodfillBoxClass *new_obj);
  160. void Remove (void);
  161. void Unlink (void);
  162. bool Is_Edge (void);
  163. bool Are_Neighbors_Processed (void);
  164. //////////////////////////////////////////////////////////////////////
  165. // Portal generation methods
  166. //////////////////////////////////////////////////////////////////////
  167. PathfindSectorClass * Peek_Sector (void) { return m_Sector; }
  168. void Set_Sector (PathfindSectorClass *sector) { m_Sector = sector; }
  169. bool Is_New_Portal (PATHFIND_DIR dir, PathfindSectorClass *dest_sector = NULL);
  170. PathfindPortalClass * Make_Portal (PATHFIND_DIR dir, const Vector3 &box_size, float z_pos, float min_acceptable_size);
  171. void Reset_Portal_Info (void) { (m_DirectionInfo &= ~PortalMask); }
  172. void Part_Of_Portal (PATHFIND_DIR dir, bool onoff);
  173. bool Part_Of_Portal (PATHFIND_DIR dir);
  174. //////////////////////////////////////////////////////////////////////
  175. // Grid link methods
  176. //////////////////////////////////////////////////////////////////////
  177. FloodfillBoxClass * Get_Grid_Link (void) { return m_GridLink; }
  178. void Set_Grid_Link (FloodfillBoxClass *link) { m_GridLink = link; }
  179. protected:
  180. //////////////////////////////////////////////////////////////////////
  181. // Protected methods
  182. //////////////////////////////////////////////////////////////////////
  183. void Set_Flag (uint8 flag, bool value);
  184. void Set_Traversible (PATHFIND_DIR dir, bool onoff);
  185. bool Get_Traversible (PATHFIND_DIR dir);
  186. private:
  187. //////////////////////////////////////////////////////////////////////
  188. // Private methods
  189. //////////////////////////////////////////////////////////////////////
  190. typedef enum
  191. {
  192. IsTaken = 0x01,
  193. NeedsProcessing = 0x02,
  194. } Flags;
  195. typedef enum
  196. {
  197. IsTraversibleUp = 0x01,
  198. IsTraversibleLeft = 0x02,
  199. IsTraversibleDown = 0x04,
  200. IsTraversibleRight = 0x08,
  201. TraversibleMask = 0x0F,
  202. IsPortalUp = 0x10,
  203. IsPortalLeft = 0x20,
  204. IsPortalDown = 0x40,
  205. IsPortalRight = 0x80,
  206. PortalMask = 0xF0,
  207. } Directions;
  208. //////////////////////////////////////////////////////////////////////
  209. // Private member data
  210. //////////////////////////////////////////////////////////////////////
  211. FloodfillBoxClass * m_Neighbors[4];
  212. uint8 m_Flags;
  213. uint8 m_DirectionInfo;
  214. uint8 m_CompressedSkipCount;
  215. FloodfillBoxClass * m_Prev;
  216. FloodfillBoxClass * m_Next;
  217. PathfindSectorClass * m_Sector;
  218. float m_MinZPos;
  219. float m_MaxZPos;
  220. Vector3 m_Position;
  221. FloodfillBoxClass * m_GridLink;
  222. //////////////////////////////////////////////////////////////////////
  223. // Static member data
  224. //////////////////////////////////////////////////////////////////////
  225. static FloodfillBoxClass * m_First;
  226. static FloodfillBoxClass * m_Last;
  227. };
  228. //////////////////////////////////////////////////////////////////////////
  229. // Find_Relative
  230. //////////////////////////////////////////////////////////////////////////
  231. inline FloodfillBoxClass *
  232. FloodfillBoxClass::Find_Relative (int cx, int cy)
  233. {
  234. PATHFIND_DIR x_dir = DIR_RIGHT;
  235. PATHFIND_DIR y_dir = DIR_BACKWARD;
  236. if (cx < 0) {
  237. x_dir = DIR_LEFT;
  238. cx = -cx;
  239. }
  240. if (cy < 0) {
  241. y_dir = DIR_FORWARD;
  242. cy = -cy;
  243. }
  244. FloodfillBoxClass *curr_box = this;
  245. for (int x = 0; x < cx; x ++) {
  246. curr_box = curr_box->Peek_Neighbor (x_dir);
  247. }
  248. for (int y = 0; y < cy; y ++) {
  249. curr_box = curr_box->Peek_Neighbor (y_dir);
  250. }
  251. return curr_box;
  252. }
  253. //////////////////////////////////////////////////////////////////////////
  254. // Remove
  255. //////////////////////////////////////////////////////////////////////////
  256. inline void
  257. FloodfillBoxClass::Remove (void)
  258. {
  259. if (m_Prev) {
  260. m_Prev->m_Next = m_Next;
  261. }
  262. if (m_Next) {
  263. m_Next->m_Prev = m_Prev;
  264. }
  265. if (m_First == this) {
  266. m_First = m_Next;
  267. }
  268. if (m_Last == this) {
  269. m_Last = m_Prev;
  270. }
  271. m_Prev = NULL;
  272. m_Next = NULL;
  273. return ;
  274. }
  275. //////////////////////////////////////////////////////////////////////////
  276. // Add
  277. //////////////////////////////////////////////////////////////////////////
  278. inline void
  279. FloodfillBoxClass::Add (FloodfillBoxClass *new_obj)
  280. {
  281. if (m_Last == NULL) {
  282. m_First = new_obj;
  283. } else {
  284. m_Last->m_Next = new_obj;
  285. new_obj->m_Prev = m_Last;
  286. }
  287. m_Last = new_obj;
  288. return ;
  289. }
  290. //////////////////////////////////////////////////////////////////////////
  291. // Unlink
  292. //////////////////////////////////////////////////////////////////////////
  293. inline void
  294. FloodfillBoxClass::Unlink (void)
  295. {
  296. Remove ();
  297. if (m_Neighbors[DIR_FORWARD] != NULL) {
  298. m_Neighbors[DIR_FORWARD]->Set_Neighbor (DIR_BACKWARD, NULL, false);
  299. }
  300. if (m_Neighbors[DIR_BACKWARD] != NULL) {
  301. m_Neighbors[DIR_BACKWARD]->Set_Neighbor (DIR_FORWARD, NULL, false);
  302. }
  303. if (m_Neighbors[DIR_LEFT] != NULL) {
  304. m_Neighbors[DIR_LEFT]->Set_Neighbor (DIR_RIGHT, NULL, false);
  305. }
  306. if (m_Neighbors[DIR_RIGHT] != NULL) {
  307. m_Neighbors[DIR_RIGHT]->Set_Neighbor (DIR_LEFT, NULL, false);
  308. }
  309. return ;
  310. }
  311. //////////////////////////////////////////////////////////////////////////
  312. // Is_Edge
  313. //////////////////////////////////////////////////////////////////////////
  314. inline bool
  315. FloodfillBoxClass::Is_Edge (void)
  316. {
  317. bool retval = false;
  318. if (Peek_Neighbor (DIR_FORWARD) == NULL ||
  319. Peek_Neighbor (DIR_BACKWARD) == NULL ||
  320. Peek_Neighbor (DIR_LEFT) == NULL ||
  321. Peek_Neighbor (DIR_RIGHT) == NULL) {
  322. retval = true;
  323. }
  324. return retval;
  325. }
  326. //////////////////////////////////////////////////////////////////////////
  327. // Are_Neighbors_Processed
  328. //////////////////////////////////////////////////////////////////////////
  329. inline bool
  330. FloodfillBoxClass::Are_Neighbors_Processed (void)
  331. {
  332. bool retval = true;
  333. for (int index = 0; (index < 4) && retval; index ++) {
  334. if ((m_Neighbors[0] != NULL) && m_Neighbors[0]->Needs_Processing ()) {
  335. retval = false;
  336. }
  337. }
  338. return retval;
  339. }
  340. //////////////////////////////////////////////////////////////////////////
  341. // Set_Neighbor
  342. //////////////////////////////////////////////////////////////////////////
  343. inline void
  344. FloodfillBoxClass::Set_Neighbor (PATHFIND_DIR dir, FloodfillBoxClass *obj, bool traversible)
  345. {
  346. m_Neighbors[dir] = obj;
  347. Set_Traversible (dir, traversible);
  348. return ;
  349. }
  350. //////////////////////////////////////////////////////////////////////////
  351. // Peek_Neighbor
  352. //////////////////////////////////////////////////////////////////////////
  353. inline FloodfillBoxClass *
  354. FloodfillBoxClass::Peek_Neighbor (PATHFIND_DIR dir, bool only_traversible)
  355. {
  356. FloodfillBoxClass *neighbor = NULL;
  357. if ((only_traversible == false) || Get_Traversible (dir)) {
  358. neighbor = m_Neighbors[dir];
  359. }
  360. return neighbor;
  361. }
  362. //////////////////////////////////////////////////////////////////////////
  363. // Set_Flag
  364. //////////////////////////////////////////////////////////////////////////
  365. inline void
  366. FloodfillBoxClass::Set_Flag (uint8 flag, bool value)
  367. {
  368. m_Flags &= ~flag;
  369. if (value) {
  370. m_Flags |= flag;
  371. }
  372. return ;
  373. }
  374. //////////////////////////////////////////////////////////////////////////
  375. // Set_Traversible
  376. //////////////////////////////////////////////////////////////////////////
  377. inline void
  378. FloodfillBoxClass::Set_Traversible (PATHFIND_DIR dir, bool onoff)
  379. {
  380. if (onoff) {
  381. m_DirectionInfo |= (1 << dir);
  382. } else {
  383. m_DirectionInfo &= ~(1 << dir);
  384. }
  385. return ;
  386. }
  387. //////////////////////////////////////////////////////////////////////////
  388. // Get_Traversible
  389. //////////////////////////////////////////////////////////////////////////
  390. inline bool
  391. FloodfillBoxClass::Get_Traversible (PATHFIND_DIR dir)
  392. {
  393. int bit = (1 << dir);
  394. return (m_DirectionInfo & bit) == bit;
  395. }
  396. //////////////////////////////////////////////////////////////////////////
  397. // Part_Of_Portal
  398. //////////////////////////////////////////////////////////////////////////
  399. inline void
  400. FloodfillBoxClass::Part_Of_Portal (PATHFIND_DIR dir, bool onoff)
  401. {
  402. if (onoff) {
  403. m_DirectionInfo |= (1 << (dir + 4));
  404. } else {
  405. m_DirectionInfo &= ~(1 << (dir + 4));
  406. }
  407. return ;
  408. }
  409. //////////////////////////////////////////////////////////////////////////
  410. // Part_Of_Portal
  411. //////////////////////////////////////////////////////////////////////////
  412. inline bool
  413. FloodfillBoxClass::Part_Of_Portal (PATHFIND_DIR dir)
  414. {
  415. int bit = (1 << (dir + 4));
  416. return (m_DirectionInfo & bit) == bit;
  417. }
  418. #endif //__FLOODFILLBOX_H