gridcull.h 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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 : WWMath *
  23. * *
  24. * $Archive:: /Commando/Code/wwmath/gridcull.h $*
  25. * *
  26. * Author:: Greg Hjelstrom *
  27. * *
  28. * $Modtime:: 5/10/01 10:42a $*
  29. * *
  30. * $Revision:: 14 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * GridCullSystemClass::clamp_indices_to_grid -- constrains indices to be a valid location *
  35. * GridCullSystemClass::map_point_to_cell -- determines which cell the point is in *
  36. * GridCullSystemClass::map_point_to_address -- determines the address of a point in the gri *
  37. * GridCullSystemClass::map_indices_to_address -- computes the address for given index tripl *
  38. * GridCullSystemClass::total_cell_count -- returns the total number of cells in the grid *
  39. * GridCullSystemClass::compute_box -- computes the bounding box for a grid cell *
  40. * GridCullSystemClass::compute_box -- computes bounding box for a range of grid cells *
  41. * GridCullSystemClass::init_volume -- inits volume to contain the given range *
  42. * GridCullSystemClass::init_volume -- inits volume to contain the given line segment *
  43. * GridCullSystemClass::init_volume -- inits volume to contain the given box *
  44. * GridCullSystemClass::init_volume -- inits volume to contain the given oriented box *
  45. * GridCullSystemClass::init_volume -- inits volume to contain the given frustum *
  46. * GridCullSystemClass::VolumeStruct::VolumeStruct -- constructor *
  47. * GridCullSystemClass::VolumeStruct::VolumeStruct -- constructor *
  48. * GridCullSystemClass::VolumeStruct::Is_Leaf -- check if volume is a leaf *
  49. * GridCullSystemClass::VolumeStruct::Is_Empty -- check if volume is empty (or invalid) *
  50. * GridCullSystemClass::VolumeStruct::Split -- split this volume *
  51. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  52. #if defined(_MSC_VER)
  53. #pragma once
  54. #endif
  55. #include "cullsys.h"
  56. #include "mempool.h"
  57. #include "frustum.h"
  58. #include "aabox.h"
  59. #include "lineseg.h"
  60. #include "obbox.h"
  61. #include <string.h>
  62. class ChunkLoadClass;
  63. class ChunkSaveClass;
  64. /*
  65. ** GridCullSystemClass
  66. ** This is a culling system designed for dynamic objects (objects which are moving or
  67. ** changing bounding box size). It features O(1) insertion as opposed to
  68. ** the AABTree, QuadTree, or Octree insertion times which are O(logn). It's disadvantages
  69. ** compared to the above mentioned systems are that it must uniformly divide space. The
  70. ** AABTree conforms to the geometry placed in it and can therefore cull things more
  71. ** efficiently. In actual use, this system is like an AAB-tree which is uniformly subdivided,
  72. ** its just that we can jump straight to the leaves of the tree for insertion...
  73. **
  74. ** The bounding volume for each grid cell is considered to be the volume of the cell, expanded
  75. ** by the maximum object size. Inserting an object into the grid is a matter of determining
  76. ** which cell its center point is in. Objects which are larger than the maximum size are
  77. ** allowed but they are simply put into a linked list which is iterated with each call to
  78. ** the culling system (linearly culled rather than logarithmic...)
  79. */
  80. class GridCullSystemClass : public CullSystemClass
  81. {
  82. public:
  83. GridCullSystemClass(void);
  84. ~GridCullSystemClass(void);
  85. virtual void Collect_Objects(const Vector3 & point);
  86. virtual void Collect_Objects(const AABoxClass & box);
  87. virtual void Collect_Objects(const OBBoxClass & box);
  88. virtual void Collect_Objects(const FrustumClass & frustum);
  89. virtual void Re_Partition(const Vector3 & min,const Vector3 & max,float objdim);
  90. virtual void Update_Culling(CullableClass * obj);
  91. virtual void Load(ChunkLoadClass & cload);
  92. virtual void Save(ChunkSaveClass & csave);
  93. virtual int Get_Object_Count (void) const { return ObjCount; }
  94. /*
  95. ** Statistics
  96. */
  97. struct StatsStruct
  98. {
  99. int NodeCount;
  100. int NodesAccepted;
  101. int NodesTriviallyAccepted;
  102. int NodesRejected;
  103. };
  104. void Reset_Statistics(void);
  105. const StatsStruct & Get_Statistics(void);
  106. void Get_Min_Cell_Size (Vector3 &size) const { size = MinCellSize; }
  107. void Set_Min_Cell_Size (const Vector3 &size) { MinCellSize = size; }
  108. int Get_Termination_Count (void) const { return TerminationCellCount; }
  109. void Set_Termination_Count (int count) { TerminationCellCount = count; }
  110. protected:
  111. void Collect_And_Unlink_All(void);
  112. void Add_Object_Internal(CullableClass * obj);
  113. void Remove_Object_Internal(CullableClass * obj);
  114. enum
  115. {
  116. TERMINATION_CELL_COUNT = 16384, // algorithm terminates if we ever have more than this many cells.
  117. UNGRIDDED_ADDRESS = 0xFFFFFFFF // address given to objs that didn't fit in grid
  118. };
  119. // Constants which control the division of space:
  120. Vector3 MinCellSize; // min dimensions for a cell (don't go below this...)
  121. float MaxObjExtent; // max extent/radius (objects bigger than this are just put in a list)
  122. int TerminationCellCount;
  123. // Constants that define the division of space
  124. Vector3 Origin;
  125. Vector3 CellDim;
  126. Vector3 OOCellDim;
  127. int CellCount[3];
  128. // 3D array of pointers to objects in each cell
  129. CullableClass ** Cells;
  130. // list of objs that were outside or too big for the grid.
  131. CullableClass * NoGridList;
  132. // number of objects in the system
  133. int ObjCount;
  134. // statistics
  135. StatsStruct Stats;
  136. // Structure used to define a volume in the grid. The volume spans from the cell indexed
  137. // by Min[0],Min[1],Min[2] to the cell indexed by Max[0]-1,Max[1]-1,Max[2]-1.
  138. struct VolumeStruct
  139. {
  140. VolumeStruct(void);
  141. VolumeStruct(int i0,int j0,int k0,int i1,int j1,int k1);
  142. bool Is_Leaf(void) const;
  143. bool Is_Empty(void) const;
  144. void Split(VolumeStruct & v0,VolumeStruct & v1) const;
  145. int Min[3];
  146. int Max[3];
  147. };
  148. void link_object(CullableClass * obj);
  149. void link_object(CullableClass * obj,int address);
  150. void unlink_object(CullableClass * obj);
  151. void link_object_to_list(CullableClass ** head,CullableClass * obj);
  152. void unlink_object_from_list(CullableClass ** head,CullableClass * obj);
  153. bool map_point_to_cell(const Vector3 & pt,int & set_i,int & set_j,int & set_k);
  154. bool map_point_to_address(const Vector3 & pt,int & set_address);
  155. WWINLINE int map_indices_to_address(int i,int j,int k);
  156. void clamp_indices_to_grid(int * i,int * j,int * k);
  157. int total_cell_count(void);
  158. void compute_box(int i,int j,int k,AABoxClass * set_box);
  159. void compute_box(const VolumeStruct & area, AABoxClass * set_box);
  160. void init_volume(const Vector3 & bound_min,const Vector3 & bound_max,VolumeStruct * set_volume);
  161. void init_volume(const Vector3 & point,VolumeStruct * set_volume);
  162. void init_volume(const LineSegClass & line,VolumeStruct * set_volume);
  163. void init_volume(const AABoxClass & box,VolumeStruct * set_volume);
  164. void init_volume(const OBBoxClass & box,VolumeStruct * set_volume);
  165. void init_volume(const FrustumClass & frustum,VolumeStruct * set_volume);
  166. void collect_objects_in_leaf(const Vector3 & point,CullableClass * head);
  167. void collect_objects_in_leaf(const AABoxClass & aabox,CullableClass * head);
  168. void collect_objects_in_leaf(const OBBoxClass & obbox,CullableClass * head);
  169. void collect_objects_in_leaf(const FrustumClass & frustum,CullableClass * head);
  170. };
  171. /*
  172. ** Macros for gathering statistics. Placed here in the header file so that
  173. ** derived classes can use them as well.
  174. */
  175. #ifdef WWDEBUG
  176. #define GRIDCULL_NODE_ACCEPTED Stats.NodesAccepted ++;
  177. #define GRIDCULL_NODE_TRIVIALLY_ACCEPTED Stats.NodesTriviallyAccepted ++;
  178. #define GRIDCULL_NODE_REJECTED Stats.NodesRejected ++;
  179. #else
  180. #define GRIDCULL_NODE_ACCEPTED
  181. #define GRIDCULL_NODE_TRIVIALLY_ACCEPTED
  182. #define GRIDCULL_NODE_REJECTED
  183. #endif
  184. /*
  185. ** TypedGridCullSystemClass
  186. ** This class simply enforces that a certain type of object is inserted into the grid cull system.
  187. ** It exposes the add, remove, and collection iterating functions and is intended to be the class
  188. ** actually used by the end user.
  189. */
  190. template <class T> class TypedGridCullSystemClass : public GridCullSystemClass
  191. {
  192. public:
  193. virtual void Add_Object(T * obj) { Add_Object_Internal(obj); }
  194. virtual void Remove_Object(T * obj) { Remove_Object_Internal(obj); }
  195. T * Get_First_Collected_Object(void) { return (T*)Get_First_Collected_Object_Internal(); }
  196. T * Get_Next_Collected_Object(T * obj) { return (T*)Get_Next_Collected_Object_Internal(obj); }
  197. };
  198. /*
  199. ** GridLinkClass
  200. ** This structure is used to link cullable objects into a Grid culling system
  201. ** This class is should only be used by classes which derive from GridCullSystemClass
  202. ** not normal users.
  203. */
  204. class GridLinkClass : public CullLinkClass, public AutoPoolClass<GridLinkClass,256>
  205. {
  206. public:
  207. GridLinkClass(GridCullSystemClass * system);
  208. virtual ~GridLinkClass(void);
  209. int GridAddress; // address in the grid.
  210. CullableClass * Prev; // prev object in this cell
  211. CullableClass * Next; // next object in this cell
  212. };
  213. /*
  214. ** GridListIterator
  215. ** This is just a simple iterator that contains the code for traversing the
  216. ** list of objects either in a cell in the grid or in the NoGridList...
  217. ** This class should only be used by classes which derive from GridCullSystemClass
  218. ** not normal users.
  219. */
  220. class GridListIterator
  221. {
  222. public:
  223. GridListIterator(CullableClass * head) { First(head); }
  224. void First(CullableClass * head) { Head = head; CurObj = head; }
  225. void First(void) { CurObj = Head; }
  226. void Next(void) { if (CurObj) { CurObj = ((GridLinkClass *)CurObj->Get_Cull_Link())->Next; } }
  227. void Prev(void) { if (CurObj) { CurObj = ((GridLinkClass *)CurObj->Get_Cull_Link())->Prev; } }
  228. bool Is_Done(void) { return (CurObj == NULL); }
  229. CullableClass * Get_Obj(void) { if (CurObj) { CurObj->Add_Ref(); } return CurObj; }
  230. CullableClass * Peek_Obj(void) { return CurObj; }
  231. private:
  232. CullableClass * Head; // head of the list we're working in
  233. CullableClass * CurObj; // node we're currently at.
  234. };
  235. /***********************************************************************************************
  236. * GridCullSystemClass::clamp_indices_to_grid -- constrains indices to be a valid location *
  237. * *
  238. * INPUT: *
  239. * *
  240. * OUTPUT: *
  241. * *
  242. * WARNINGS: *
  243. * *
  244. * HISTORY: *
  245. * 3/30/2000 gth : Created. *
  246. *=============================================================================================*/
  247. WWINLINE void GridCullSystemClass::clamp_indices_to_grid(int * i,int * j,int * k)
  248. {
  249. if (*i < 0) *i = 0;
  250. if (*i >= CellCount[0]) *i = CellCount[0] - 1;
  251. if (*j < 0) *j = 0;
  252. if (*j >= CellCount[1]) *j = CellCount[1] - 1;
  253. if (*k < 0) *k = 0;
  254. if (*k >= CellCount[2]) *k = CellCount[2] - 1;
  255. }
  256. /***********************************************************************************************
  257. * GridCullSystemClass::map_point_to_cell -- determines which cell the point is in *
  258. * *
  259. * INPUT: *
  260. * *
  261. * OUTPUT: *
  262. * *
  263. * WARNINGS: *
  264. * *
  265. * HISTORY: *
  266. * 3/30/2000 gth : Created. *
  267. *=============================================================================================*/
  268. WWINLINE bool GridCullSystemClass::map_point_to_cell(const Vector3 & pt,int & set_i,int & set_j,int & set_k)
  269. {
  270. Vector3 dp = pt - Origin;
  271. set_i = floor(dp.X * OOCellDim.X);
  272. set_j = floor(dp.Y * OOCellDim.Y);
  273. set_k = floor(dp.Z * OOCellDim.Z);
  274. if ( (set_i >= 0) && (set_j >= 0) && (set_k >= 0) &&
  275. (set_i < CellCount[0]) && (set_j < CellCount[1]) && (set_k < CellCount[2]) )
  276. {
  277. return true;
  278. }
  279. return false;
  280. }
  281. /***********************************************************************************************
  282. * GridCullSystemClass::map_point_to_address -- determines the address of a point in the grid *
  283. * *
  284. * INPUT: *
  285. * *
  286. * OUTPUT: *
  287. * *
  288. * WARNINGS: *
  289. * *
  290. * HISTORY: *
  291. * 3/30/2000 gth : Created. *
  292. *=============================================================================================*/
  293. WWINLINE bool GridCullSystemClass::map_point_to_address(const Vector3 & pt,int &set_address)
  294. {
  295. int i,j,k;
  296. bool res = map_point_to_cell(pt,i,j,k);
  297. if (res) {
  298. set_address = map_indices_to_address(i,j,k);
  299. return true;
  300. } else {
  301. set_address = UNGRIDDED_ADDRESS;
  302. return false;
  303. }
  304. }
  305. /***********************************************************************************************
  306. * GridCullSystemClass::map_indices_to_address -- computes the address for given index triplet *
  307. * *
  308. * INPUT: *
  309. * *
  310. * OUTPUT: *
  311. * *
  312. * WARNINGS: *
  313. * *
  314. * HISTORY: *
  315. * 3/30/2000 gth : Created. *
  316. *=============================================================================================*/
  317. WWINLINE int GridCullSystemClass::map_indices_to_address(int i,int j,int k)
  318. {
  319. return i + j*CellCount[0] + k*CellCount[0]*CellCount[1];
  320. }
  321. /***********************************************************************************************
  322. * GridCullSystemClass::total_cell_count -- returns the total number of cells in the grid *
  323. * *
  324. * INPUT: *
  325. * *
  326. * OUTPUT: *
  327. * *
  328. * WARNINGS: *
  329. * *
  330. * HISTORY: *
  331. * 3/30/2000 gth : Created. *
  332. *=============================================================================================*/
  333. WWINLINE int GridCullSystemClass::total_cell_count(void)
  334. {
  335. return CellCount[0] * CellCount[1] * CellCount[2];
  336. }
  337. /***********************************************************************************************
  338. * GridCullSystemClass::compute_box -- computes the bounding box for a grid cell *
  339. * *
  340. * INPUT: *
  341. * *
  342. * OUTPUT: *
  343. * *
  344. * WARNINGS: *
  345. * *
  346. * HISTORY: *
  347. * 3/30/2000 gth : Created. *
  348. *=============================================================================================*/
  349. WWINLINE void GridCullSystemClass::compute_box(int i,int j,int k,AABoxClass * set_box)
  350. {
  351. WWASSERT(set_box != NULL);
  352. WWASSERT((i >= 0) && (j >= 0) && (k >= 0));
  353. WWASSERT((i < CellCount[0]) && (j < CellCount[1]) && (k < CellCount[2]));
  354. Vector3 min,max;
  355. min.X = Origin.X + i * CellDim.X - MaxObjExtent;
  356. min.Y = Origin.Y + j * CellDim.Y - MaxObjExtent;
  357. min.Z = Origin.Z + k * CellDim.Z - MaxObjExtent;
  358. max.X = min.X + CellDim.X + 2.0f*MaxObjExtent;
  359. max.Y = min.Y + CellDim.Y + 2.0f*MaxObjExtent;
  360. max.Z = min.Z + CellDim.Z + 2.0f*MaxObjExtent;
  361. set_box->Init((min+max)*0.5f, (min-max)*0.5f);
  362. }
  363. /***********************************************************************************************
  364. * GridCullSystemClass::compute_box -- computes bounding box for a range of grid cells *
  365. * *
  366. * INPUT: *
  367. * *
  368. * OUTPUT: *
  369. * *
  370. * WARNINGS: *
  371. * *
  372. * HISTORY: *
  373. * 3/30/2000 gth : Created. *
  374. *=============================================================================================*/
  375. WWINLINE void GridCullSystemClass::compute_box(const GridCullSystemClass::VolumeStruct & vol, AABoxClass * set_box)
  376. {
  377. WWASSERT(set_box != NULL);
  378. WWASSERT((vol.Min[0] >= 0) && (vol.Min[1] >= 0) && (vol.Min[2] >= 0));
  379. WWASSERT((vol.Max[0] <= CellCount[0]) && (vol.Max[1] <= CellCount[1]) && (vol.Max[2] <= CellCount[2]));
  380. Vector3 min,max;
  381. min.X = Origin.X + vol.Min[0] * CellDim.X - MaxObjExtent;
  382. min.Y = Origin.Y + vol.Min[1] * CellDim.Y - MaxObjExtent;
  383. min.Z = Origin.Z + vol.Min[2] * CellDim.Z - MaxObjExtent;
  384. max.X = Origin.X + vol.Max[0] * CellDim.X + MaxObjExtent;
  385. max.Y = Origin.Y + vol.Max[1] * CellDim.Y + MaxObjExtent;
  386. max.Z = Origin.Z + vol.Max[2] * CellDim.Z + MaxObjExtent;
  387. Vector3 center((max.X+min.X)*0.5f,(max.Y+min.Y)*0.5f,(max.Z+min.Z)*0.5f);
  388. Vector3 extent((max.X-min.X)*0.5f,(max.Y-min.Y)*0.5f,(max.Z-min.Z)*0.5f);
  389. set_box->Init(center,extent);
  390. }
  391. /***********************************************************************************************
  392. * GridCullSystemClass::init_volume -- inits volume to contain the given range *
  393. * *
  394. * INPUT: *
  395. * *
  396. * OUTPUT: *
  397. * *
  398. * WARNINGS: *
  399. * *
  400. * HISTORY: *
  401. * 3/30/2000 gth : Created. *
  402. *=============================================================================================*/
  403. WWINLINE void GridCullSystemClass::init_volume
  404. (
  405. const Vector3 & bound_min,
  406. const Vector3 & bound_max,
  407. VolumeStruct * set_vol
  408. )
  409. {
  410. // expand the box by the maximum size of any object
  411. Vector3 grid_min = bound_min;
  412. grid_min.X -= MaxObjExtent;
  413. grid_min.Y -= MaxObjExtent;
  414. grid_min.Z -= MaxObjExtent;
  415. Vector3 grid_max = bound_max;
  416. grid_max.X += MaxObjExtent;
  417. grid_max.Y += MaxObjExtent;
  418. grid_max.Z += MaxObjExtent;
  419. // now compute the grid coordinates of the corners of the box
  420. GridCullSystemClass::map_point_to_cell(grid_min,set_vol->Min[0],set_vol->Min[1],set_vol->Min[2]);
  421. GridCullSystemClass::map_point_to_cell(grid_max,set_vol->Max[0],set_vol->Max[1],set_vol->Max[2]);
  422. // now clamp the volume to the actual grid
  423. clamp_indices_to_grid(&(set_vol->Min[0]),&(set_vol->Min[1]),&(set_vol->Min[2]));
  424. clamp_indices_to_grid(&(set_vol->Max[0]),&(set_vol->Max[1]),&(set_vol->Max[2]));
  425. // increment the outer edge of the box due to the way we traverse the grid...
  426. set_vol->Max[0] ++;
  427. set_vol->Max[1] ++;
  428. set_vol->Max[2] ++;
  429. }
  430. /***********************************************************************************************
  431. * GridCullSystemClass::init_volume -- inits volume to contain the given line segment *
  432. * *
  433. * INPUT: *
  434. * *
  435. * OUTPUT: *
  436. * *
  437. * WARNINGS: *
  438. * *
  439. * HISTORY: *
  440. * 3/30/2000 gth : Created. *
  441. *=============================================================================================*/
  442. WWINLINE void GridCullSystemClass::init_volume(const LineSegClass & line,VolumeStruct * set_volume)
  443. {
  444. Vector3 min_pt,max_pt;
  445. min_pt.X = WWMath::Min(line.Get_P0().X,line.Get_P1().X);
  446. max_pt.X = WWMath::Max(line.Get_P0().X,line.Get_P1().X);
  447. min_pt.Y = WWMath::Min(line.Get_P0().Y,line.Get_P1().Y);
  448. max_pt.Y = WWMath::Max(line.Get_P0().Y,line.Get_P1().Y);
  449. min_pt.Z = WWMath::Min(line.Get_P0().Z,line.Get_P1().Z);
  450. max_pt.Z = WWMath::Max(line.Get_P0().Z,line.Get_P1().Z);
  451. init_volume(min_pt,max_pt,set_volume);
  452. }
  453. /***********************************************************************************************
  454. * GridCullSystemClass::init_volume -- inits volume to contain the given box *
  455. * *
  456. * INPUT: *
  457. * *
  458. * OUTPUT: *
  459. * *
  460. * WARNINGS: *
  461. * *
  462. * HISTORY: *
  463. * 3/30/2000 gth : Created. *
  464. *=============================================================================================*/
  465. WWINLINE void GridCullSystemClass::init_volume(const AABoxClass & box,VolumeStruct * set_volume)
  466. {
  467. init_volume(box.Center - box.Extent,box.Center + box.Extent,set_volume);
  468. }
  469. /***********************************************************************************************
  470. * GridCullSystemClass::init_volume -- inits volume to contain the given oriented box *
  471. * *
  472. * INPUT: *
  473. * *
  474. * OUTPUT: *
  475. * *
  476. * WARNINGS: *
  477. * *
  478. * HISTORY: *
  479. * 3/30/2000 gth : Created. *
  480. *=============================================================================================*/
  481. WWINLINE void GridCullSystemClass::init_volume(const OBBoxClass & box,VolumeStruct * set_volume)
  482. {
  483. Vector3 aaextent;
  484. box.Compute_Axis_Aligned_Extent(&aaextent);
  485. init_volume(box.Center - aaextent,box.Center + aaextent,set_volume);
  486. }
  487. /***********************************************************************************************
  488. * GridCullSystemClass::init_volume -- inits volume to contain the given frustum *
  489. * *
  490. * INPUT: *
  491. * *
  492. * OUTPUT: *
  493. * *
  494. * WARNINGS: *
  495. * *
  496. * HISTORY: *
  497. * 3/30/2000 gth : Created. *
  498. *=============================================================================================*/
  499. WWINLINE void GridCullSystemClass::init_volume(const FrustumClass & frustum,VolumeStruct * set_volume)
  500. {
  501. init_volume(frustum.Get_Bound_Min(),frustum.Get_Bound_Max(),set_volume);
  502. }
  503. /***********************************************************************************************
  504. * GridCullSystemClass::VolumeStruct::VolumeStruct -- constructor *
  505. * *
  506. * INPUT: *
  507. * *
  508. * OUTPUT: *
  509. * *
  510. * WARNINGS: *
  511. * *
  512. * HISTORY: *
  513. *=============================================================================================*/
  514. WWINLINE GridCullSystemClass::VolumeStruct::VolumeStruct(void)
  515. {
  516. }
  517. /***********************************************************************************************
  518. * GridCullSystemClass::VolumeStruct::VolumeStruct -- constructor *
  519. * *
  520. * INPUT: *
  521. * *
  522. * OUTPUT: *
  523. * *
  524. * WARNINGS: *
  525. * *
  526. * HISTORY: *
  527. * 3/30/2000 gth : Created. *
  528. *=============================================================================================*/
  529. WWINLINE GridCullSystemClass::VolumeStruct::VolumeStruct(int i0,int j0,int k0,int i1,int j1,int k1)
  530. {
  531. Min[0] = i0;
  532. Min[1] = j0;
  533. Min[2] = k0;
  534. Max[0] = i1;
  535. Max[1] = j1;
  536. Max[2] = k1;
  537. WWASSERT(Max[0] > Min[0]);
  538. WWASSERT(Max[1] > Min[1]);
  539. WWASSERT(Max[2] > Min[2]);
  540. }
  541. /***********************************************************************************************
  542. * GridCullSystemClass::VolumeStruct::Is_Leaf -- check if volume is a leaf *
  543. * *
  544. * INPUT: *
  545. * *
  546. * OUTPUT: *
  547. * *
  548. * WARNINGS: *
  549. * *
  550. * HISTORY: *
  551. * 3/30/2000 gth : Created. *
  552. *=============================================================================================*/
  553. WWINLINE bool GridCullSystemClass::VolumeStruct::Is_Leaf(void) const
  554. {
  555. return ((Max[0]-Min[0] == 1) && (Max[1]-Min[1] == 1) && (Max[2]-Min[2] == 1));
  556. }
  557. /***********************************************************************************************
  558. * GridCullSystemClass::VolumeStruct::Is_Empty -- check if volume is empty (or invalid) *
  559. * *
  560. * INPUT: *
  561. * *
  562. * OUTPUT: *
  563. * *
  564. * WARNINGS: *
  565. * *
  566. * HISTORY: *
  567. * 3/30/2000 gth : Created. *
  568. *=============================================================================================*/
  569. WWINLINE bool GridCullSystemClass::VolumeStruct::Is_Empty(void) const
  570. {
  571. return ((Max[0]-Min[0] <= 0) || (Max[1]-Min[1] <= 0) || (Max[2]-Min[2] <= 0));
  572. }
  573. /***********************************************************************************************
  574. * GridCullSystemClass::VolumeStruct::Split -- split this volume *
  575. * *
  576. * INPUT: *
  577. * *
  578. * OUTPUT: *
  579. * *
  580. * WARNINGS: *
  581. * *
  582. * HISTORY: *
  583. * 3/30/2000 gth : Created. *
  584. *=============================================================================================*/
  585. WWINLINE void GridCullSystemClass::VolumeStruct::Split(VolumeStruct & v0,VolumeStruct & v1) const
  586. {
  587. // find the longest dimension
  588. int split_axis = 0;
  589. int delta[3];
  590. delta[0] = Max[0] - Min[0];
  591. delta[1] = Max[1] - Min[1];
  592. delta[2] = Max[2] - Min[2];
  593. if (delta[1] > delta[split_axis]) split_axis = 1;
  594. if (delta[2] > delta[split_axis]) split_axis = 2;
  595. WWASSERT(delta[split_axis] > 0);
  596. // split the volume perpendicularly to that dimension
  597. memcpy(&v0,this,sizeof(VolumeStruct));
  598. memcpy(&v1,this,sizeof(VolumeStruct));
  599. v0.Max[split_axis] = v1.Min[split_axis] = Min[split_axis] + (delta[split_axis] >> 1);
  600. }