aabtree.cpp 58 KB

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