AASBuild_file.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 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. #include "../../../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "AASBuild_local.h"
  23. #define VERTEX_HASH_BOXSIZE (1<<6) // must be power of 2
  24. #define VERTEX_HASH_SIZE (VERTEX_HASH_BOXSIZE*VERTEX_HASH_BOXSIZE)
  25. #define EDGE_HASH_SIZE (1<<14)
  26. #define INTEGRAL_EPSILON 0.01f
  27. #define VERTEX_EPSILON 0.1f
  28. #define AAS_PLANE_NORMAL_EPSILON 0.00001f
  29. #define AAS_PLANE_DIST_EPSILON 0.01f
  30. idHashIndex *aas_vertexHash;
  31. idHashIndex *aas_edgeHash;
  32. idBounds aas_vertexBounds;
  33. int aas_vertexShift;
  34. /*
  35. ================
  36. idAASBuild::SetupHash
  37. ================
  38. */
  39. void idAASBuild::SetupHash( void ) {
  40. aas_vertexHash = new idHashIndex( VERTEX_HASH_SIZE, 1024 );
  41. aas_edgeHash = new idHashIndex( EDGE_HASH_SIZE, 1024 );
  42. }
  43. /*
  44. ================
  45. idAASBuild::ShutdownHash
  46. ================
  47. */
  48. void idAASBuild::ShutdownHash( void ) {
  49. delete aas_vertexHash;
  50. delete aas_edgeHash;
  51. }
  52. /*
  53. ================
  54. idAASBuild::ClearHash
  55. ================
  56. */
  57. void idAASBuild::ClearHash( const idBounds &bounds ) {
  58. int i;
  59. float f, max;
  60. aas_vertexHash->Clear();
  61. aas_edgeHash->Clear();
  62. aas_vertexBounds = bounds;
  63. max = bounds[1].x - bounds[0].x;
  64. f = bounds[1].y - bounds[0].y;
  65. if ( f > max ) {
  66. max = f;
  67. }
  68. aas_vertexShift = (float) max / VERTEX_HASH_BOXSIZE;
  69. for ( i = 0; (1<<i) < aas_vertexShift; i++ ) {
  70. }
  71. if ( i == 0 ) {
  72. aas_vertexShift = 1;
  73. }
  74. else {
  75. aas_vertexShift = i;
  76. }
  77. }
  78. /*
  79. ================
  80. idAASBuild::HashVec
  81. ================
  82. */
  83. ID_INLINE int idAASBuild::HashVec( const idVec3 &vec ) {
  84. int x, y;
  85. x = (((int) (vec[0] - aas_vertexBounds[0].x + 0.5)) + 2) >> 2;
  86. y = (((int) (vec[1] - aas_vertexBounds[0].y + 0.5)) + 2) >> 2;
  87. return (x + y * VERTEX_HASH_BOXSIZE) & (VERTEX_HASH_SIZE-1);
  88. }
  89. /*
  90. ================
  91. idAASBuild::GetVertex
  92. ================
  93. */
  94. bool idAASBuild::GetVertex( const idVec3 &v, int *vertexNum ) {
  95. int i, hashKey, vn;
  96. aasVertex_t vert, *p;
  97. for (i = 0; i < 3; i++) {
  98. if ( idMath::Fabs(v[i] - idMath::Rint(v[i])) < INTEGRAL_EPSILON ) {
  99. vert[i] = idMath::Rint(v[i]);
  100. }
  101. else {
  102. vert[i] = v[i];
  103. }
  104. }
  105. hashKey = idAASBuild::HashVec( vert );
  106. for ( vn = aas_vertexHash->First( hashKey ); vn >= 0; vn = aas_vertexHash->Next( vn ) ) {
  107. p = &file->vertices[vn];
  108. // first compare z-axis because hash is based on x-y plane
  109. if (idMath::Fabs( vert.z - p->z ) < VERTEX_EPSILON &&
  110. idMath::Fabs( vert.x - p->x ) < VERTEX_EPSILON &&
  111. idMath::Fabs( vert.y - p->y ) < VERTEX_EPSILON )
  112. {
  113. *vertexNum = vn;
  114. return true;
  115. }
  116. }
  117. *vertexNum = file->vertices.Num();
  118. aas_vertexHash->Add( hashKey, file->vertices.Num() );
  119. file->vertices.Append( vert );
  120. return false;
  121. }
  122. /*
  123. ================
  124. idAASBuild::GetEdge
  125. ================
  126. */
  127. bool idAASBuild::GetEdge( const idVec3 &v1, const idVec3 &v2, int *edgeNum, int v1num ) {
  128. int v2num, hashKey, e;
  129. int *vertexNum;
  130. aasEdge_t edge;
  131. bool found;
  132. if ( v1num != -1 ) {
  133. found = true;
  134. }
  135. else {
  136. found = GetVertex( v1, &v1num );
  137. }
  138. found &= GetVertex( v2, &v2num );
  139. // if both vertexes are the same or snapped onto each other
  140. if ( v1num == v2num ) {
  141. *edgeNum = 0;
  142. return true;
  143. }
  144. hashKey = aas_edgeHash->GenerateKey( v1num, v2num );
  145. // if both vertexes where already stored
  146. if ( found ) {
  147. for ( e = aas_edgeHash->First( hashKey ); e >= 0; e = aas_edgeHash->Next( e ) ) {
  148. vertexNum = file->edges[e].vertexNum;
  149. if ( vertexNum[0] == v2num ) {
  150. if ( vertexNum[1] == v1num ) {
  151. // negative for a reversed edge
  152. *edgeNum = -e;
  153. break;
  154. }
  155. }
  156. else if ( vertexNum[0] == v1num ) {
  157. if ( vertexNum[1] == v2num ) {
  158. *edgeNum = e;
  159. break;
  160. }
  161. }
  162. }
  163. // if edge found in hash
  164. if ( e >= 0 ) {
  165. return true;
  166. }
  167. }
  168. *edgeNum = file->edges.Num();
  169. aas_edgeHash->Add( hashKey, file->edges.Num() );
  170. edge.vertexNum[0] = v1num;
  171. edge.vertexNum[1] = v2num;
  172. file->edges.Append( edge );
  173. return false;
  174. }
  175. /*
  176. ================
  177. idAASBuild::GetFaceForPortal
  178. ================
  179. */
  180. bool idAASBuild::GetFaceForPortal( idBrushBSPPortal *portal, int side, int *faceNum ) {
  181. int i, j, v1num;
  182. int numFaceEdges, faceEdges[MAX_POINTS_ON_WINDING];
  183. idWinding *w;
  184. aasFace_t face;
  185. if ( portal->GetFaceNum() > 0 ) {
  186. if ( side ) {
  187. *faceNum = -portal->GetFaceNum();
  188. }
  189. else {
  190. *faceNum = portal->GetFaceNum();
  191. }
  192. return true;
  193. }
  194. w = portal->GetWinding();
  195. // turn the winding into a sequence of edges
  196. numFaceEdges = 0;
  197. v1num = -1; // first vertex unknown
  198. for ( i = 0; i < w->GetNumPoints(); i++ ) {
  199. GetEdge( (*w)[i].ToVec3(), (*w)[(i+1)%w->GetNumPoints()].ToVec3(), &faceEdges[numFaceEdges], v1num );
  200. if ( faceEdges[numFaceEdges] ) {
  201. // last vertex of this edge is the first vertex of the next edge
  202. v1num = file->edges[ abs(faceEdges[numFaceEdges]) ].vertexNum[ INTSIGNBITNOTSET(faceEdges[numFaceEdges]) ];
  203. // this edge is valid so keep it
  204. numFaceEdges++;
  205. }
  206. }
  207. // should have at least 3 edges
  208. if ( numFaceEdges < 3 ) {
  209. return false;
  210. }
  211. // the polygon is invalid if some edge is found twice
  212. for ( i = 0; i < numFaceEdges; i++ ) {
  213. for ( j = i+1; j < numFaceEdges; j++ ) {
  214. if ( faceEdges[i] == faceEdges[j] || faceEdges[i] == -faceEdges[j] ) {
  215. return false;
  216. }
  217. }
  218. }
  219. portal->SetFaceNum( file->faces.Num() );
  220. face.planeNum = file->planeList.FindPlane( portal->GetPlane(), AAS_PLANE_NORMAL_EPSILON, AAS_PLANE_DIST_EPSILON );
  221. face.flags = portal->GetFlags();
  222. face.areas[0] = face.areas[1] = 0;
  223. face.firstEdge = file->edgeIndex.Num();
  224. face.numEdges = numFaceEdges;
  225. for ( i = 0; i < numFaceEdges; i++ ) {
  226. file->edgeIndex.Append( faceEdges[i] );
  227. }
  228. if ( side ) {
  229. *faceNum = -file->faces.Num();
  230. }
  231. else {
  232. *faceNum = file->faces.Num();
  233. }
  234. file->faces.Append( face );
  235. return true;
  236. }
  237. /*
  238. ================
  239. idAASBuild::GetAreaForLeafNode
  240. ================
  241. */
  242. bool idAASBuild::GetAreaForLeafNode( idBrushBSPNode *node, int *areaNum ) {
  243. int s, faceNum;
  244. idBrushBSPPortal *p;
  245. aasArea_t area;
  246. if ( node->GetAreaNum() ) {
  247. *areaNum = -node->GetAreaNum();
  248. return true;
  249. }
  250. area.flags = node->GetFlags();
  251. area.cluster = area.clusterAreaNum = 0;
  252. area.contents = node->GetContents();
  253. area.firstFace = file->faceIndex.Num();
  254. area.numFaces = 0;
  255. area.reach = NULL;
  256. area.rev_reach = NULL;
  257. for ( p = node->GetPortals(); p; p = p->Next(s) ) {
  258. s = (p->GetNode(1) == node);
  259. if ( !GetFaceForPortal( p, s, &faceNum ) ) {
  260. continue;
  261. }
  262. file->faceIndex.Append( faceNum );
  263. area.numFaces++;
  264. if ( faceNum > 0 ) {
  265. file->faces[abs(faceNum)].areas[0] = file->areas.Num();
  266. }
  267. else {
  268. file->faces[abs(faceNum)].areas[1] = file->areas.Num();
  269. }
  270. }
  271. if ( !area.numFaces ) {
  272. *areaNum = 0;
  273. return false;
  274. }
  275. *areaNum = -file->areas.Num();
  276. node->SetAreaNum( file->areas.Num() );
  277. file->areas.Append( area );
  278. DisplayRealTimeString( "\r%6d", file->areas.Num() );
  279. return true;
  280. }
  281. /*
  282. ================
  283. idAASBuild::StoreTree_r
  284. ================
  285. */
  286. int idAASBuild::StoreTree_r( idBrushBSPNode *node ) {
  287. int areaNum, nodeNum, child0, child1;
  288. aasNode_t aasNode;
  289. if ( !node ) {
  290. return 0;
  291. }
  292. if ( node->GetContents() & AREACONTENTS_SOLID ) {
  293. return 0;
  294. }
  295. if ( !node->GetChild(0) && !node->GetChild(1) ) {
  296. if ( GetAreaForLeafNode( node, &areaNum ) ) {
  297. return areaNum;
  298. }
  299. return 0;
  300. }
  301. aasNode.planeNum = file->planeList.FindPlane( node->GetPlane(), AAS_PLANE_NORMAL_EPSILON, AAS_PLANE_DIST_EPSILON );
  302. aasNode.children[0] = aasNode.children[1] = 0;
  303. nodeNum = file->nodes.Num();
  304. file->nodes.Append( aasNode );
  305. // !@#$%^ cause of some bug we cannot set the children directly with the StoreTree_r return value
  306. child0 = StoreTree_r( node->GetChild(0) );
  307. file->nodes[nodeNum].children[0] = child0;
  308. child1 = StoreTree_r( node->GetChild(1) );
  309. file->nodes[nodeNum].children[1] = child1;
  310. if ( !child0 && !child1 ) {
  311. file->nodes.SetNum( file->nodes.Num()-1 );
  312. return 0;
  313. }
  314. return nodeNum;
  315. }
  316. /*
  317. ================
  318. idAASBuild::GetSizeEstimate_r
  319. ================
  320. */
  321. typedef struct sizeEstimate_s {
  322. int numEdgeIndexes;
  323. int numFaceIndexes;
  324. int numAreas;
  325. int numNodes;
  326. } sizeEstimate_t;
  327. void idAASBuild::GetSizeEstimate_r( idBrushBSPNode *parent, idBrushBSPNode *node, struct sizeEstimate_s &size ) {
  328. idBrushBSPPortal *p;
  329. int s;
  330. if ( !node ) {
  331. return;
  332. }
  333. if ( node->GetContents() & AREACONTENTS_SOLID ) {
  334. return;
  335. }
  336. if ( !node->GetChild(0) && !node->GetChild(1) ) {
  337. // multiple branches of the bsp tree might point to the same leaf node
  338. if ( node->GetParent() == parent ) {
  339. size.numAreas++;
  340. for ( p = node->GetPortals(); p; p = p->Next(s) ) {
  341. s = (p->GetNode(1) == node);
  342. size.numFaceIndexes++;
  343. size.numEdgeIndexes += p->GetWinding()->GetNumPoints();
  344. }
  345. }
  346. }
  347. else {
  348. size.numNodes++;
  349. }
  350. GetSizeEstimate_r( node, node->GetChild(0), size );
  351. GetSizeEstimate_r( node, node->GetChild(1), size );
  352. }
  353. /*
  354. ================
  355. idAASBuild::SetSizeEstimate
  356. ================
  357. */
  358. void idAASBuild::SetSizeEstimate( const idBrushBSP &bsp, idAASFileLocal *file ) {
  359. sizeEstimate_t size;
  360. size.numEdgeIndexes = 1;
  361. size.numFaceIndexes = 1;
  362. size.numAreas = 1;
  363. size.numNodes = 1;
  364. GetSizeEstimate_r( NULL, bsp.GetRootNode(), size );
  365. file->planeList.Resize( size.numNodes / 2, 1024 );
  366. file->vertices.Resize( size.numEdgeIndexes / 3, 1024 );
  367. file->edges.Resize( size.numEdgeIndexes / 2, 1024 );
  368. file->edgeIndex.Resize( size.numEdgeIndexes, 4096 );
  369. file->faces.Resize( size.numFaceIndexes, 1024 );
  370. file->faceIndex.Resize( size.numFaceIndexes, 4096 );
  371. file->areas.Resize( size.numAreas, 1024 );
  372. file->nodes.Resize( size.numNodes, 1024 );
  373. }
  374. /*
  375. ================
  376. idAASBuild::StoreFile
  377. ================
  378. */
  379. bool idAASBuild::StoreFile( const idBrushBSP &bsp ) {
  380. aasEdge_t edge;
  381. aasFace_t face;
  382. aasArea_t area;
  383. aasNode_t node;
  384. common->Printf( "[Store AAS]\n" );
  385. SetupHash();
  386. ClearHash( bsp.GetTreeBounds() );
  387. file = new idAASFileLocal();
  388. file->Clear();
  389. SetSizeEstimate( bsp, file );
  390. // the first edge is a dummy
  391. memset( &edge, 0, sizeof( edge ) );
  392. file->edges.Append( edge );
  393. // the first face is a dummy
  394. memset( &face, 0, sizeof( face ) );
  395. file->faces.Append( face );
  396. // the first area is a dummy
  397. memset( &area, 0, sizeof( area ) );
  398. file->areas.Append( area );
  399. // the first node is a dummy
  400. memset( &node, 0, sizeof( node ) );
  401. file->nodes.Append( node );
  402. // store the tree
  403. StoreTree_r( bsp.GetRootNode() );
  404. // calculate area bounds and a reachable point in the area
  405. file->FinishAreas();
  406. ShutdownHash();
  407. common->Printf( "\r%6d areas\n", file->areas.Num() );
  408. return true;
  409. }