aabtreebuilder.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930
  1. /*
  2. ** Command & Conquer Generals(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 : WW3D *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/aabtreebuilder.cpp $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * $Author:: Greg_h $*
  29. * *
  30. * $Modtime:: 1/08/01 10:04a $*
  31. * *
  32. * $Revision:: 1 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * AABTreeBuilderClass::AABTreeBuilderClass -- Constructor *
  37. * AABTreeBuilderClass::~AABTreeBuilderClass -- Destructor *
  38. * AABTreeBuilderClass::Reset -- reset the builder, delete all arrays *
  39. * AABTreeBuilderClass::Build_AABTree -- Build an AABTree for the given mesh. *
  40. * AABTreeBuilderClass::Build_Tree -- recursivly builds the culling tree *
  41. * AABTreeBuilderClass::Select_Splitting_Plane -- select a partition for the given polys *
  42. * AABTreeBuilderClass::Compute_Plane_Score -- evaluate the suitability of a partition plane *
  43. * AABTreeBuilderClass::Which_Side -- which side of a plane is the given poly *
  44. * AABTreeBuilderClass::Split_Polys -- partition the polys with a plane *
  45. * AABTreeBuilderClass::Compute_Bounding_Box -- compute bounding boxes for the cull nodes *
  46. * AABTreeBuilderClass::Assign_Index -- assign an array index to each node *
  47. * AABTreeBuilderClass::Node_Count -- Count the nodes in the tree *
  48. * AABTreeBuilderClass::Poly_Count -- returns number of polys *
  49. * AABTreeBuilderClass::Node_Count_Recursive -- internal implementation of Node_Count *
  50. * AABTreeBuilderClass::Submit_Tree -- install nodes into an AABTreeClass *
  51. * AABTreeBuilderClass::Submit_Tree_Recursive -- internal implementation of Submit_Tree *
  52. * AABTreeBuilderClass::Update_Min -- ensure given vector is < min of the poly *
  53. * AABTreeBuilderClass::Update_Max -- ensure given vector is > max of poly *
  54. * AABTreeBuilderClass::Update_Min_Max -- ensure given vector is in min max of poly *
  55. * AABTreeBuilderClass::Export -- Saves this AABTree into a W3D chunk *
  56. * AABTreeBuilderClass::Build_W3D_AABTree_Recursive -- Build array of indices and W3dMeshAAB *
  57. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  58. #include "aabtreebuilder.h"
  59. #include "chunkio.h"
  60. #include "w3d_file.h"
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <assert.h>
  64. #define WWASSERT assert // can't use WWASSERT because we use this module in the MAX plugin...
  65. const float COINCIDENCE_EPSILON = 0.001f;
  66. /***********************************************************************************************
  67. * AABTreeBuilderClass::AABTreeBuilderClass -- Constructor *
  68. * *
  69. * INPUT: *
  70. * *
  71. * OUTPUT: *
  72. * *
  73. * WARNINGS: *
  74. * *
  75. * HISTORY: *
  76. *=============================================================================================*/
  77. AABTreeBuilderClass::AABTreeBuilderClass(void) :
  78. Root(NULL),
  79. CurPolyIndex(0),
  80. PolyCount(0),
  81. Polys(NULL),
  82. VertCount(0),
  83. Verts(NULL)
  84. {
  85. }
  86. /***********************************************************************************************
  87. * AABTreeBuilderClass::~AABTreeBuilderClass -- Destructor *
  88. * *
  89. * INPUT: *
  90. * *
  91. * OUTPUT: *
  92. * *
  93. * WARNINGS: *
  94. * *
  95. * HISTORY: *
  96. * 5/19/2000 gth : Created. *
  97. *=============================================================================================*/
  98. AABTreeBuilderClass::~AABTreeBuilderClass(void)
  99. {
  100. Reset();
  101. }
  102. /***********************************************************************************************
  103. * AABTreeBuilderClass::Reset -- reset the builder, delete all arrays *
  104. * *
  105. * INPUT: *
  106. * *
  107. * OUTPUT: *
  108. * *
  109. * WARNINGS: *
  110. * *
  111. * HISTORY: *
  112. * 5/19/2000 gth : Created. *
  113. *=============================================================================================*/
  114. void AABTreeBuilderClass::Reset(void)
  115. {
  116. if (Root) {
  117. delete Root; Root = NULL;
  118. }
  119. if (Verts != NULL) {
  120. delete[] Verts;
  121. Verts = NULL;
  122. }
  123. if (Polys != NULL) {
  124. delete[] Polys;
  125. Polys = NULL;
  126. }
  127. }
  128. /***********************************************************************************************
  129. * AABTreeBuilderClass::Build_AABTree -- Build an AABTree for the given mesh. *
  130. * *
  131. * INPUT: *
  132. * *
  133. * OUTPUT: *
  134. * *
  135. * WARNINGS: *
  136. * *
  137. * HISTORY: *
  138. * 6/19/98 GTH : Created. *
  139. *=============================================================================================*/
  140. void AABTreeBuilderClass::Build_AABTree(int polycount,Vector3i * polys,int vertcount,Vector3 * verts)
  141. {
  142. WWASSERT(polycount > 0);
  143. WWASSERT(vertcount > 0);
  144. WWASSERT(polys != NULL);
  145. WWASSERT(verts != NULL);
  146. /*
  147. ** If we already have allocated data, release it
  148. */
  149. Reset();
  150. /*
  151. ** Copy the mesh data
  152. */
  153. VertCount = vertcount;
  154. PolyCount = polycount;
  155. Verts = W3DNEWARRAY Vector3[VertCount];
  156. Polys = W3DNEWARRAY Vector3i[PolyCount];
  157. for (int vi=0; vi<VertCount; vi++) {
  158. Verts[vi] = verts[vi];
  159. }
  160. for (int pi=0; pi<PolyCount; pi++) {
  161. Polys[pi] = polys[pi];
  162. }
  163. /*
  164. ** First, create a list of all of the poly indices
  165. */
  166. int * polyindices = W3DNEWARRAY int[PolyCount];
  167. for (int i=0; i<PolyCount; i++) {
  168. polyindices[i] = i;
  169. }
  170. /*
  171. ** Build the tree, note that the array of poly indices will be
  172. ** deleted by the Build_Tree function.
  173. */
  174. Root = W3DNEW CullNodeStruct;
  175. Build_Tree(Root,PolyCount,polyindices);
  176. polyindices = NULL;
  177. /*
  178. ** fill in the remaining information needed in the tree:
  179. ** for example: bounding boxes, index assignments
  180. */
  181. Compute_Bounding_Box(Root);
  182. Assign_Index(Root,0);
  183. }
  184. /***********************************************************************************************
  185. * AABTreeBuilderClass::Build_Tree -- recursivly builds the culling tree *
  186. * *
  187. * INPUT: *
  188. * *
  189. * OUTPUT: *
  190. * *
  191. * WARNINGS: *
  192. * *
  193. * HISTORY: *
  194. * 6/19/98 GTH : Created. *
  195. *=============================================================================================*/
  196. void AABTreeBuilderClass::Build_Tree(CullNodeStruct * node,int polycount,int * polyindices)
  197. {
  198. /*
  199. ** First, if there are only a few polys left, just terminate the tree
  200. */
  201. if (polycount <= MIN_POLYS_PER_NODE) {
  202. node->PolyCount = polycount;
  203. node->PolyIndices = polyindices;
  204. return;
  205. }
  206. /*
  207. ** Try to find a suitable partitioning plane.
  208. */
  209. SplitChoiceStruct sc;
  210. sc = Select_Splitting_Plane(polycount,polyindices);
  211. /*
  212. ** If the algorithm could not separate any polys, just install the polys
  213. ** in this node and terminate. TODO: explore how this happens.
  214. */
  215. if (sc.FrontCount + sc.BackCount != polycount) {
  216. node->PolyCount = polycount;
  217. node->PolyIndices = polyindices;
  218. return;
  219. }
  220. /*
  221. ** Decide whether to actually partition this node. If the partitioning
  222. ** will not gain us anything, just install the polys in this node and terminate
  223. ** the tree.
  224. */
  225. #if 0
  226. if (sc.Cost == MAX_COST) {
  227. node->PolyCount = polycount;
  228. node->PolyIndices = polyindices;
  229. return;
  230. }
  231. #endif
  232. /*
  233. ** Ok, split the polys
  234. */
  235. SplitArraysStruct arrays;
  236. Split_Polys(polycount,polyindices,sc,&arrays);
  237. /*
  238. ** Free the memory in use by the input tile-list
  239. */
  240. delete[] polyindices;
  241. /*
  242. ** Build a front tree if necessary. Remember that the Build function
  243. ** deletes the poly array.
  244. */
  245. if (arrays.FrontCount) {
  246. WWASSERT(arrays.FrontPolys != NULL);
  247. node->Front = W3DNEW CullNodeStruct;
  248. Build_Tree(node->Front,arrays.FrontCount,arrays.FrontPolys);
  249. arrays.FrontPolys = NULL;
  250. }
  251. /*
  252. ** Build a back tree if necessary. Remember that the build function
  253. ** deletes the tile array.
  254. */
  255. if (arrays.BackCount) {
  256. WWASSERT(arrays.BackPolys != NULL);
  257. node->Back = W3DNEW CullNodeStruct;
  258. Build_Tree(node->Back,arrays.BackCount,arrays.BackPolys);
  259. arrays.BackPolys = NULL;
  260. }
  261. }
  262. /***********************************************************************************************
  263. * AABTreeBuilderClass::Select_Splitting_Plane -- select a partition for the given polys *
  264. * *
  265. * INPUT: *
  266. * *
  267. * OUTPUT: *
  268. * *
  269. * WARNINGS: *
  270. * *
  271. * HISTORY: *
  272. * 6/19/98 GTH : Created. *
  273. *=============================================================================================*/
  274. AABTreeBuilderClass::SplitChoiceStruct
  275. AABTreeBuilderClass::Select_Splitting_Plane(int polycount,int * polyindices)
  276. {
  277. WWASSERT(polyindices != NULL);
  278. const int NUM_TRYS = 50;
  279. SplitChoiceStruct best_plane_stats;
  280. SplitChoiceStruct considered_plane_stats;
  281. /*
  282. ** Try putting axis-aligned planes through some random vertices
  283. */
  284. for (int trys = 0; trys < MIN(NUM_TRYS,polycount); trys++) {
  285. AAPlaneClass plane;
  286. /*
  287. ** Select a random poly and vertex index;
  288. */
  289. int poly_index = polyindices[rand() % polycount];
  290. int vert_index = rand() % 3;
  291. const Vector3i * polyverts = Polys + poly_index;
  292. const Vector3 * vert = Verts + (*polyverts)[vert_index];
  293. /*
  294. ** Select a random plane
  295. */
  296. switch(rand() % 3) {
  297. case 0: plane.Set(AAPlaneClass::XNORMAL,vert->X); break;
  298. case 1: plane.Set(AAPlaneClass::YNORMAL,vert->Y); break;
  299. case 2: plane.Set(AAPlaneClass::ZNORMAL,vert->Z); break;
  300. };
  301. /*
  302. ** Get the score for this plane
  303. */
  304. considered_plane_stats = Compute_Plane_Score(polycount,polyindices,plane);
  305. if (considered_plane_stats.Cost < best_plane_stats.Cost) {
  306. best_plane_stats = considered_plane_stats;
  307. }
  308. }
  309. return best_plane_stats;
  310. }
  311. /***********************************************************************************************
  312. * AABTreeBuilderClass::Compute_Plane_Score -- evaluate the suitability of a partition plane *
  313. * *
  314. * INPUT: *
  315. * *
  316. * OUTPUT: *
  317. * *
  318. * WARNINGS: *
  319. * *
  320. * HISTORY: *
  321. * 6/19/98 GTH : Created. *
  322. *=============================================================================================*/
  323. AABTreeBuilderClass::SplitChoiceStruct
  324. AABTreeBuilderClass::Compute_Plane_Score(int polycount,int * polyindices,const AAPlaneClass & plane)
  325. {
  326. /*
  327. ** The score of a splitting plane is based on the following factors:
  328. ** - the volumes of the resulting two children volumes,
  329. ** - the number of polys in each child volume
  330. */
  331. SplitChoiceStruct sc;
  332. sc.Plane = plane;
  333. for (int i=0; i<polycount; i++) {
  334. switch(Which_Side(plane,polyindices[i])) {
  335. case FRONT:
  336. case ON:
  337. case BOTH:
  338. {
  339. sc.FrontCount++;
  340. Update_Min_Max(polyindices[i],sc.FMin,sc.FMax );
  341. break;
  342. }
  343. case BACK:
  344. {
  345. sc.BackCount++;
  346. Update_Min_Max(polyindices[i],sc.BMin,sc.BMax );
  347. break;
  348. }
  349. }
  350. }
  351. /*
  352. ** Inflate the box a tiny amount so that we never
  353. ** get volumes of zero!
  354. */
  355. sc.BMin -= Vector3(WWMATH_EPSILON,WWMATH_EPSILON,WWMATH_EPSILON);
  356. sc.BMax += Vector3(WWMATH_EPSILON,WWMATH_EPSILON,WWMATH_EPSILON);
  357. /*
  358. ** Compute the cost.
  359. */
  360. float back_cost = (sc.BMax.X - sc.BMin.X) * (sc.BMax.Y - sc.BMin.Y) * (sc.BMax.Z - sc.BMin.Z) * sc.BackCount;
  361. float front_cost = (sc.FMax.X - sc.FMin.X) * (sc.FMax.Y - sc.FMin.Y) * (sc.FMax.Z - sc.FMin.Z) * sc.FrontCount;
  362. sc.Cost = front_cost + back_cost;
  363. if ((sc.FrontCount == 0) || (sc.BackCount == 0)) {
  364. sc.Cost = FLT_MAX;
  365. }
  366. return sc;
  367. }
  368. /***********************************************************************************************
  369. * AABTreeBuilderClass::Which_Side -- which side of a plane is the given poly *
  370. * *
  371. * INPUT: *
  372. * *
  373. * OUTPUT: *
  374. * *
  375. * WARNINGS: *
  376. * *
  377. * HISTORY: *
  378. * 6/19/98 GTH : Created. *
  379. *=============================================================================================*/
  380. AABTreeBuilderClass::OverlapType
  381. AABTreeBuilderClass::Which_Side(const AAPlaneClass & plane,int poly_index)
  382. {
  383. /*
  384. ** Check each vertex to see if it is in front, behind or on the plane
  385. */
  386. int mask = 0;
  387. for (int vi=0; vi<3; vi++) {
  388. const Vector3 & point = Verts[ Polys[poly_index][vi] ];
  389. float delta = point[plane.Normal] - plane.Dist;
  390. if (delta > COINCIDENCE_EPSILON) {
  391. mask |= POS;
  392. }
  393. if (delta < -COINCIDENCE_EPSILON) {
  394. mask |= NEG;
  395. }
  396. mask |= ON;
  397. }
  398. /*
  399. ** Now evaluate the status of all of the verts to determine whether the
  400. ** triangle is in front, behind, on or overlapping the plane
  401. */
  402. /*
  403. ** If all verts were ON the plane, the triangle is ON the plane
  404. */
  405. if (mask == ON) {
  406. return ON;
  407. }
  408. /*
  409. ** If all verts were POS or ON, the triangle is POS (IN_FRONT)
  410. */
  411. if ((mask & ~(POS | ON)) == 0) {
  412. return POS;
  413. }
  414. /*
  415. ** If all verts were NEG or ON, the triangle is NEG (BEHIND)
  416. */
  417. if ((mask & ~(NEG | ON)) == 0) {
  418. return NEG;
  419. }
  420. /*
  421. ** Otherwise, the triangle spans the plane
  422. */
  423. return BOTH;
  424. }
  425. /***********************************************************************************************
  426. * AABTreeBuilderClass::Split_Polys -- partition the polys with a plane *
  427. * *
  428. * INPUT: *
  429. * *
  430. * OUTPUT: *
  431. * *
  432. * WARNINGS: *
  433. * *
  434. * HISTORY: *
  435. * 6/19/98 GTH : Created. *
  436. *=============================================================================================*/
  437. void AABTreeBuilderClass::Split_Polys
  438. (
  439. int polycount,
  440. int * polyindices,
  441. const SplitChoiceStruct & sc,
  442. SplitArraysStruct * arrays
  443. )
  444. {
  445. /*
  446. ** Note that this routine arrays of polygons. The caller is then responsible for keeping
  447. ** track of the memory this routine allocates.
  448. */
  449. if (sc.FrontCount > 0) {
  450. arrays->FrontPolys = W3DNEWARRAY int[sc.FrontCount];
  451. }
  452. if (sc.BackCount > 0) {
  453. arrays->BackPolys = W3DNEWARRAY int[sc.BackCount];
  454. }
  455. arrays->FrontCount = 0;
  456. arrays->BackCount = 0;
  457. for (int i=0; i<polycount; i++) {
  458. switch(Which_Side(sc.Plane,polyindices[i])) {
  459. case FRONT:
  460. case ON:
  461. case BOTH:
  462. arrays->FrontPolys[arrays->FrontCount++] = polyindices[i];
  463. break;
  464. case BACK:
  465. arrays->BackPolys[arrays->BackCount++] = polyindices[i];
  466. break;
  467. }
  468. }
  469. /*
  470. ** when we are all done, the counts should match.
  471. */
  472. WWASSERT(arrays->FrontCount == sc.FrontCount);
  473. WWASSERT(arrays->BackCount == sc.BackCount);
  474. }
  475. /***********************************************************************************************
  476. * AABTreeBuilderClass::Compute_Bounding_Box -- compute bounding boxes for the cull nodes *
  477. * *
  478. * INPUT: *
  479. * *
  480. * OUTPUT: *
  481. * *
  482. * WARNINGS: *
  483. * *
  484. * HISTORY: *
  485. * 6/19/98 GTH : Created. *
  486. *=============================================================================================*/
  487. void AABTreeBuilderClass::Compute_Bounding_Box(CullNodeStruct * node)
  488. {
  489. /*
  490. ** compute bounding volumes of the children
  491. */
  492. if (node->Front) {
  493. Compute_Bounding_Box(node->Front);
  494. }
  495. if (node->Back) {
  496. Compute_Bounding_Box(node->Back);
  497. }
  498. /*
  499. ** compute bounding volume for the polys in this node
  500. */
  501. node->Min.Set(100000.0f,100000.0f,100000.0f);
  502. node->Max.Set(-100000.0f,-100000.0f,-100000.0f);
  503. for (int poly_index = 0; poly_index < node->PolyCount; poly_index++) {
  504. Update_Min_Max(node->PolyIndices[poly_index],node->Min,node->Max );
  505. }
  506. /*
  507. ** bound the polys in the front child node
  508. */
  509. if (node->Front) {
  510. if (node->Front->Min.X < node->Min.X) node->Min.X = node->Front->Min.X;
  511. if (node->Front->Max.X > node->Max.X) node->Max.X = node->Front->Max.X;
  512. if (node->Front->Min.Y < node->Min.Y) node->Min.Y = node->Front->Min.Y;
  513. if (node->Front->Max.Y > node->Max.Y) node->Max.Y = node->Front->Max.Y;
  514. if (node->Front->Min.Z < node->Min.Z) node->Min.Z = node->Front->Min.Z;
  515. if (node->Front->Max.Z > node->Max.Z) node->Max.Z = node->Front->Max.Z;
  516. }
  517. /*
  518. ** bound the polys in the back child node
  519. */
  520. if (node->Back) {
  521. if (node->Back->Min.X < node->Min.X) node->Min.X = node->Back->Min.X;
  522. if (node->Back->Max.X > node->Max.X) node->Max.X = node->Back->Max.X;
  523. if (node->Back->Min.Y < node->Min.Y) node->Min.Y = node->Back->Min.Y;
  524. if (node->Back->Max.Y > node->Max.Y) node->Max.Y = node->Back->Max.Y;
  525. if (node->Back->Min.Z < node->Min.Z) node->Min.Z = node->Back->Min.Z;
  526. if (node->Back->Max.Z > node->Max.Z) node->Max.Z = node->Back->Max.Z;
  527. }
  528. WWASSERT(node->Min.X != 100000.0f);
  529. WWASSERT(node->Min.Y != 100000.0f);
  530. WWASSERT(node->Min.Z != 100000.0f);
  531. WWASSERT(node->Max.X != -100000.0f);
  532. WWASSERT(node->Max.Y != -100000.0f);
  533. WWASSERT(node->Max.Z != -100000.0f);
  534. }
  535. /***********************************************************************************************
  536. * AABTreeBuilderClass::Assign_Index -- assign an array index to each node *
  537. * *
  538. * INPUT: *
  539. * *
  540. * OUTPUT: *
  541. * *
  542. * WARNINGS: *
  543. * *
  544. * HISTORY: *
  545. * 6/19/98 GTH : Created. *
  546. *=============================================================================================*/
  547. int AABTreeBuilderClass::Assign_Index(CullNodeStruct * node,int index)
  548. {
  549. /*
  550. ** This function is used to assign a sequential index to
  551. ** each node in the tree. The AABTree stores its nodes in
  552. ** an array so this index is used to determine which slot
  553. ** in the array to put each node into.
  554. */
  555. WWASSERT(node);
  556. node->Index = index;
  557. index++;
  558. if (node->Front) {
  559. index = Assign_Index(node->Front,index);
  560. }
  561. if (node->Back) {
  562. index = Assign_Index(node->Back,index);
  563. }
  564. return index;
  565. }
  566. /***********************************************************************************************
  567. * AABTreeBuilderClass::Node_Count -- Count the nodes in the tree *
  568. * *
  569. * INPUT: *
  570. * *
  571. * OUTPUT: *
  572. * *
  573. * WARNINGS: *
  574. * *
  575. * HISTORY: *
  576. * 6/19/98 GTH : Created. *
  577. *=============================================================================================*/
  578. int AABTreeBuilderClass::Node_Count(void)
  579. {
  580. if (Root) {
  581. return Node_Count_Recursive(Root,0);
  582. } else {
  583. return 0;
  584. }
  585. }
  586. /***********************************************************************************************
  587. * AABTreeBuilderClass::Poly_Count -- returns number of polys *
  588. * *
  589. * INPUT: *
  590. * *
  591. * OUTPUT: *
  592. * *
  593. * WARNINGS: *
  594. * *
  595. * HISTORY: *
  596. * 10/23/98 GTH : Created. *
  597. *=============================================================================================*/
  598. int AABTreeBuilderClass::Poly_Count(void)
  599. {
  600. return PolyCount;
  601. }
  602. /***********************************************************************************************
  603. * AABTreeBuilderClass::Node_Count_Recursive -- internal implementation of Node_Count *
  604. * *
  605. * INPUT: *
  606. * *
  607. * OUTPUT: *
  608. * *
  609. * WARNINGS: *
  610. * *
  611. * HISTORY: *
  612. * 6/19/98 GTH : Created. *
  613. *=============================================================================================*/
  614. int AABTreeBuilderClass::Node_Count_Recursive(CullNodeStruct * node,int curcount)
  615. {
  616. curcount++;
  617. if (node->Front) {
  618. curcount = Node_Count_Recursive(node->Front,curcount);
  619. }
  620. if (node->Back) {
  621. curcount = Node_Count_Recursive(node->Back,curcount);
  622. }
  623. return curcount;
  624. }
  625. /***********************************************************************************************
  626. * AABTreeBuilderClass::Update_Min -- ensure given vector is < min of the poly *
  627. * *
  628. * INPUT: *
  629. * *
  630. * OUTPUT: *
  631. * *
  632. * WARNINGS: *
  633. * *
  634. * HISTORY: *
  635. * 6/22/98 GTH : Created. *
  636. *=============================================================================================*/
  637. void AABTreeBuilderClass::Update_Min(int poly_index,Vector3 & min)
  638. {
  639. for (int vert_index = 0; vert_index < 3; vert_index++) {
  640. const Vector3i * polyverts = Polys + poly_index;
  641. const Vector3 * point = Verts + (*polyverts)[vert_index];
  642. if (point->X < min.X) min.X = point->X;
  643. if (point->Y < min.Y) min.Y = point->Y;
  644. if (point->Z < min.Z) min.Z = point->Z;
  645. }
  646. }
  647. /***********************************************************************************************
  648. * AABTreeBuilderClass::Update_Max -- ensure given vector is > max of poly *
  649. * *
  650. * INPUT: *
  651. * *
  652. * OUTPUT: *
  653. * *
  654. * WARNINGS: *
  655. * *
  656. * HISTORY: *
  657. * 6/22/98 GTH : Created. *
  658. *=============================================================================================*/
  659. void AABTreeBuilderClass::Update_Max(int poly_index,Vector3 & max)
  660. {
  661. for (int vert_index = 0; vert_index < 3; vert_index++) {
  662. const Vector3i * polyverts = Polys + poly_index;
  663. const Vector3 * point = Verts + (*polyverts)[vert_index];
  664. if (point->X > max.X) max.X = point->X;
  665. if (point->Y > max.Y) max.Y = point->Y;
  666. if (point->Z > max.Z) max.Z = point->Z;
  667. }
  668. }
  669. /***********************************************************************************************
  670. * AABTreeBuilderClass::Update_Min_Max -- ensure given vector is in min max of poly *
  671. * *
  672. * INPUT: *
  673. * *
  674. * OUTPUT: *
  675. * *
  676. * WARNINGS: *
  677. * *
  678. * HISTORY: *
  679. * 9/24/98 BMG : Created. *
  680. *=============================================================================================*/
  681. void AABTreeBuilderClass::Update_Min_Max(int poly_index, Vector3 & min, Vector3 & max)
  682. {
  683. for (int vert_index = 0; vert_index < 3; vert_index++) {
  684. const Vector3i * polyverts = Polys + poly_index;
  685. const Vector3 * point = Verts + (*polyverts)[vert_index];
  686. if (point->X < min.X) min.X = point->X;
  687. if (point->Y < min.Y) min.Y = point->Y;
  688. if (point->Z < min.Z) min.Z = point->Z;
  689. if (point->X > max.X) max.X = point->X;
  690. if (point->Y > max.Y) max.Y = point->Y;
  691. if (point->Z > max.Z) max.Z = point->Z;
  692. }
  693. }
  694. /***********************************************************************************************
  695. * AABTreeBuilderClass::Export -- Saves this AABTree into a W3D chunk *
  696. * *
  697. * This function will export the AABTree into a W3D chunk so that it can be loaded by its *
  698. * sister class "AABTreeClass" in the WW3D library. *
  699. * *
  700. * INPUT: *
  701. * *
  702. * OUTPUT: *
  703. * *
  704. * WARNINGS: *
  705. * *
  706. * HISTORY: *
  707. * 5/22/2000 gth : Created. *
  708. *=============================================================================================*/
  709. void AABTreeBuilderClass::Export(ChunkSaveClass & csave)
  710. {
  711. csave.Begin_Chunk(W3D_CHUNK_AABTREE);
  712. /*
  713. ** Pack the tree into an array of W3dMeshAABTreeNode's and polygon indices
  714. */
  715. W3dMeshAABTreeNode * nodes = W3DNEWARRAY W3dMeshAABTreeNode[Node_Count()];
  716. uint32 * poly_indices = W3DNEWARRAY uint32[Poly_Count()];
  717. int cur_node = 0;
  718. int cur_poly = 0;
  719. Build_W3D_AABTree_Recursive(Root,nodes,poly_indices,cur_node,cur_poly);
  720. /*
  721. ** Write out the header
  722. */
  723. csave.Begin_Chunk(W3D_CHUNK_AABTREE_HEADER);
  724. W3dMeshAABTreeHeader header;
  725. memset(&header,0,sizeof(header));
  726. header.NodeCount = Node_Count();
  727. header.PolyCount = Poly_Count();
  728. csave.Write(&header,sizeof(header));
  729. csave.End_Chunk();
  730. /*
  731. ** Write out the array of polygon indices
  732. */
  733. csave.Begin_Chunk(W3D_CHUNK_AABTREE_POLYINDICES);
  734. csave.Write(poly_indices,Poly_Count() * sizeof(uint32));
  735. csave.End_Chunk();
  736. /*
  737. ** Write out the array of nodes
  738. */
  739. csave.Begin_Chunk(W3D_CHUNK_AABTREE_NODES);
  740. for (int ni=0; ni<Node_Count(); ni++) {
  741. csave.Write(&(nodes[ni]),sizeof(W3dMeshAABTreeNode));
  742. }
  743. csave.End_Chunk();
  744. csave.End_Chunk(); // W3D_CHUNK_AABTREE done
  745. }
  746. /***********************************************************************************************
  747. * AABTreeBuilderClass::Build_W3D_AABTree_Recursive -- Build array of indices and W3dMeshAABTr *
  748. * *
  749. * INPUT: *
  750. * *
  751. * OUTPUT: *
  752. * *
  753. * WARNINGS: *
  754. * *
  755. * HISTORY: *
  756. * 5/22/2000 gth : Created. *
  757. *=============================================================================================*/
  758. void AABTreeBuilderClass::Build_W3D_AABTree_Recursive
  759. (
  760. AABTreeBuilderClass::CullNodeStruct * node,
  761. W3dMeshAABTreeNode * w3d_nodes,
  762. uint32 * poly_indices,
  763. int & cur_node,
  764. int & cur_poly
  765. )
  766. {
  767. /*
  768. ** Copy data from the builder's node into our node
  769. */
  770. W3dMeshAABTreeNode * newnode = &(w3d_nodes[node->Index]);
  771. newnode->Min.X = node->Min.X;
  772. newnode->Min.Y = node->Min.Y;
  773. newnode->Min.Z = node->Min.Z;
  774. newnode->Max.X = node->Max.X;
  775. newnode->Max.Y = node->Max.Y;
  776. newnode->Max.Z = node->Max.Z;
  777. /*
  778. ** If this is a non-leaf node, set up the child indices, otherwise set up the polygon indices
  779. */
  780. if (node->Front != NULL) {
  781. WWASSERT(node->Back != NULL); // if we have one child, we better have both!
  782. newnode->FrontOrPoly0 = node->Front->Index;
  783. newnode->BackOrPolyCount = node->Back->Index;
  784. } else {
  785. newnode->FrontOrPoly0 = cur_poly | 0x80000000;
  786. newnode->BackOrPolyCount = node->PolyCount;
  787. }
  788. /*
  789. ** Copy the polygon indices for this node into our array
  790. */
  791. for (int pcounter = 0; pcounter < node->PolyCount; pcounter++) {
  792. poly_indices[cur_poly++] = node->PolyIndices[pcounter];
  793. }
  794. /*
  795. ** Install the children
  796. */
  797. if (node->Front) {
  798. Build_W3D_AABTree_Recursive(node->Front,w3d_nodes,poly_indices,cur_node,cur_poly);
  799. }
  800. if (node->Back) {
  801. Build_W3D_AABTree_Recursive(node->Back,w3d_nodes,poly_indices,cur_node,cur_poly);
  802. }
  803. }