AASFile_sample.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code 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. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "AASFile.h"
  23. #include "AASFile_local.h"
  24. //===============================================================
  25. //
  26. // Environment Sampling
  27. //
  28. //===============================================================
  29. /*
  30. ================
  31. idAASFileLocal::EdgeCenter
  32. ================
  33. */
  34. idVec3 idAASFileLocal::EdgeCenter( int edgeNum ) const {
  35. const aasEdge_t *edge;
  36. edge = &edges[edgeNum];
  37. return ( vertices[edge->vertexNum[0]] + vertices[edge->vertexNum[1]] ) * 0.5f;
  38. }
  39. /*
  40. ================
  41. idAASFileLocal::FaceCenter
  42. ================
  43. */
  44. idVec3 idAASFileLocal::FaceCenter( int faceNum ) const {
  45. int i, edgeNum;
  46. const aasFace_t *face;
  47. const aasEdge_t *edge;
  48. idVec3 center;
  49. center = vec3_origin;
  50. face = &faces[faceNum];
  51. if ( face->numEdges > 0 ) {
  52. for ( i = 0; i < face->numEdges; i++ ) {
  53. edgeNum = edgeIndex[ face->firstEdge + i ];
  54. edge = &edges[ abs( edgeNum ) ];
  55. center += vertices[ edge->vertexNum[ INT32_SIGNBITSET(edgeNum) ] ];
  56. }
  57. center /= face->numEdges;
  58. }
  59. return center;
  60. }
  61. /*
  62. ================
  63. idAASFileLocal::AreaCenter
  64. ================
  65. */
  66. idVec3 idAASFileLocal::AreaCenter( int areaNum ) const {
  67. int i, faceNum;
  68. const aasArea_t *area;
  69. idVec3 center;
  70. center = vec3_origin;
  71. area = &areas[areaNum];
  72. if ( area->numFaces > 0 ) {
  73. for ( i = 0; i < area->numFaces; i++ ) {
  74. faceNum = faceIndex[area->firstFace + i];
  75. center += FaceCenter( abs(faceNum) );
  76. }
  77. center /= area->numFaces;
  78. }
  79. return center;
  80. }
  81. /*
  82. ============
  83. idAASFileLocal::AreaReachableGoal
  84. ============
  85. */
  86. idVec3 idAASFileLocal::AreaReachableGoal( int areaNum ) const {
  87. int i, faceNum, numFaces;
  88. const aasArea_t *area;
  89. idVec3 center;
  90. idVec3 start, end;
  91. aasTrace_t trace;
  92. area = &areas[areaNum];
  93. if ( !(area->flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY)) || (area->flags & AREA_LIQUID) ) {
  94. return AreaCenter( areaNum );
  95. }
  96. center = vec3_origin;
  97. numFaces = 0;
  98. for ( i = 0; i < area->numFaces; i++ ) {
  99. faceNum = faceIndex[area->firstFace + i];
  100. if ( !(faces[abs(faceNum)].flags & FACE_FLOOR) ) {
  101. continue;
  102. }
  103. center += FaceCenter( abs(faceNum) );
  104. numFaces++;
  105. }
  106. if ( numFaces > 0 ) {
  107. center /= numFaces;
  108. }
  109. center[2] += 1.0f;
  110. end = center;
  111. end[2] -= 1024;
  112. Trace( trace, center, end );
  113. return trace.endpos;
  114. }
  115. /*
  116. ================
  117. idAASFileLocal::EdgeBounds
  118. ================
  119. */
  120. idBounds idAASFileLocal::EdgeBounds( int edgeNum ) const {
  121. const aasEdge_t *edge;
  122. idBounds bounds;
  123. edge = &edges[ abs( edgeNum ) ];
  124. bounds[0] = bounds[1] = vertices[ edge->vertexNum[0] ];
  125. bounds += vertices[ edge->vertexNum[1] ];
  126. return bounds;
  127. }
  128. /*
  129. ================
  130. idAASFileLocal::FaceBounds
  131. ================
  132. */
  133. idBounds idAASFileLocal::FaceBounds( int faceNum ) const {
  134. int i, edgeNum;
  135. const aasFace_t *face;
  136. const aasEdge_t *edge;
  137. idBounds bounds;
  138. face = &faces[faceNum];
  139. bounds.Clear();
  140. for ( i = 0; i < face->numEdges; i++ ) {
  141. edgeNum = edgeIndex[ face->firstEdge + i ];
  142. edge = &edges[ abs( edgeNum ) ];
  143. bounds.AddPoint( vertices[ edge->vertexNum[ INT32_SIGNBITSET(edgeNum) ] ] );
  144. }
  145. return bounds;
  146. }
  147. /*
  148. ================
  149. idAASFileLocal::AreaBounds
  150. ================
  151. */
  152. idBounds idAASFileLocal::AreaBounds( int areaNum ) const {
  153. int i, faceNum;
  154. const aasArea_t *area;
  155. idBounds bounds;
  156. area = &areas[areaNum];
  157. bounds.Clear();
  158. for ( i = 0; i < area->numFaces; i++ ) {
  159. faceNum = faceIndex[area->firstFace + i];
  160. bounds += FaceBounds( abs(faceNum) );
  161. }
  162. return bounds;
  163. }
  164. /*
  165. ============
  166. idAASFileLocal::PointAreaNum
  167. ============
  168. */
  169. int idAASFileLocal::PointAreaNum( const idVec3 &origin ) const {
  170. int nodeNum;
  171. const aasNode_t *node;
  172. nodeNum = 1;
  173. do {
  174. node = &nodes[nodeNum];
  175. if ( planeList[node->planeNum].Side( origin ) == PLANESIDE_BACK ) {
  176. nodeNum = node->children[1];
  177. }
  178. else {
  179. nodeNum = node->children[0];
  180. }
  181. if ( nodeNum < 0 ) {
  182. return -nodeNum;
  183. }
  184. } while( nodeNum );
  185. return 0;
  186. }
  187. /*
  188. ============
  189. idAASFileLocal::PointReachableAreaNum
  190. ============
  191. */
  192. int idAASFileLocal::PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags, const int excludeTravelFlags ) const {
  193. int areaList[32], areaNum, i;
  194. idVec3 start, end, pointList[32];
  195. aasTrace_t trace;
  196. idBounds bounds;
  197. float frac;
  198. start = origin;
  199. trace.areas = areaList;
  200. trace.points = pointList;
  201. trace.maxAreas = sizeof( areaList ) / sizeof( int );
  202. trace.getOutOfSolid = true;
  203. areaNum = PointAreaNum( start );
  204. if ( areaNum ) {
  205. if ( ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
  206. return areaNum;
  207. }
  208. }
  209. else {
  210. // trace up
  211. end = start;
  212. end[2] += 32.0f;
  213. Trace( trace, start, end );
  214. if ( trace.numAreas >= 1 ) {
  215. if ( ( areas[0].flags & areaFlags ) && ( ( areas[0].travelFlags & excludeTravelFlags ) == 0 ) ) {
  216. return areaList[0];
  217. }
  218. start = pointList[0];
  219. start[2] += 1.0f;
  220. }
  221. }
  222. // trace down
  223. end = start;
  224. end[2] -= 32.0f;
  225. Trace( trace, start, end );
  226. if ( trace.lastAreaNum ) {
  227. if ( ( areas[trace.lastAreaNum].flags & areaFlags ) && ( ( areas[trace.lastAreaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
  228. return trace.lastAreaNum;
  229. }
  230. start = trace.endpos;
  231. }
  232. // expand bounds until an area is found
  233. for ( i = 1; i <= 12; i++ ) {
  234. frac = i * ( 1.0f / 12.0f );
  235. bounds[0] = origin + searchBounds[0] * frac;
  236. bounds[1] = origin + searchBounds[1] * frac;
  237. areaNum = BoundsReachableAreaNum( bounds, areaFlags, excludeTravelFlags );
  238. if ( areaNum && ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
  239. return areaNum;
  240. }
  241. }
  242. return 0;
  243. }
  244. /*
  245. ============
  246. idAASFileLocal::BoundsReachableAreaNum_r
  247. ============
  248. */
  249. int idAASFileLocal::BoundsReachableAreaNum_r( int nodeNum, const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const {
  250. int res;
  251. const aasNode_t *node;
  252. while( nodeNum ) {
  253. if ( nodeNum < 0 ) {
  254. if ( ( areas[-nodeNum].flags & areaFlags ) && ( ( areas[-nodeNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
  255. return -nodeNum;
  256. }
  257. return 0;
  258. }
  259. node = &nodes[nodeNum];
  260. res = bounds.PlaneSide( planeList[node->planeNum] );
  261. if ( res == PLANESIDE_BACK ) {
  262. nodeNum = node->children[1];
  263. }
  264. else if ( res == PLANESIDE_FRONT ) {
  265. nodeNum = node->children[0];
  266. }
  267. else {
  268. nodeNum = BoundsReachableAreaNum_r( node->children[1], bounds, areaFlags, excludeTravelFlags );
  269. if ( nodeNum ) {
  270. return nodeNum;
  271. }
  272. nodeNum = node->children[0];
  273. }
  274. }
  275. return 0;
  276. }
  277. /*
  278. ============
  279. idAASFileLocal::BoundsReachableAreaNum
  280. ============
  281. */
  282. int idAASFileLocal::BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const {
  283. return BoundsReachableAreaNum_r( 1, bounds, areaFlags, excludeTravelFlags );
  284. }
  285. /*
  286. ============
  287. idAASFileLocal::PushPointIntoAreaNum
  288. ============
  289. */
  290. void idAASFileLocal::PushPointIntoAreaNum( int areaNum, idVec3 &point ) const {
  291. int i, faceNum;
  292. const aasArea_t *area;
  293. const aasFace_t *face;
  294. area = &areas[areaNum];
  295. // push the point to the right side of all area face planes
  296. for ( i = 0; i < area->numFaces; i++ ) {
  297. faceNum = faceIndex[area->firstFace + i];
  298. face = &faces[abs( faceNum )];
  299. const idPlane &plane = planeList[face->planeNum ^ INT32_SIGNBITSET( faceNum )];
  300. float dist = plane.Distance( point );
  301. // project the point onto the face plane if it is on the wrong side
  302. if ( dist < 0.0f ) {
  303. point -= dist * plane.Normal();
  304. }
  305. }
  306. }
  307. /*
  308. ============
  309. idAASFileLocal::Trace
  310. ============
  311. */
  312. #define TRACEPLANE_EPSILON 0.125f
  313. typedef struct aasTraceStack_s
  314. {
  315. idVec3 start;
  316. idVec3 end;
  317. int planeNum;
  318. int nodeNum;
  319. } aasTraceStack_t;
  320. bool idAASFileLocal::Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const {
  321. int side, nodeNum, tmpPlaneNum;
  322. double front, back, frac;
  323. idVec3 cur_start, cur_end, cur_mid, v1, v2;
  324. aasTraceStack_t tracestack[MAX_AAS_TREE_DEPTH];
  325. aasTraceStack_t *tstack_p;
  326. const aasNode_t *node;
  327. const idPlane *plane;
  328. trace.numAreas = 0;
  329. trace.lastAreaNum = 0;
  330. trace.blockingAreaNum = 0;
  331. tstack_p = tracestack;
  332. tstack_p->start = start;
  333. tstack_p->end = end;
  334. tstack_p->planeNum = 0;
  335. tstack_p->nodeNum = 1; //start with the root of the tree
  336. tstack_p++;
  337. while( 1 ) {
  338. tstack_p--;
  339. // if the trace stack is empty
  340. if ( tstack_p < tracestack ) {
  341. if ( !trace.lastAreaNum ) {
  342. // completely in solid
  343. trace.fraction = 0.0f;
  344. trace.endpos = start;
  345. }
  346. else {
  347. // nothing was hit
  348. trace.fraction = 1.0f;
  349. trace.endpos = end;
  350. }
  351. trace.planeNum = 0;
  352. return false;
  353. }
  354. // number of the current node to test the line against
  355. nodeNum = tstack_p->nodeNum;
  356. // if it is an area
  357. if ( nodeNum < 0) {
  358. // if can't enter the area
  359. if ( ( areas[-nodeNum].flags & trace.flags ) || ( areas[-nodeNum].travelFlags & trace.travelFlags ) ) {
  360. if ( !trace.lastAreaNum ) {
  361. trace.fraction = 0.0f;
  362. v1 = vec3_origin;
  363. } else {
  364. v1 = end - start;
  365. v2 = tstack_p->start - start;
  366. trace.fraction = v2.Length() / v1.Length();
  367. }
  368. trace.endpos = tstack_p->start;
  369. trace.blockingAreaNum = -nodeNum;
  370. trace.planeNum = tstack_p->planeNum;
  371. // always take the plane with normal facing towards the trace start
  372. plane = &planeList[trace.planeNum];
  373. if ( v1 * plane->Normal() > 0.0f ) {
  374. trace.planeNum ^= 1;
  375. }
  376. return true;
  377. }
  378. trace.lastAreaNum = -nodeNum;
  379. if ( trace.numAreas < trace.maxAreas ) {
  380. if ( trace.areas ) {
  381. trace.areas[trace.numAreas] = -nodeNum;
  382. }
  383. if ( trace.points ) {
  384. trace.points[trace.numAreas] = tstack_p->start;
  385. }
  386. trace.numAreas++;
  387. }
  388. continue;
  389. }
  390. // if it is a solid leaf
  391. if ( !nodeNum ) {
  392. if ( !trace.lastAreaNum ) {
  393. trace.fraction = 0.0f;
  394. v1 = vec3_origin;
  395. } else {
  396. v1 = end - start;
  397. v2 = tstack_p->start - start;
  398. trace.fraction = v2.Length() / v1.Length();
  399. }
  400. trace.endpos = tstack_p->start;
  401. trace.blockingAreaNum = 0; // hit solid leaf
  402. trace.planeNum = tstack_p->planeNum;
  403. // always take the plane with normal facing towards the trace start
  404. plane = &planeList[trace.planeNum];
  405. if ( v1 * plane->Normal() > 0.0f ) {
  406. trace.planeNum ^= 1;
  407. }
  408. if ( !trace.lastAreaNum && trace.getOutOfSolid ) {
  409. continue;
  410. }
  411. else {
  412. return true;
  413. }
  414. }
  415. // the node to test against
  416. node = &nodes[nodeNum];
  417. // start point of current line to test against node
  418. cur_start = tstack_p->start;
  419. // end point of the current line to test against node
  420. cur_end = tstack_p->end;
  421. // the current node plane
  422. plane = &planeList[node->planeNum];
  423. front = plane->Distance( cur_start );
  424. back = plane->Distance( cur_end );
  425. // if the whole to be traced line is totally at the front of this node
  426. // only go down the tree with the front child
  427. if ( front >= -ON_EPSILON && back >= -ON_EPSILON ) {
  428. // keep the current start and end point on the stack and go down the tree with the front child
  429. tstack_p->nodeNum = node->children[0];
  430. tstack_p++;
  431. if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
  432. common->Error("idAASFileLocal::Trace: stack overflow\n" );
  433. return false;
  434. }
  435. }
  436. // if the whole to be traced line is totally at the back of this node
  437. // only go down the tree with the back child
  438. else if ( front < ON_EPSILON && back < ON_EPSILON ) {
  439. // keep the current start and end point on the stack and go down the tree with the back child
  440. tstack_p->nodeNum = node->children[1];
  441. tstack_p++;
  442. if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
  443. common->Error("idAASFileLocal::Trace: stack overflow\n" );
  444. return false;
  445. }
  446. }
  447. // go down the tree both at the front and back of the node
  448. else {
  449. tmpPlaneNum = tstack_p->planeNum;
  450. // calculate the hit point with the node plane
  451. // put the cross point TRACEPLANE_EPSILON on the near side
  452. if (front < 0) {
  453. frac = (front + TRACEPLANE_EPSILON) / ( front - back );
  454. }
  455. else {
  456. frac = (front - TRACEPLANE_EPSILON) / ( front - back );
  457. }
  458. if (frac < 0) {
  459. frac = 0.001f; //0
  460. }
  461. else if (frac > 1) {
  462. frac = 0.999f; //1
  463. }
  464. cur_mid = cur_start + ( cur_end - cur_start ) * frac;
  465. // side the front part of the line is on
  466. side = front < 0;
  467. // first put the end part of the line on the stack (back side)
  468. tstack_p->start = cur_mid;
  469. tstack_p->planeNum = node->planeNum;
  470. tstack_p->nodeNum = node->children[!side];
  471. tstack_p++;
  472. if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
  473. common->Error("idAASFileLocal::Trace: stack overflow\n" );
  474. return false;
  475. }
  476. // now put the part near the start of the line on the stack so we will
  477. // continue with that part first.
  478. tstack_p->start = cur_start;
  479. tstack_p->end = cur_mid;
  480. tstack_p->planeNum = tmpPlaneNum;
  481. tstack_p->nodeNum = node->children[side];
  482. tstack_p++;
  483. if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
  484. common->Error("idAASFileLocal::Trace: stack overflow\n" );
  485. return false;
  486. }
  487. }
  488. }
  489. return false;
  490. }
  491. /*
  492. ============
  493. idAASLocal::AreaContentsTravelFlags
  494. ============
  495. */
  496. int idAASFileLocal::AreaContentsTravelFlags( int areaNum ) const {
  497. if ( areas[areaNum].contents & AREACONTENTS_WATER ) {
  498. return TFL_WATER;
  499. }
  500. return TFL_AIR;
  501. }
  502. /*
  503. ============
  504. idAASFileLocal::MaxTreeDepth_r
  505. ============
  506. */
  507. void idAASFileLocal::MaxTreeDepth_r( int nodeNum, int &depth, int &maxDepth ) const {
  508. const aasNode_t *node;
  509. if ( nodeNum <= 0 ) {
  510. return;
  511. }
  512. depth++;
  513. if ( depth > maxDepth ) {
  514. maxDepth = depth;
  515. }
  516. node = &nodes[nodeNum];
  517. MaxTreeDepth_r( node->children[0], depth, maxDepth );
  518. MaxTreeDepth_r( node->children[1], depth, maxDepth );
  519. depth--;
  520. }
  521. /*
  522. ============
  523. idAASFileLocal::MaxTreeDepth
  524. ============
  525. */
  526. int idAASFileLocal::MaxTreeDepth() const {
  527. int depth, maxDepth;
  528. depth = maxDepth = 0;
  529. MaxTreeDepth_r( 1, depth, maxDepth );
  530. return maxDepth;
  531. }