aabtreebuilder.cpp 41 KB

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