aabtree.cpp 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WW3D *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/aabtree.cpp $*
  25. * *
  26. * Author:: Greg Hjelstrom *
  27. * *
  28. * $Modtime:: 6/14/01 9:42a $*
  29. * *
  30. * $Revision:: 3 $*
  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 = W3DNEWARRAY AABTreeClass::CullNodeStruct[NodeCount];
  111. PolyCount = builder->Poly_Count();
  112. PolyIndices = W3DNEWARRAY 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 = W3DNEWARRAY CullNodeStruct[NodeCount];
  171. memcpy(Nodes,that.Nodes,NodeCount * sizeof(CullNodeStruct));
  172. }
  173. PolyCount = that.PolyCount;
  174. if (PolyCount > 0) {
  175. PolyIndices = W3DNEWARRAY 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 Vector3i * 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 Vector3i * 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. #ifdef _DEBUG
  616. #pragma optimize("", off) // We get an odd error when using optimized in the debug.
  617. // All optimized seems to work. jba.
  618. #endif
  619. /***********************************************************************************************
  620. * AABTreeClass::Cast_Ray_To_Polys -- cast the ray to polys in the given node *
  621. * *
  622. * INPUT: *
  623. * *
  624. * OUTPUT: *
  625. * *
  626. * WARNINGS: *
  627. * *
  628. * HISTORY: *
  629. * 6/19/98 GTH : Created. *
  630. *=============================================================================================*/
  631. bool AABTreeClass::Cast_Ray_To_Polys(CullNodeStruct * node,RayCollisionTestClass & raytest)
  632. {
  633. if (node->Get_Poly_Count() > 0) {
  634. /*
  635. ** Simply loop through the polys in this node, checking each for collision
  636. */
  637. TriClass tri;
  638. const Vector3 * loc = Mesh->Get_Vertex_Array();
  639. const Vector3i * polyverts = Mesh->Get_Polygon_Array();
  640. #if (!OPTIMIZE_PLANEEQ_RAM)
  641. const Vector4 * norms = Mesh->Get_Plane_Array();
  642. #endif
  643. int polyhit = -1;
  644. int poly0 = node->Get_Poly0();
  645. int polycount = node->Get_Poly_Count();
  646. for (int poly_counter=0; poly_counter<polycount; poly_counter++) {
  647. int poly_index = PolyIndices[poly0 + poly_counter];
  648. tri.V[0] = &(loc[ polyverts[poly_index][0] ]);
  649. tri.V[1] = &(loc[ polyverts[poly_index][1] ]);
  650. tri.V[2] = &(loc[ polyverts[poly_index][2] ]);
  651. #if (!OPTIMIZE_PLANEEQ_RAM)
  652. tri.N = (Vector3*)&(norms[poly_index]);
  653. #else
  654. Vector3 normal;
  655. tri.N = &normal;
  656. tri.Compute_Normal();
  657. #endif
  658. if (CollisionMath::Collide(raytest.Ray,tri,raytest.Result)) {;
  659. polyhit = poly_index;
  660. }
  661. if (raytest.Result->StartBad) {
  662. return true;
  663. }
  664. }
  665. if (polyhit != -1) {
  666. raytest.Result->SurfaceType = Mesh->Get_Poly_Surface_Type (polyhit);
  667. return true;
  668. }
  669. }
  670. return false;
  671. }
  672. #ifdef _DEBUG
  673. #pragma optimize("", on)
  674. #endif
  675. /***********************************************************************************************
  676. * AABTreeClass::Cast_Semi_Infinite_Axis_Aligned_Ray_To_Polys -- cast ray to polys in the node *
  677. * *
  678. * INPUT: *
  679. * node - current cull node being processed *
  680. * start_point - starting point *
  681. * axis_r - the axis along which the ray is projected *
  682. * axis_1, axis_2 - the other two axes *
  683. * direction - 0 means the ray goes toward the negative axis, 1 means positive. *
  684. * flags - reference bitfield for result flags (ray hit edge, start point embedded in tri, etc)*
  685. * *
  686. * OUTPUT: *
  687. * *
  688. * WARNINGS: *
  689. * *
  690. * HISTORY: *
  691. * 8/30/00 NH : Created. *
  692. *=============================================================================================*/
  693. int AABTreeClass::Cast_Semi_Infinite_Axis_Aligned_Ray_To_Polys(CullNodeStruct * node,
  694. const Vector3 & start_point, int axis_r, int axis_1, int axis_2, int direction,
  695. unsigned char & flags)
  696. {
  697. int count = 0;
  698. if (node->Get_Poly_Count() > 0) {
  699. /*
  700. ** Simply loop through the polys in this node, checking each for collision
  701. */
  702. const Vector3 * loc = Mesh->Get_Vertex_Array();
  703. const Vector3i * polyverts = Mesh->Get_Polygon_Array();
  704. const Vector4 * plane = Mesh->Get_Plane_Array();
  705. int poly0 = node->Get_Poly0();
  706. int polycount = node->Get_Poly_Count();
  707. for (int poly_counter=0; poly_counter < polycount; poly_counter++) {
  708. int poly_index = PolyIndices[poly0 + poly_counter];
  709. const Vector3 &v0 = loc[ polyverts[poly_index][0] ];
  710. const Vector3 &v1 = loc[ polyverts[poly_index][1] ];
  711. const Vector3 &v2 = loc[ polyverts[poly_index][2] ];
  712. const Vector4 &tri_plane = plane[poly_index];
  713. // Since (int)true is defined as 1, and (int)false as 0:
  714. count += (unsigned int)Cast_Semi_Infinite_Axis_Aligned_Ray_To_Triangle(v0, v1, v2,
  715. tri_plane, start_point, axis_r, axis_1, axis_2, direction, flags);
  716. }
  717. }
  718. return count;
  719. }
  720. /***********************************************************************************************
  721. * AABTreeClass::Cast_AABox_To_Polys -- cast aabox to polys in the given node *
  722. * *
  723. * INPUT: *
  724. * *
  725. * OUTPUT: *
  726. * *
  727. * WARNINGS: *
  728. * *
  729. * HISTORY: *
  730. * 6/19/98 GTH : Created. *
  731. *=============================================================================================*/
  732. bool AABTreeClass::Cast_AABox_To_Polys(CullNodeStruct * node,AABoxCollisionTestClass & boxtest)
  733. {
  734. if (node->Get_Poly_Count() > 0) {
  735. /*
  736. ** Simply loop through the polys in this node, checking each for collision
  737. */
  738. TriClass tri;
  739. const Vector3 * loc = Mesh->Get_Vertex_Array();
  740. const Vector3i * polyverts = Mesh->Get_Polygon_Array();
  741. #if (!OPTIMIZE_PLANEEQ_RAM)
  742. const Vector4 * norms = Mesh->Get_Plane_Array();
  743. #endif
  744. int polyhit = -1;
  745. int poly0 = node->Get_Poly0();
  746. int polycount = node->Get_Poly_Count();
  747. for (int poly_counter=0; poly_counter<polycount; poly_counter++) {
  748. int poly_index = PolyIndices[poly0 + poly_counter];
  749. tri.V[0] = &(loc[ polyverts[poly_index][0] ]);
  750. tri.V[1] = &(loc[ polyverts[poly_index][1] ]);
  751. tri.V[2] = &(loc[ polyverts[poly_index][2] ]);
  752. #if (!OPTIMIZE_PLANEEQ_RAM)
  753. tri.N = (Vector3*)&(norms[poly_index]);
  754. #else
  755. Vector3 normal;
  756. tri.N = &normal;
  757. tri.Compute_Normal();
  758. #endif
  759. if (CollisionMath::Collide(boxtest.Box,boxtest.Move,tri,boxtest.Result)) {
  760. polyhit = poly_index;
  761. }
  762. if (boxtest.Result->StartBad) {
  763. return true;
  764. }
  765. }
  766. if (polyhit != -1) {
  767. boxtest.Result->SurfaceType = Mesh->Get_Poly_Surface_Type (polyhit);
  768. return true;
  769. }
  770. }
  771. return false;
  772. }
  773. /***********************************************************************************************
  774. * AABTreeClass::Cast_OBBox_To_Polys -- cast obbox to polys in the given node *
  775. * *
  776. * INPUT: *
  777. * *
  778. * OUTPUT: *
  779. * *
  780. * WARNINGS: *
  781. * *
  782. * HISTORY: *
  783. * 6/19/98 GTH : Created. *
  784. *=============================================================================================*/
  785. bool AABTreeClass::Cast_OBBox_To_Polys(CullNodeStruct * node,OBBoxCollisionTestClass & boxtest)
  786. {
  787. int polycount = node->Get_Poly_Count();
  788. int poly0 = node->Get_Poly0();
  789. if (polycount > 0) {
  790. /*
  791. ** Simply loop through the polys in this node, checking each for collision
  792. */
  793. TriClass tri;
  794. const Vector3 * loc = Mesh->Get_Vertex_Array();
  795. const Vector3i * polyverts = Mesh->Get_Polygon_Array();
  796. #if (!OPTIMIZE_PLANEEQ_RAM)
  797. const Vector4 * norms = Mesh->Get_Plane_Array();
  798. #endif
  799. int polyhit = -1;
  800. for (int poly_counter=0; poly_counter<polycount; poly_counter++) {
  801. int poly_index = PolyIndices[poly0 + poly_counter];
  802. tri.V[0] = &(loc[ polyverts[poly_index][0] ]);
  803. tri.V[1] = &(loc[ polyverts[poly_index][1] ]);
  804. tri.V[2] = &(loc[ polyverts[poly_index][2] ]);
  805. #if (!OPTIMIZE_PLANEEQ_RAM)
  806. tri.N = (Vector3*)&(norms[poly_index]);
  807. #else
  808. Vector3 normal;
  809. tri.N = &normal;
  810. tri.Compute_Normal();
  811. #endif
  812. if (CollisionMath::Collide(boxtest.Box,boxtest.Move,tri,Vector3(0,0,0),boxtest.Result)) {
  813. polyhit = poly_index;
  814. }
  815. if (boxtest.Result->StartBad) {
  816. return true;
  817. }
  818. }
  819. if (polyhit != -1) {
  820. boxtest.Result->SurfaceType = Mesh->Get_Poly_Surface_Type (polyhit);
  821. return true;
  822. }
  823. }
  824. return false;
  825. }
  826. /***********************************************************************************************
  827. * AABTreeClass::Intersect_OBBox_With_Polys -- Test polys for intersection *
  828. * *
  829. * INPUT: *
  830. * *
  831. * OUTPUT: *
  832. * *
  833. * WARNINGS: *
  834. * *
  835. * HISTORY: *
  836. * 1/20/00 gth : Created. *
  837. *=============================================================================================*/
  838. bool AABTreeClass::Intersect_OBBox_With_Polys
  839. (
  840. CullNodeStruct * node,
  841. OBBoxIntersectionTestClass & test
  842. )
  843. {
  844. int poly0 = node->Get_Poly0();
  845. int polycount = node->Get_Poly_Count();
  846. if (polycount > 0) {
  847. /*
  848. ** Simply loop through the polys in this node, checking each for collision
  849. */
  850. TriClass tri;
  851. const Vector3 * loc = Mesh->Get_Vertex_Array();
  852. const Vector3i * polyverts = Mesh->Get_Polygon_Array();
  853. #if (!OPTIMIZE_PLANEEQ_RAM)
  854. const Vector4 * norms = Mesh->Get_Plane_Array();
  855. #endif
  856. for (int poly_counter=0; poly_counter<polycount; poly_counter++) {
  857. int poly_index = PolyIndices[poly0 + poly_counter];
  858. tri.V[0] = &(loc[ polyverts[poly_index][0] ]);
  859. tri.V[1] = &(loc[ polyverts[poly_index][1] ]);
  860. tri.V[2] = &(loc[ polyverts[poly_index][2] ]);
  861. #if (!OPTIMIZE_PLANEEQ_RAM)
  862. tri.N = (Vector3*)&(norms[poly_index]);
  863. #else
  864. Vector3 normal;
  865. tri.N = &normal;
  866. tri.Compute_Normal();
  867. #endif
  868. if (CollisionMath::Intersection_Test(test.Box,tri)) {
  869. return true;
  870. }
  871. }
  872. }
  873. return false;
  874. }
  875. /***********************************************************************************************
  876. * AABTreeClass::Update_Bounding_Boxes_Recursive -- recompute the bounding boxes *
  877. * *
  878. * Typically this function will be used when you have modified the mesh slightly and you need *
  879. * to update the bounding boxes but you want to keep the structure of the tree. *
  880. * *
  881. * INPUT: *
  882. * *
  883. * OUTPUT: *
  884. * *
  885. * WARNINGS: *
  886. * *
  887. * HISTORY: *
  888. * 6/22/99 GTH : Created. *
  889. *=============================================================================================*/
  890. void AABTreeClass::Update_Bounding_Boxes_Recursive(CullNodeStruct * node)
  891. {
  892. node->Min.Set(100000.0f,100000.0f,100000.0f);
  893. node->Max.Set(-100000.0f,-100000.0f,-100000.0f);
  894. /*
  895. ** Recurse to the children first
  896. */
  897. if (node->Is_Leaf() == false) {
  898. Update_Bounding_Boxes_Recursive(&(Nodes[node->Get_Front_Child()]));
  899. Update_Bounding_Boxes_Recursive(&(Nodes[node->Get_Back_Child()]));
  900. /*
  901. ** Bound our children
  902. */
  903. int front = node->Get_Front_Child();
  904. int back = node->Get_Back_Child();
  905. if (Nodes[front].Min.X < node->Min.X) node->Min.X = Nodes[front].Min.X;
  906. if (Nodes[front].Max.X > node->Max.X) node->Max.X = Nodes[front].Max.X;
  907. if (Nodes[front].Min.Y < node->Min.Y) node->Min.Y = Nodes[front].Min.Y;
  908. if (Nodes[front].Max.Y > node->Max.Y) node->Max.Y = Nodes[front].Max.Y;
  909. if (Nodes[front].Min.Z < node->Min.Z) node->Min.Z = Nodes[front].Min.Z;
  910. if (Nodes[front].Max.Z > node->Max.Z) node->Max.Z = Nodes[front].Max.Z;
  911. if (Nodes[back].Min.X < node->Min.X) node->Min.X = Nodes[back].Min.X;
  912. if (Nodes[back].Max.X > node->Max.X) node->Max.X = Nodes[back].Max.X;
  913. if (Nodes[back].Min.Y < node->Min.Y) node->Min.Y = Nodes[back].Min.Y;
  914. if (Nodes[back].Max.Y > node->Max.Y) node->Max.Y = Nodes[back].Max.Y;
  915. if (Nodes[back].Min.Z < node->Min.Z) node->Min.Z = Nodes[back].Min.Z;
  916. if (Nodes[back].Max.Z > node->Max.Z) node->Max.Z = Nodes[back].Max.Z;
  917. } else {
  918. /*
  919. ** Bound our polygons
  920. */
  921. int poly0 = node->Get_Poly0();
  922. int polycount = node->Get_Poly_Count();
  923. for (int poly_index = 0; poly_index < polycount; poly_index++) {
  924. int pi = PolyIndices[poly0 + poly_index];
  925. Update_Min_Max(pi,node->Min,node->Max );
  926. }
  927. }
  928. WWASSERT(node->Min.X != 100000.0f);
  929. WWASSERT(node->Min.Y != 100000.0f);
  930. WWASSERT(node->Min.Z != 100000.0f);
  931. WWASSERT(node->Max.X != -100000.0f);
  932. WWASSERT(node->Max.Y != -100000.0f);
  933. WWASSERT(node->Max.Z != -100000.0f);
  934. }
  935. /***********************************************************************************************
  936. * AABTreeClass::Update_Min_Max -- updates min and max given a polygon index *
  937. * *
  938. * INPUT: *
  939. * *
  940. * OUTPUT: *
  941. * *
  942. * WARNINGS: *
  943. * *
  944. * HISTORY: *
  945. * 6/22/99 GTH : Created. *
  946. *=============================================================================================*/
  947. void AABTreeClass::Update_Min_Max(int poly_index,Vector3 & min,Vector3 & max)
  948. {
  949. for (int vert_index = 0; vert_index < 3; vert_index++) {
  950. const Vector3i * polyverts = Mesh->Get_Polygon_Array() + poly_index;
  951. const Vector3 * point = Mesh->Get_Vertex_Array() + (*polyverts)[vert_index];
  952. if (point->X < min.X) min.X = point->X;
  953. if (point->Y < min.Y) min.Y = point->Y;
  954. if (point->Z < min.Z) min.Z = point->Z;
  955. if (point->X > max.X) max.X = point->X;
  956. if (point->Y > max.Y) max.Y = point->Y;
  957. if (point->Z > max.Z) max.Z = point->Z;
  958. }
  959. }
  960. /***********************************************************************************************
  961. * AABTreeClass::Load_W3D -- Load a W3D description of an AABTree *
  962. * *
  963. * INPUT: *
  964. * *
  965. * OUTPUT: *
  966. * *
  967. * WARNINGS: *
  968. * *
  969. * HISTORY: *
  970. * 5/22/2000 gth : Created. *
  971. *=============================================================================================*/
  972. void AABTreeClass::Load_W3D(ChunkLoadClass & cload)
  973. {
  974. Reset();
  975. W3dMeshAABTreeHeader header;
  976. cload.Open_Chunk();
  977. WWASSERT(cload.Cur_Chunk_ID() == W3D_CHUNK_AABTREE_HEADER);
  978. cload.Read(&header,sizeof(header));
  979. cload.Close_Chunk();
  980. NodeCount = header.NodeCount;
  981. PolyCount = header.PolyCount;
  982. Nodes = W3DNEWARRAY CullNodeStruct[NodeCount];
  983. PolyIndices = W3DNEWARRAY uint32[PolyCount];
  984. while (cload.Open_Chunk()) {
  985. switch (cload.Cur_Chunk_ID())
  986. {
  987. case W3D_CHUNK_AABTREE_POLYINDICES:
  988. Read_Poly_Indices(cload);
  989. break;
  990. case W3D_CHUNK_AABTREE_NODES:
  991. Read_Nodes(cload);
  992. break;
  993. }
  994. cload.Close_Chunk();
  995. }
  996. }
  997. /***********************************************************************************************
  998. * AABTreeClass::Read_Poly_Indices -- load the polygon index array *
  999. * *
  1000. * INPUT: *
  1001. * *
  1002. * OUTPUT: *
  1003. * *
  1004. * WARNINGS: *
  1005. * *
  1006. * HISTORY: *
  1007. * 5/22/2000 gth : Created. *
  1008. *=============================================================================================*/
  1009. void AABTreeClass::Read_Poly_Indices(ChunkLoadClass & cload)
  1010. {
  1011. cload.Read(PolyIndices,sizeof(uint32) * PolyCount);
  1012. }
  1013. /***********************************************************************************************
  1014. * AABTreeClass::Read_Nodes -- Load the node array *
  1015. * *
  1016. * INPUT: *
  1017. * *
  1018. * OUTPUT: *
  1019. * *
  1020. * WARNINGS: *
  1021. * *
  1022. * HISTORY: *
  1023. * 5/22/2000 gth : Created. *
  1024. *=============================================================================================*/
  1025. void AABTreeClass::Read_Nodes(ChunkLoadClass & cload)
  1026. {
  1027. W3dMeshAABTreeNode w3dnode;
  1028. for (int i=0; i<NodeCount; i++) {
  1029. cload.Read(&w3dnode,sizeof(w3dnode));
  1030. Nodes[i].Min.X = w3dnode.Min.X;
  1031. Nodes[i].Min.Y = w3dnode.Min.Y;
  1032. Nodes[i].Min.Z = w3dnode.Min.Z;
  1033. Nodes[i].Max.X = w3dnode.Max.X;
  1034. Nodes[i].Max.Y = w3dnode.Max.Y;
  1035. Nodes[i].Max.Z = w3dnode.Max.Z;
  1036. Nodes[i].FrontOrPoly0 = w3dnode.FrontOrPoly0;
  1037. Nodes[i].BackOrPolyCount = w3dnode.BackOrPolyCount;
  1038. }
  1039. }