aabtree.cpp 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  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/aabtree.cpp $*
  25. * *
  26. * Author:: Greg Hjelstrom *
  27. * *
  28. * $Modtime:: 11/24/01 5:34p $*
  29. * *
  30. * $Revision:: 4 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * AABTreeClass::AABTreeClass -- Constructor *
  35. * AABTreeClass::AABTreeClass -- Constructor *
  36. * AABTreeClass::AABTreeClass -- copy constructor *
  37. * AABTreeClass::~AABTreeClass -- Destructor *
  38. * AABTreeClass::operator = -- assignment operator *
  39. * AABTreeClass::Reset -- reset this tree, releases all allocated resources *
  40. * AABTreeClass::Build_Tree_Recursive -- Initializes this tree from the given builder *
  41. * AABTreeClass::Set_Mesh -- set the mesh pointer *
  42. * AABTreeClass::Generate_APT -- Generate an active poly table for the mesh *
  43. * AABTreeClass::Generate_OBBox_APT_Recursive -- recursively generate the apt *
  44. * AABTreeClass::Cast_Ray_Recursive -- Internal implementation of Cast_Ray *
  45. * AABTreeClass::Cast_Semi_Infinite_Axis_Aligned_Ray_Recursive -- Internal implementation *
  46. * AABTreeClass::Cast_AABox_Recursive -- internal implementation of Cast_AABox *
  47. * AABTreeClass::Cast_OBBox_Recursive -- Internal implementation of Cast_OBBox *
  48. * AABTreeClass::Intersect_OBBox_Recursive -- internal implementation of Intersect_OBBox *
  49. * AABTreeClass::Cast_Ray_To_Polys -- cast the ray to polys in the given node *
  50. * AABTreeClass::Cast_Semi_Infinite_Axis_Aligned_Ray_To_Polys -- cast ray to polys in the nod*
  51. * AABTreeClass::Cast_AABox_To_Polys -- cast aabox to polys in the given node *
  52. * AABTreeClass::Cast_OBBox_To_Polys -- cast obbox to polys in the given node *
  53. * AABTreeClass::Intersect_OBBox_With_Polys -- Test polys for intersection *
  54. * AABTreeClass::Update_Bounding_Boxes_Recursive -- recompute the bounding boxes *
  55. * AABTreeClass::Update_Min_Max -- updates min and max given a polygon index *
  56. * AABTreeClass::Load_W3D -- Load a W3D description of an AABTree *
  57. * AABTreeClass::Read_Poly_Indices -- load the polygon index array *
  58. * AABTreeClass::Read_Nodes -- Load the node array *
  59. * AABTreeClass::Generate_APT -- generate an apt from a box and viewdir *
  60. * AABTreeClass::Generate_OBBox_APT_Recursive -- recurse, generate the apt for a box and vie *
  61. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  62. #include "aabtree.h"
  63. #include "aabtreebuilder.h"
  64. #include "wwdebug.h"
  65. #include "tri.h"
  66. #include "meshgeometry.h"
  67. #include "coltest.h"
  68. #include "inttest.h"
  69. #include "colmathinlines.h"
  70. #include "w3d_file.h"
  71. #include "chunkio.h"
  72. /***********************************************************************************************
  73. * AABTreeClass::AABTreeClass -- Constructor *
  74. * *
  75. * INPUT: *
  76. * *
  77. * OUTPUT: *
  78. * *
  79. * WARNINGS: *
  80. * *
  81. * HISTORY: *
  82. *=============================================================================================*/
  83. AABTreeClass::AABTreeClass(void) :
  84. NodeCount(0),
  85. Nodes(NULL),
  86. PolyCount(0),
  87. PolyIndices(NULL),
  88. Mesh(NULL)
  89. {
  90. }
  91. /***********************************************************************************************
  92. * AABTreeClass::AABTreeClass -- Constructor *
  93. * *
  94. * Builds an AABTree from the contents of an AABTreeBuilderClass. *
  95. * *
  96. * INPUT: *
  97. * *
  98. * OUTPUT: *
  99. * *
  100. * WARNINGS: *
  101. * *
  102. * HISTORY: *
  103. * 6/19/98 GTH : Created. *
  104. * 5/23/2000 gth : Created. *
  105. *=============================================================================================*/
  106. AABTreeClass::AABTreeClass(AABTreeBuilderClass * builder)
  107. {
  108. NodeCount = builder->Node_Count();
  109. Nodes = W3DNEWARRAY AABTreeClass::CullNodeStruct[NodeCount];
  110. PolyCount = builder->Poly_Count();
  111. PolyIndices = W3DNEWARRAY uint32[PolyCount];
  112. int curpolyindex = 0;
  113. Build_Tree_Recursive(builder->Root,curpolyindex);
  114. }
  115. /***********************************************************************************************
  116. * AABTreeClass::AABTreeClass -- copy constructor *
  117. * *
  118. * INPUT: *
  119. * *
  120. * OUTPUT: *
  121. * *
  122. * WARNINGS: *
  123. * *
  124. * HISTORY: *
  125. * 6/22/99 GTH : Created. *
  126. *=============================================================================================*/
  127. AABTreeClass::AABTreeClass(const AABTreeClass & that) :
  128. NodeCount(0),
  129. Nodes(NULL),
  130. PolyCount(0),
  131. PolyIndices(0),
  132. Mesh(NULL)
  133. {
  134. *this = that;
  135. }
  136. /***********************************************************************************************
  137. * AABTreeClass::~AABTreeClass -- Destructor *
  138. * *
  139. * INPUT: *
  140. * *
  141. * OUTPUT: *
  142. * *
  143. * WARNINGS: *
  144. * *
  145. * HISTORY: *
  146. * 6/19/98 GTH : Created. *
  147. *=============================================================================================*/
  148. AABTreeClass::~AABTreeClass(void)
  149. {
  150. Reset();
  151. }
  152. /***********************************************************************************************
  153. * AABTreeClass::operator = -- assignment operator *
  154. * *
  155. * INPUT: *
  156. * *
  157. * OUTPUT: *
  158. * *
  159. * WARNINGS: *
  160. * *
  161. * HISTORY: *
  162. * 6/22/99 GTH : Created. *
  163. *=============================================================================================*/
  164. AABTreeClass & AABTreeClass::operator = (const AABTreeClass & that)
  165. {
  166. Reset();
  167. NodeCount = that.NodeCount;
  168. if (NodeCount > 0) {
  169. Nodes = W3DNEWARRAY CullNodeStruct[NodeCount];
  170. memcpy(Nodes,that.Nodes,NodeCount * sizeof(CullNodeStruct));
  171. }
  172. PolyCount = that.PolyCount;
  173. if (PolyCount > 0) {
  174. PolyIndices = W3DNEWARRAY uint32[PolyCount];
  175. memcpy(PolyIndices,that.PolyIndices,PolyCount * sizeof(uint32));
  176. }
  177. Mesh = that.Mesh;
  178. return *this;
  179. }
  180. /***********************************************************************************************
  181. * AABTreeClass::Reset -- reset this tree, releases all allocated resources *
  182. * *
  183. * INPUT: *
  184. * *
  185. * OUTPUT: *
  186. * *
  187. * WARNINGS: *
  188. * *
  189. * HISTORY: *
  190. * 6/22/99 GTH : Created. *
  191. *=============================================================================================*/
  192. void AABTreeClass::Reset(void)
  193. {
  194. NodeCount = 0;
  195. if (Nodes) {
  196. delete[] Nodes;
  197. Nodes = NULL;
  198. }
  199. PolyCount = 0;
  200. if (PolyIndices) {
  201. delete[] PolyIndices;
  202. PolyIndices = NULL;
  203. }
  204. if (Mesh) {
  205. Mesh = NULL;
  206. }
  207. }
  208. /***********************************************************************************************
  209. * AABTreeClass::Scale - uniform scale *
  210. * *
  211. * INPUT: *
  212. * *
  213. * OUTPUT: *
  214. * *
  215. * WARNINGS: *
  216. * *
  217. * HISTORY: *
  218. * 6/17/02 Jani : Created. *
  219. *=============================================================================================*/
  220. void AABTreeClass::Scale(float f)
  221. {
  222. for (int i=0;i<NodeCount;++i) {
  223. Nodes[i].Min*=f;
  224. Nodes[i].Max*=f;
  225. }
  226. }
  227. /***********************************************************************************************
  228. * AABTreeClass::Build_Tree_Recursive -- Initializes this tree from the given builder *
  229. * *
  230. * INPUT: *
  231. * *
  232. * OUTPUT: *
  233. * *
  234. * WARNINGS: *
  235. * *
  236. * HISTORY: *
  237. * 5/19/2000 gth : Created. *
  238. *=============================================================================================*/
  239. void AABTreeClass::Build_Tree_Recursive(AABTreeBuilderClass::CullNodeStruct * node,int & curpolyindex)
  240. {
  241. /*
  242. ** Copy data from the builder's node into our node
  243. */
  244. CullNodeStruct * newnode = &(Nodes[node->Index]);
  245. newnode->Min = node->Min;
  246. newnode->Max = node->Max;
  247. /*
  248. ** If this is a non-leaf node, set up the child indices, otherwise set up the polygon indices
  249. */
  250. if (node->Front != NULL) {
  251. WWASSERT(node->Back != NULL); // if we have one child, we better have both!
  252. newnode->Set_Front_Child(node->Front->Index);
  253. newnode->Set_Back_Child(node->Back->Index);
  254. } else {
  255. newnode->Set_Poly0(curpolyindex);
  256. newnode->Set_Poly_Count(node->PolyCount);
  257. }
  258. /*
  259. ** Copy the polygon indices for this node into our array
  260. */
  261. for (int pcounter = 0; pcounter < node->PolyCount; pcounter++) {
  262. PolyIndices[curpolyindex++] = node->PolyIndices[pcounter];
  263. }
  264. /*
  265. ** Install the children
  266. */
  267. if (node->Front) {
  268. Build_Tree_Recursive(node->Front,curpolyindex);
  269. }
  270. if (node->Back) {
  271. Build_Tree_Recursive(node->Back,curpolyindex);
  272. }
  273. }
  274. /***********************************************************************************************
  275. * AABTreeClass::Set_Mesh -- set the mesh pointer *
  276. * *
  277. * INPUT: *
  278. * *
  279. * OUTPUT: *
  280. * *
  281. * WARNINGS: *
  282. * *
  283. * HISTORY: *
  284. * 6/22/99 GTH : Created. *
  285. *=============================================================================================*/
  286. void AABTreeClass::Set_Mesh(MeshGeometryClass * mesh)
  287. {
  288. Mesh = mesh;
  289. }
  290. /***********************************************************************************************
  291. * AABTreeClass::Generate_APT -- Generate an active poly table for the mesh *
  292. * *
  293. * INPUT: *
  294. * box - oriented box to cull the mesh against (in the mesh's coordinate system!!!) *
  295. * apt - vector of ints to fill the apt into *
  296. * *
  297. * OUTPUT: *
  298. * *
  299. * WARNINGS: *
  300. * *
  301. * HISTORY: *
  302. *=============================================================================================*/
  303. void AABTreeClass::Generate_APT(const OBBoxClass & box,SimpleDynVecClass<uint32> & apt)
  304. {
  305. OBBoxAPTContextStruct context(box,apt);
  306. Generate_OBBox_APT_Recursive(&(Nodes[0]),context);
  307. }
  308. /***********************************************************************************************
  309. * AABTreeClass::Generate_OBBox_APT_Recursive -- recursively generate the apt *
  310. * *
  311. * INPUT: *
  312. * node - current node in the recursion *
  313. * context - structure containing the results/current state *
  314. * *
  315. * OUTPUT: *
  316. * *
  317. * WARNINGS: *
  318. * *
  319. * HISTORY: *
  320. * 1/25/00 gth : Created. *
  321. *=============================================================================================*/
  322. void AABTreeClass::Generate_OBBox_APT_Recursive(CullNodeStruct * node,OBBoxAPTContextStruct & context)
  323. {
  324. /*
  325. ** Test the volume against the bounding volume of this node
  326. ** If it is outside, stop descending the tree.
  327. */
  328. AABoxClass nodebox;
  329. nodebox.Init_Min_Max(node->Min,node->Max); // NOTE: too bad we have to compute the nodebox!!!
  330. if (!CollisionMath::Intersection_Test(context.Box,nodebox)) {
  331. return;
  332. }
  333. /*
  334. ** If this is a leaf, test its polygons, otherwise recurse into the children
  335. */
  336. if (node->Is_Leaf()) {
  337. int polycount = node->Get_Poly_Count();
  338. int poly0 = node->Get_Poly0();
  339. if (polycount > 0) {
  340. TriClass tri;
  341. const Vector3 * loc = Mesh->Get_Vertex_Array();
  342. const TriIndex * polys = Mesh->Get_Polygon_Array();
  343. #if (!OPTIMIZE_PLANEEQ_RAM)
  344. const Vector4 * norms = Mesh->Get_Plane_Array();
  345. #endif
  346. for (int poly_counter=0; poly_counter<polycount; poly_counter++) {
  347. int poly_index = PolyIndices[poly0 + poly_counter];
  348. tri.V[0] = &(loc[ polys[poly_index][0] ]);
  349. tri.V[1] = &(loc[ polys[poly_index][1] ]);
  350. tri.V[2] = &(loc[ polys[poly_index][2] ]);
  351. #if (!OPTIMIZE_PLANEEQ_RAM)
  352. tri.N = (Vector3*)&(norms[poly_index]);
  353. #else
  354. Vector3 normal;
  355. tri.N = &normal;
  356. tri.Compute_Normal();
  357. #endif
  358. if (CollisionMath::Intersection_Test(context.Box,tri)) {;
  359. context.APT.Add(poly_index);
  360. }
  361. }
  362. }
  363. } else {
  364. Generate_OBBox_APT_Recursive(&(Nodes[node->Get_Front_Child()]),context);
  365. Generate_OBBox_APT_Recursive(&(Nodes[node->Get_Back_Child()]),context);
  366. }
  367. }
  368. /***********************************************************************************************
  369. * AABTreeClass::Generate_APT -- generate an apt from a box and viewdir *
  370. * *
  371. * Indices of the polys which intersect the box and are not backfacing to the given viewdir *
  372. * will be added to the passed in apt. *
  373. * *
  374. * INPUT: *
  375. * *
  376. * OUTPUT: *
  377. * *
  378. * WARNINGS: *
  379. * *
  380. * HISTORY: *
  381. * 5/10/2001 gth : Created. *
  382. *=============================================================================================*/
  383. void AABTreeClass::Generate_APT
  384. (
  385. const OBBoxClass & box,
  386. const Vector3 & viewdir,
  387. SimpleDynVecClass<uint32> & apt
  388. )
  389. {
  390. OBBoxRayAPTContextStruct context(box,viewdir,apt);
  391. Generate_OBBox_APT_Recursive(&(Nodes[0]),context);
  392. }
  393. /***********************************************************************************************
  394. * AABTreeClass::Generate_OBBox_APT_Recursive -- recurse, generate the apt for a box and viewd *
  395. * *
  396. * INPUT: *
  397. * *
  398. * OUTPUT: *
  399. * *
  400. * WARNINGS: *
  401. * *
  402. * HISTORY: *
  403. * 5/10/2001 gth : Created. *
  404. *=============================================================================================*/
  405. void AABTreeClass::Generate_OBBox_APT_Recursive(CullNodeStruct * node, OBBoxRayAPTContextStruct & context)
  406. {
  407. /*
  408. ** Test the volume against the bounding volume of this node
  409. ** If it is outside, stop descending the tree.
  410. */
  411. AABoxClass nodebox;
  412. nodebox.Init_Min_Max(node->Min,node->Max); // NOTE: too bad we have to compute the nodebox!!!
  413. if (!CollisionMath::Intersection_Test(context.Box,nodebox)) {
  414. return;
  415. }
  416. /*
  417. ** If this is a leaf, test its polygons, otherwise recurse into the children
  418. */
  419. if (node->Is_Leaf()) {
  420. int polycount = node->Get_Poly_Count();
  421. int poly0 = node->Get_Poly0();
  422. if (polycount > 0) {
  423. TriClass tri;
  424. const Vector3 * loc = Mesh->Get_Vertex_Array();
  425. const TriIndex * polys = Mesh->Get_Polygon_Array();
  426. #if (!OPTIMIZE_PLANEEQ_RAM)
  427. const Vector4 * norms = Mesh->Get_Plane_Array();
  428. #endif
  429. for (int poly_counter=0; poly_counter<polycount; poly_counter++) {
  430. int poly_index = PolyIndices[poly0 + poly_counter];
  431. tri.V[0] = &(loc[ polys[poly_index][0] ]);
  432. tri.V[1] = &(loc[ polys[poly_index][1] ]);
  433. tri.V[2] = &(loc[ polys[poly_index][2] ]);
  434. #if (!OPTIMIZE_PLANEEQ_RAM)
  435. tri.N = (Vector3*)&(norms[poly_index]);
  436. #else
  437. Vector3 normal;
  438. tri.N = &normal;
  439. tri.Compute_Normal();
  440. #endif
  441. if (Vector3::Dot_Product(*tri.N,context.ViewVector) < 0.0f) {
  442. if (CollisionMath::Intersection_Test(context.Box,tri)) {
  443. context.APT.Add(poly_index);
  444. }
  445. }
  446. }
  447. }
  448. } else {
  449. Generate_OBBox_APT_Recursive(&(Nodes[node->Get_Front_Child()]),context);
  450. Generate_OBBox_APT_Recursive(&(Nodes[node->Get_Back_Child()]),context);
  451. }
  452. }
  453. /***********************************************************************************************
  454. * AABTreeClass::Cast_Ray_Recursive -- Internal implementation of Cast_Ray *
  455. * *
  456. * INPUT: *
  457. * raytest - contains all of the ray test information *
  458. * node - current cull node being processed *
  459. * *
  460. * OUTPUT: *
  461. * *
  462. * WARNINGS: *
  463. * *
  464. * HISTORY: *
  465. * 6/19/98 GTH : Created. *
  466. *=============================================================================================*/
  467. bool AABTreeClass::Cast_Ray_Recursive(CullNodeStruct * node,RayCollisionTestClass & raytest)
  468. {
  469. /*
  470. ** Cull the collision test against the bounding volume of this node
  471. ** If it is culled, stop descending the tree.
  472. */
  473. if (raytest.Cull(node->Min,node->Max)) {
  474. return false;
  475. }
  476. bool res = false;
  477. if (node->Is_Leaf()) {
  478. return Cast_Ray_To_Polys(node,raytest);
  479. } else {
  480. res = res | Cast_Ray_Recursive(&(Nodes[node->Get_Front_Child()]),raytest);
  481. res = res | Cast_Ray_Recursive(&(Nodes[node->Get_Back_Child()]),raytest);
  482. }
  483. return res;
  484. }
  485. /***********************************************************************************************
  486. * AABTreeClass::Cast_Semi_Infinite_Axis_Aligned_Ray_Recursive -- Internal implementation *
  487. * *
  488. * INPUT: *
  489. * node - current cull node being processed *
  490. * start_point - starting point *
  491. * axis_r - the axis along which the ray is projected *
  492. * axis_1, axis_2 - the other two axes *
  493. * direction - 0 means the ray goes toward the negative axis, 1 means positive. *
  494. * flags - reference bitfield for result flags (ray hit edge, start point embedded in tri, etc)*
  495. * *
  496. * OUTPUT: *
  497. * *
  498. * WARNINGS: *
  499. * *
  500. * HISTORY: *
  501. * 8/30/00 NH : Created. *
  502. *=============================================================================================*/
  503. int AABTreeClass::Cast_Semi_Infinite_Axis_Aligned_Ray_Recursive(CullNodeStruct * node,
  504. const Vector3 & start_point, int axis_r, int axis_1, int axis_2, int direction,
  505. unsigned char & flags)
  506. {
  507. /*
  508. ** Cull the ray against the bounding volume of this node
  509. ** If it is culled, stop descending the tree.
  510. ** We do two main tests: a 2D test against axis1 and axis2 to see if the starting point (and
  511. ** hence the ray) falls within the 2D projection of the bbox, and a 1D test to see if the ray
  512. ** is completely above or below the bbox. The second test checks (start > max) or (start < min)
  513. ** depending on the direction of the ray - we do this in a branchless fashion by turning
  514. ** (start < min) into (-start > -min). Then we can use tables to perform the correct check.
  515. */
  516. static const float sign[2] = { -1.0f, 1.0f };
  517. float bounds[2], start[2];
  518. bounds[0] = -node->Min[axis_r];
  519. bounds[1] = node->Max[axis_r];
  520. start[0] = -start_point[axis_r];
  521. start[1] = start_point[axis_r];
  522. if ( start_point[axis_1] < node->Min[axis_1] || start_point[axis_2] < node->Min[axis_2] ||
  523. start_point[axis_1] > node->Max[axis_1] || start_point[axis_2] > node->Max[axis_2] ||
  524. start[direction] > bounds[direction] ) {
  525. return 0;
  526. }
  527. int count = 0;
  528. if (node->Is_Leaf()) {
  529. return Cast_Semi_Infinite_Axis_Aligned_Ray_To_Polys(node, start_point, axis_r, axis_1,
  530. axis_2, direction, flags);
  531. } else {
  532. count += Cast_Semi_Infinite_Axis_Aligned_Ray_Recursive(&(Nodes[node->Get_Front_Child()]),
  533. start_point, axis_r, axis_1, axis_2, direction, flags);
  534. count += Cast_Semi_Infinite_Axis_Aligned_Ray_Recursive(&(Nodes[node->Get_Back_Child()]),
  535. start_point, axis_r, axis_1, axis_2, direction, flags);
  536. }
  537. return count;
  538. }
  539. /***********************************************************************************************
  540. * AABTreeClass::Cast_AABox_Recursive -- internal implementation of Cast_AABox *
  541. * *
  542. * INPUT: *
  543. * boxtest - contains description of the collision operation to be performed *
  544. * node - current cull node being processed *
  545. * *
  546. * OUTPUT: *
  547. * *
  548. * WARNINGS: *
  549. * *
  550. * HISTORY: *
  551. * 6/19/98 GTH : Created. *
  552. *=============================================================================================*/
  553. bool AABTreeClass::Cast_AABox_Recursive(CullNodeStruct * node,AABoxCollisionTestClass & boxtest)
  554. {
  555. /*
  556. ** First, check the bounding box of the move against the bounding box
  557. ** of this tree, if they don't intersect, bail out
  558. */
  559. if (boxtest.Cull(node->Min,node->Max)) {
  560. return false;
  561. }
  562. bool res = false;
  563. if (node->Is_Leaf()) {
  564. return Cast_AABox_To_Polys(node,boxtest);
  565. } else {
  566. res = res | Cast_AABox_Recursive(&(Nodes[node->Get_Front_Child()]),boxtest);
  567. res = res | Cast_AABox_Recursive(&(Nodes[node->Get_Back_Child()]),boxtest);
  568. }
  569. return res;
  570. }
  571. /***********************************************************************************************
  572. * AABTreeClass::Cast_OBBox_Recursive -- Internal implementation of Cast_OBBox *
  573. * *
  574. * INPUT: *
  575. * boxtest - contains description of the collision test to be performed *
  576. * node - current cull node being processed *
  577. * *
  578. * OUTPUT: *
  579. * *
  580. * WARNINGS: *
  581. * *
  582. * HISTORY: *
  583. * 6/19/98 GTH : Created. *
  584. *=============================================================================================*/
  585. bool AABTreeClass::Cast_OBBox_Recursive(CullNodeStruct * node,OBBoxCollisionTestClass & boxtest)
  586. {
  587. /*
  588. ** First, check the bounding box of the move against the bounding box
  589. ** of this tree, if they don't intersect, bail out
  590. */
  591. if (boxtest.Cull(node->Min,node->Max)) {
  592. return false;
  593. }
  594. bool res = false;
  595. if (node->Is_Leaf()) {
  596. return Cast_OBBox_To_Polys(node,boxtest);
  597. } else {
  598. res = res | Cast_OBBox_Recursive(&(Nodes[node->Get_Front_Child()]),boxtest);
  599. res = res | Cast_OBBox_Recursive(&(Nodes[node->Get_Back_Child()]),boxtest);
  600. }
  601. return res;
  602. }
  603. /***********************************************************************************************
  604. * AABTreeClass::Intersect_OBBox_Recursive -- internal implementation of Intersect_OBBox *
  605. * *
  606. * INPUT: *
  607. * *
  608. * OUTPUT: *
  609. * *
  610. * WARNINGS: *
  611. * *
  612. * HISTORY: *
  613. * 1/20/00 gth : Created. *
  614. *=============================================================================================*/
  615. bool AABTreeClass::Intersect_OBBox_Recursive(AABTreeClass::CullNodeStruct * node,OBBoxIntersectionTestClass & test)
  616. {
  617. /*
  618. ** Cull the collision test against the bounding volume of this node
  619. ** If it is culled, stop descending the tree.
  620. */
  621. if (test.Cull(node->Min,node->Max)) {
  622. return false;
  623. }
  624. bool res = false;
  625. if (node->Is_Leaf()) {
  626. return Intersect_OBBox_With_Polys(node,test);
  627. } else {
  628. res = res | Intersect_OBBox_Recursive(&(Nodes[node->Get_Front_Child()]),test);
  629. res = res | Intersect_OBBox_Recursive(&(Nodes[node->Get_Back_Child()]),test);
  630. }
  631. return res;
  632. }
  633. #ifdef _DEBUG
  634. #pragma optimize("", off) // We get an odd error when using optimized in the debug.
  635. // All optimized seems to work. jba.
  636. #endif
  637. /***********************************************************************************************
  638. * AABTreeClass::Cast_Ray_To_Polys -- cast the ray to polys in the given node *
  639. * *
  640. * INPUT: *
  641. * *
  642. * OUTPUT: *
  643. * *
  644. * WARNINGS: *
  645. * *
  646. * HISTORY: *
  647. * 6/19/98 GTH : Created. *
  648. *=============================================================================================*/
  649. bool AABTreeClass::Cast_Ray_To_Polys(CullNodeStruct * node,RayCollisionTestClass & raytest)
  650. {
  651. if (node->Get_Poly_Count() > 0) {
  652. /*
  653. ** Simply loop through the polys in this node, checking each for collision
  654. */
  655. TriClass tri;
  656. const Vector3 * loc = Mesh->Get_Vertex_Array();
  657. const TriIndex * polyverts = Mesh->Get_Polygon_Array();
  658. #if (!OPTIMIZE_PLANEEQ_RAM)
  659. const Vector4 * norms = Mesh->Get_Plane_Array();
  660. #endif
  661. int polyhit = -1;
  662. int poly0 = node->Get_Poly0();
  663. int polycount = node->Get_Poly_Count();
  664. for (int poly_counter=0; poly_counter<polycount; poly_counter++) {
  665. int poly_index = PolyIndices[poly0 + poly_counter];
  666. tri.V[0] = &(loc[ polyverts[poly_index][0] ]);
  667. tri.V[1] = &(loc[ polyverts[poly_index][1] ]);
  668. tri.V[2] = &(loc[ polyverts[poly_index][2] ]);
  669. #if (!OPTIMIZE_PLANEEQ_RAM)
  670. tri.N = (Vector3*)&(norms[poly_index]);
  671. #else
  672. Vector3 normal;
  673. tri.N = &normal;
  674. tri.Compute_Normal();
  675. #endif
  676. if (CollisionMath::Collide(raytest.Ray,tri,raytest.Result)) {;
  677. polyhit = poly_index;
  678. }
  679. if (raytest.Result->StartBad) {
  680. return true;
  681. }
  682. }
  683. if (polyhit != -1) {
  684. raytest.Result->SurfaceType = Mesh->Get_Poly_Surface_Type (polyhit);
  685. return true;
  686. }
  687. }
  688. return false;
  689. }
  690. #ifdef _DEBUG
  691. #pragma optimize("", on)
  692. #endif
  693. /***********************************************************************************************
  694. * AABTreeClass::Cast_Semi_Infinite_Axis_Aligned_Ray_To_Polys -- cast ray to polys in the node *
  695. * *
  696. * INPUT: *
  697. * node - current cull node being processed *
  698. * start_point - starting point *
  699. * axis_r - the axis along which the ray is projected *
  700. * axis_1, axis_2 - the other two axes *
  701. * direction - 0 means the ray goes toward the negative axis, 1 means positive. *
  702. * flags - reference bitfield for result flags (ray hit edge, start point embedded in tri, etc)*
  703. * *
  704. * OUTPUT: *
  705. * *
  706. * WARNINGS: *
  707. * *
  708. * HISTORY: *
  709. * 8/30/00 NH : Created. *
  710. *=============================================================================================*/
  711. int AABTreeClass::Cast_Semi_Infinite_Axis_Aligned_Ray_To_Polys(CullNodeStruct * node,
  712. const Vector3 & start_point, int axis_r, int axis_1, int axis_2, int direction,
  713. unsigned char & flags)
  714. {
  715. int count = 0;
  716. if (node->Get_Poly_Count() > 0) {
  717. /*
  718. ** Simply loop through the polys in this node, checking each for collision
  719. */
  720. const Vector3 * loc = Mesh->Get_Vertex_Array();
  721. const TriIndex * polyverts = Mesh->Get_Polygon_Array();
  722. const Vector4 * plane = Mesh->Get_Plane_Array();
  723. int poly0 = node->Get_Poly0();
  724. int polycount = node->Get_Poly_Count();
  725. for (int poly_counter=0; poly_counter < polycount; poly_counter++) {
  726. int poly_index = PolyIndices[poly0 + poly_counter];
  727. const Vector3 &v0 = loc[ polyverts[poly_index][0] ];
  728. const Vector3 &v1 = loc[ polyverts[poly_index][1] ];
  729. const Vector3 &v2 = loc[ polyverts[poly_index][2] ];
  730. const Vector4 &tri_plane = plane[poly_index];
  731. // Since (int)true is defined as 1, and (int)false as 0:
  732. count += (unsigned int)Cast_Semi_Infinite_Axis_Aligned_Ray_To_Triangle(v0, v1, v2,
  733. tri_plane, start_point, axis_r, axis_1, axis_2, direction, flags);
  734. }
  735. }
  736. return count;
  737. }
  738. /***********************************************************************************************
  739. * AABTreeClass::Cast_AABox_To_Polys -- cast aabox to polys in the given node *
  740. * *
  741. * INPUT: *
  742. * *
  743. * OUTPUT: *
  744. * *
  745. * WARNINGS: *
  746. * *
  747. * HISTORY: *
  748. * 6/19/98 GTH : Created. *
  749. *=============================================================================================*/
  750. bool AABTreeClass::Cast_AABox_To_Polys(CullNodeStruct * node,AABoxCollisionTestClass & boxtest)
  751. {
  752. if (node->Get_Poly_Count() > 0) {
  753. /*
  754. ** Simply loop through the polys in this node, checking each for collision
  755. */
  756. TriClass tri;
  757. const Vector3 * loc = Mesh->Get_Vertex_Array();
  758. const TriIndex * polyverts = Mesh->Get_Polygon_Array();
  759. #if (!OPTIMIZE_PLANEEQ_RAM)
  760. const Vector4 * norms = Mesh->Get_Plane_Array();
  761. #endif
  762. int polyhit = -1;
  763. int poly0 = node->Get_Poly0();
  764. int polycount = node->Get_Poly_Count();
  765. for (int poly_counter=0; poly_counter<polycount; poly_counter++) {
  766. int poly_index = PolyIndices[poly0 + poly_counter];
  767. tri.V[0] = &(loc[ polyverts[poly_index][0] ]);
  768. tri.V[1] = &(loc[ polyverts[poly_index][1] ]);
  769. tri.V[2] = &(loc[ polyverts[poly_index][2] ]);
  770. #if (!OPTIMIZE_PLANEEQ_RAM)
  771. tri.N = (Vector3*)&(norms[poly_index]);
  772. #else
  773. Vector3 normal;
  774. tri.N = &normal;
  775. tri.Compute_Normal();
  776. #endif
  777. if (CollisionMath::Collide(boxtest.Box,boxtest.Move,tri,boxtest.Result)) {
  778. polyhit = poly_index;
  779. }
  780. if (boxtest.Result->StartBad) {
  781. return true;
  782. }
  783. }
  784. if (polyhit != -1) {
  785. boxtest.Result->SurfaceType = Mesh->Get_Poly_Surface_Type (polyhit);
  786. return true;
  787. }
  788. }
  789. return false;
  790. }
  791. /***********************************************************************************************
  792. * AABTreeClass::Cast_OBBox_To_Polys -- cast obbox to polys in the given node *
  793. * *
  794. * INPUT: *
  795. * *
  796. * OUTPUT: *
  797. * *
  798. * WARNINGS: *
  799. * *
  800. * HISTORY: *
  801. * 6/19/98 GTH : Created. *
  802. *=============================================================================================*/
  803. bool AABTreeClass::Cast_OBBox_To_Polys(CullNodeStruct * node,OBBoxCollisionTestClass & boxtest)
  804. {
  805. int polycount = node->Get_Poly_Count();
  806. int poly0 = node->Get_Poly0();
  807. if (polycount > 0) {
  808. /*
  809. ** Simply loop through the polys in this node, checking each for collision
  810. */
  811. TriClass tri;
  812. const Vector3 * loc = Mesh->Get_Vertex_Array();
  813. const TriIndex * polyverts = Mesh->Get_Polygon_Array();
  814. #if (!OPTIMIZE_PLANEEQ_RAM)
  815. const Vector4 * norms = Mesh->Get_Plane_Array();
  816. #endif
  817. int polyhit = -1;
  818. for (int poly_counter=0; poly_counter<polycount; poly_counter++) {
  819. int poly_index = PolyIndices[poly0 + poly_counter];
  820. tri.V[0] = &(loc[ polyverts[poly_index][0] ]);
  821. tri.V[1] = &(loc[ polyverts[poly_index][1] ]);
  822. tri.V[2] = &(loc[ polyverts[poly_index][2] ]);
  823. #if (!OPTIMIZE_PLANEEQ_RAM)
  824. tri.N = (Vector3*)&(norms[poly_index]);
  825. #else
  826. Vector3 normal;
  827. tri.N = &normal;
  828. tri.Compute_Normal();
  829. #endif
  830. if (CollisionMath::Collide(boxtest.Box,boxtest.Move,tri,Vector3(0,0,0),boxtest.Result)) {
  831. polyhit = poly_index;
  832. }
  833. if (boxtest.Result->StartBad) {
  834. return true;
  835. }
  836. }
  837. if (polyhit != -1) {
  838. boxtest.Result->SurfaceType = Mesh->Get_Poly_Surface_Type (polyhit);
  839. return true;
  840. }
  841. }
  842. return false;
  843. }
  844. /***********************************************************************************************
  845. * AABTreeClass::Intersect_OBBox_With_Polys -- Test polys for intersection *
  846. * *
  847. * INPUT: *
  848. * *
  849. * OUTPUT: *
  850. * *
  851. * WARNINGS: *
  852. * *
  853. * HISTORY: *
  854. * 1/20/00 gth : Created. *
  855. *=============================================================================================*/
  856. bool AABTreeClass::Intersect_OBBox_With_Polys
  857. (
  858. CullNodeStruct * node,
  859. OBBoxIntersectionTestClass & test
  860. )
  861. {
  862. int poly0 = node->Get_Poly0();
  863. int polycount = node->Get_Poly_Count();
  864. if (polycount > 0) {
  865. /*
  866. ** Simply loop through the polys in this node, checking each for collision
  867. */
  868. TriClass tri;
  869. const Vector3 * loc = Mesh->Get_Vertex_Array();
  870. const TriIndex * polyverts = Mesh->Get_Polygon_Array();
  871. #if (!OPTIMIZE_PLANEEQ_RAM)
  872. const Vector4 * norms = Mesh->Get_Plane_Array();
  873. #endif
  874. for (int poly_counter=0; poly_counter<polycount; poly_counter++) {
  875. int poly_index = PolyIndices[poly0 + poly_counter];
  876. tri.V[0] = &(loc[ polyverts[poly_index][0] ]);
  877. tri.V[1] = &(loc[ polyverts[poly_index][1] ]);
  878. tri.V[2] = &(loc[ polyverts[poly_index][2] ]);
  879. #if (!OPTIMIZE_PLANEEQ_RAM)
  880. tri.N = (Vector3*)&(norms[poly_index]);
  881. #else
  882. Vector3 normal;
  883. tri.N = &normal;
  884. tri.Compute_Normal();
  885. #endif
  886. if (CollisionMath::Intersection_Test(test.Box,tri)) {
  887. return true;
  888. }
  889. }
  890. }
  891. return false;
  892. }
  893. /***********************************************************************************************
  894. * AABTreeClass::Update_Bounding_Boxes_Recursive -- recompute the bounding boxes *
  895. * *
  896. * Typically this function will be used when you have modified the mesh slightly and you need *
  897. * to update the bounding boxes but you want to keep the structure of the tree. *
  898. * *
  899. * INPUT: *
  900. * *
  901. * OUTPUT: *
  902. * *
  903. * WARNINGS: *
  904. * *
  905. * HISTORY: *
  906. * 6/22/99 GTH : Created. *
  907. *=============================================================================================*/
  908. void AABTreeClass::Update_Bounding_Boxes_Recursive(CullNodeStruct * node)
  909. {
  910. node->Min.Set(100000.0f,100000.0f,100000.0f);
  911. node->Max.Set(-100000.0f,-100000.0f,-100000.0f);
  912. /*
  913. ** Recurse to the children first
  914. */
  915. if (node->Is_Leaf() == false) {
  916. Update_Bounding_Boxes_Recursive(&(Nodes[node->Get_Front_Child()]));
  917. Update_Bounding_Boxes_Recursive(&(Nodes[node->Get_Back_Child()]));
  918. /*
  919. ** Bound our children
  920. */
  921. int front = node->Get_Front_Child();
  922. int back = node->Get_Back_Child();
  923. if (Nodes[front].Min.X < node->Min.X) node->Min.X = Nodes[front].Min.X;
  924. if (Nodes[front].Max.X > node->Max.X) node->Max.X = Nodes[front].Max.X;
  925. if (Nodes[front].Min.Y < node->Min.Y) node->Min.Y = Nodes[front].Min.Y;
  926. if (Nodes[front].Max.Y > node->Max.Y) node->Max.Y = Nodes[front].Max.Y;
  927. if (Nodes[front].Min.Z < node->Min.Z) node->Min.Z = Nodes[front].Min.Z;
  928. if (Nodes[front].Max.Z > node->Max.Z) node->Max.Z = Nodes[front].Max.Z;
  929. if (Nodes[back].Min.X < node->Min.X) node->Min.X = Nodes[back].Min.X;
  930. if (Nodes[back].Max.X > node->Max.X) node->Max.X = Nodes[back].Max.X;
  931. if (Nodes[back].Min.Y < node->Min.Y) node->Min.Y = Nodes[back].Min.Y;
  932. if (Nodes[back].Max.Y > node->Max.Y) node->Max.Y = Nodes[back].Max.Y;
  933. if (Nodes[back].Min.Z < node->Min.Z) node->Min.Z = Nodes[back].Min.Z;
  934. if (Nodes[back].Max.Z > node->Max.Z) node->Max.Z = Nodes[back].Max.Z;
  935. } else {
  936. /*
  937. ** Bound our polygons
  938. */
  939. int poly0 = node->Get_Poly0();
  940. int polycount = node->Get_Poly_Count();
  941. for (int poly_index = 0; poly_index < polycount; poly_index++) {
  942. int pi = PolyIndices[poly0 + poly_index];
  943. Update_Min_Max(pi,node->Min,node->Max );
  944. }
  945. }
  946. WWASSERT(node->Min.X != 100000.0f);
  947. WWASSERT(node->Min.Y != 100000.0f);
  948. WWASSERT(node->Min.Z != 100000.0f);
  949. WWASSERT(node->Max.X != -100000.0f);
  950. WWASSERT(node->Max.Y != -100000.0f);
  951. WWASSERT(node->Max.Z != -100000.0f);
  952. }
  953. /***********************************************************************************************
  954. * AABTreeClass::Update_Min_Max -- updates min and max given a polygon index *
  955. * *
  956. * INPUT: *
  957. * *
  958. * OUTPUT: *
  959. * *
  960. * WARNINGS: *
  961. * *
  962. * HISTORY: *
  963. * 6/22/99 GTH : Created. *
  964. *=============================================================================================*/
  965. void AABTreeClass::Update_Min_Max(int poly_index,Vector3 & min,Vector3 & max)
  966. {
  967. for (int vert_index = 0; vert_index < 3; vert_index++) {
  968. const TriIndex * polyverts = Mesh->Get_Polygon_Array() + poly_index;
  969. const Vector3 * point = Mesh->Get_Vertex_Array() + (*polyverts)[vert_index];
  970. if (point->X < min.X) min.X = point->X;
  971. if (point->Y < min.Y) min.Y = point->Y;
  972. if (point->Z < min.Z) min.Z = point->Z;
  973. if (point->X > max.X) max.X = point->X;
  974. if (point->Y > max.Y) max.Y = point->Y;
  975. if (point->Z > max.Z) max.Z = point->Z;
  976. }
  977. }
  978. /***********************************************************************************************
  979. * AABTreeClass::Load_W3D -- Load a W3D description of an AABTree *
  980. * *
  981. * INPUT: *
  982. * *
  983. * OUTPUT: *
  984. * *
  985. * WARNINGS: *
  986. * *
  987. * HISTORY: *
  988. * 5/22/2000 gth : Created. *
  989. *=============================================================================================*/
  990. void AABTreeClass::Load_W3D(ChunkLoadClass & cload)
  991. {
  992. Reset();
  993. W3dMeshAABTreeHeader header;
  994. cload.Open_Chunk();
  995. WWASSERT(cload.Cur_Chunk_ID() == W3D_CHUNK_AABTREE_HEADER);
  996. cload.Read(&header,sizeof(header));
  997. cload.Close_Chunk();
  998. NodeCount = header.NodeCount;
  999. PolyCount = header.PolyCount;
  1000. Nodes = W3DNEWARRAY CullNodeStruct[NodeCount];
  1001. PolyIndices = W3DNEWARRAY uint32[PolyCount];
  1002. while (cload.Open_Chunk()) {
  1003. switch (cload.Cur_Chunk_ID())
  1004. {
  1005. case W3D_CHUNK_AABTREE_POLYINDICES:
  1006. Read_Poly_Indices(cload);
  1007. break;
  1008. case W3D_CHUNK_AABTREE_NODES:
  1009. Read_Nodes(cload);
  1010. break;
  1011. }
  1012. cload.Close_Chunk();
  1013. }
  1014. }
  1015. /***********************************************************************************************
  1016. * AABTreeClass::Read_Poly_Indices -- load the polygon index array *
  1017. * *
  1018. * INPUT: *
  1019. * *
  1020. * OUTPUT: *
  1021. * *
  1022. * WARNINGS: *
  1023. * *
  1024. * HISTORY: *
  1025. * 5/22/2000 gth : Created. *
  1026. *=============================================================================================*/
  1027. void AABTreeClass::Read_Poly_Indices(ChunkLoadClass & cload)
  1028. {
  1029. cload.Read(PolyIndices,sizeof(uint32) * PolyCount);
  1030. }
  1031. /***********************************************************************************************
  1032. * AABTreeClass::Read_Nodes -- Load the node array *
  1033. * *
  1034. * INPUT: *
  1035. * *
  1036. * OUTPUT: *
  1037. * *
  1038. * WARNINGS: *
  1039. * *
  1040. * HISTORY: *
  1041. * 5/22/2000 gth : Created. *
  1042. *=============================================================================================*/
  1043. void AABTreeClass::Read_Nodes(ChunkLoadClass & cload)
  1044. {
  1045. W3dMeshAABTreeNode w3dnode;
  1046. for (int i=0; i<NodeCount; i++) {
  1047. cload.Read(&w3dnode,sizeof(w3dnode));
  1048. Nodes[i].Min.X = w3dnode.Min.X;
  1049. Nodes[i].Min.Y = w3dnode.Min.Y;
  1050. Nodes[i].Min.Z = w3dnode.Min.Z;
  1051. Nodes[i].Max.X = w3dnode.Max.X;
  1052. Nodes[i].Max.Y = w3dnode.Max.Y;
  1053. Nodes[i].Max.Z = w3dnode.Max.Z;
  1054. Nodes[i].FrontOrPoly0 = w3dnode.FrontOrPoly0;
  1055. Nodes[i].BackOrPolyCount = w3dnode.BackOrPolyCount;
  1056. }
  1057. }