aabtreebuilder.cpp 43 KB

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