facebsp.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "qbsp.h"
  19. int c_faceLeafs;
  20. /*
  21. ================
  22. AllocBspFace
  23. ================
  24. */
  25. bspface_t *AllocBspFace( void ) {
  26. bspface_t *f;
  27. f = malloc(sizeof(*f));
  28. memset( f, 0, sizeof(*f) );
  29. return f;
  30. }
  31. /*
  32. ================
  33. FreeBspFace
  34. ================
  35. */
  36. void FreeBspFace( bspface_t *f ) {
  37. if ( f->w ) {
  38. FreeWinding( f->w );
  39. }
  40. free( f );
  41. }
  42. /*
  43. ================
  44. SelectSplitPlaneNum
  45. ================
  46. */
  47. int hintsplit;
  48. #define BLOCK_SIZE 1024
  49. int SelectSplitPlaneNum( node_t *node, bspface_t *list ) {
  50. bspface_t *split;
  51. bspface_t *check;
  52. bspface_t *bestSplit;
  53. int splits, facing, front, back;
  54. int side;
  55. plane_t *plane;
  56. int value, bestValue;
  57. int i;
  58. vec3_t normal;
  59. float dist;
  60. int planenum;
  61. hintsplit = qfalse;
  62. // if it is crossing a 1k block boundary, force a split
  63. for ( i = 0 ; i < 2 ; i++ ) {
  64. dist = BLOCK_SIZE * ( floor( node->mins[i] / BLOCK_SIZE ) + 1 );
  65. if ( node->maxs[i] > dist ) {
  66. VectorClear( normal );
  67. normal[i] = 1;
  68. planenum = FindFloatPlane( normal, dist );
  69. return planenum;
  70. }
  71. }
  72. // pick one of the face planes
  73. bestValue = -99999;
  74. bestSplit = list;
  75. for ( split = list ; split ; split = split->next ) {
  76. split->checked = qfalse;
  77. }
  78. for ( split = list ; split ; split = split->next ) {
  79. if ( split->checked ) {
  80. continue;
  81. }
  82. plane = &mapplanes[ split->planenum ];
  83. splits = 0;
  84. facing = 0;
  85. front = 0;
  86. back = 0;
  87. for ( check = list ; check ; check = check->next ) {
  88. if ( check->planenum == split->planenum ) {
  89. facing++;
  90. check->checked = qtrue; // won't need to test this plane again
  91. continue;
  92. }
  93. side = WindingOnPlaneSide( check->w, plane->normal, plane->dist );
  94. if ( side == SIDE_CROSS ) {
  95. splits++;
  96. } else if ( side == SIDE_FRONT ) {
  97. front++;
  98. } else if ( side == SIDE_BACK ) {
  99. back++;
  100. }
  101. }
  102. value = 5*facing - 5*splits; // - abs(front-back);
  103. if ( plane->type < 3 ) {
  104. value+=5; // axial is better
  105. }
  106. value += split->priority; // prioritize hints higher
  107. if ( value > bestValue ) {
  108. bestValue = value;
  109. bestSplit = split;
  110. }
  111. }
  112. if ( bestValue == -99999 ) {
  113. return -1;
  114. }
  115. if (bestSplit->hint)
  116. hintsplit = qtrue;
  117. return bestSplit->planenum;
  118. }
  119. int CountFaceList( bspface_t *list ) {
  120. int c;
  121. c = 0;
  122. for ( ; list ; list = list->next ) {
  123. c++;
  124. }
  125. return c;
  126. }
  127. /*
  128. ================
  129. BuildFaceTree_r
  130. ================
  131. */
  132. void BuildFaceTree_r( node_t *node, bspface_t *list ) {
  133. bspface_t *split;
  134. bspface_t *next;
  135. int side;
  136. plane_t *plane;
  137. bspface_t *newFace;
  138. bspface_t *childLists[2];
  139. winding_t *frontWinding, *backWinding;
  140. int i;
  141. int splitPlaneNum;
  142. i = CountFaceList( list );
  143. splitPlaneNum = SelectSplitPlaneNum( node, list );
  144. // if we don't have any more faces, this is a node
  145. if ( splitPlaneNum == -1 ) {
  146. node->planenum = PLANENUM_LEAF;
  147. c_faceLeafs++;
  148. return;
  149. }
  150. // partition the list
  151. node->planenum = splitPlaneNum;
  152. node->hint = hintsplit;
  153. plane = &mapplanes[ splitPlaneNum ];
  154. childLists[0] = NULL;
  155. childLists[1] = NULL;
  156. for ( split = list ; split ; split = next ) {
  157. next = split->next;
  158. if ( split->planenum == node->planenum ) {
  159. FreeBspFace( split );
  160. continue;
  161. }
  162. side = WindingOnPlaneSide( split->w, plane->normal, plane->dist );
  163. if ( side == SIDE_CROSS ) {
  164. ClipWindingEpsilon( split->w, plane->normal, plane->dist, CLIP_EPSILON * 2,
  165. &frontWinding, &backWinding );
  166. if ( frontWinding ) {
  167. newFace = AllocBspFace();
  168. newFace->w = frontWinding;
  169. newFace->next = childLists[0];
  170. newFace->planenum = split->planenum;
  171. newFace->priority = split->priority;
  172. newFace->hint = split->hint;
  173. childLists[0] = newFace;
  174. }
  175. if ( backWinding ) {
  176. newFace = AllocBspFace();
  177. newFace->w = backWinding;
  178. newFace->next = childLists[1];
  179. newFace->planenum = split->planenum;
  180. newFace->priority = split->priority;
  181. newFace->hint = split->hint;
  182. childLists[1] = newFace;
  183. }
  184. FreeBspFace( split );
  185. } else if ( side == SIDE_FRONT ) {
  186. split->next = childLists[0];
  187. childLists[0] = split;
  188. } else if ( side == SIDE_BACK ) {
  189. split->next = childLists[1];
  190. childLists[1] = split;
  191. }
  192. }
  193. // recursively process children
  194. for ( i = 0 ; i < 2 ; i++ ) {
  195. node->children[i] = AllocNode();
  196. node->children[i]->parent = node;
  197. VectorCopy( node->mins, node->children[i]->mins );
  198. VectorCopy( node->maxs, node->children[i]->maxs );
  199. }
  200. for ( i = 0 ; i < 3 ; i++ ) {
  201. if ( plane->normal[i] == 1 ) {
  202. node->children[0]->mins[i] = plane->dist;
  203. node->children[1]->maxs[i] = plane->dist;
  204. break;
  205. }
  206. }
  207. for ( i = 0 ; i < 2 ; i++ ) {
  208. BuildFaceTree_r ( node->children[i], childLists[i]);
  209. }
  210. }
  211. /*
  212. ================
  213. FaceBSP
  214. List will be freed before returning
  215. ================
  216. */
  217. tree_t *FaceBSP( bspface_t *list ) {
  218. tree_t *tree;
  219. bspface_t *face;
  220. int i;
  221. int count;
  222. qprintf( "--- FaceBSP ---\n" );
  223. tree = AllocTree ();
  224. count = 0;
  225. for ( face = list ; face ; face = face->next ) {
  226. count++;
  227. for ( i = 0 ; i < face->w->numpoints ; i++ ) {
  228. AddPointToBounds( face->w->p[i], tree->mins, tree->maxs);
  229. }
  230. }
  231. qprintf( "%5i faces\n", count );
  232. tree->headnode = AllocNode();
  233. VectorCopy( tree->mins, tree->headnode->mins );
  234. VectorCopy( tree->maxs, tree->headnode->maxs );
  235. c_faceLeafs = 0;
  236. BuildFaceTree_r ( tree->headnode, list );
  237. qprintf( "%5i leafs\n", c_faceLeafs );
  238. return tree;
  239. }
  240. /*
  241. =================
  242. BspFaceForPortal
  243. =================
  244. */
  245. bspface_t *BspFaceForPortal( portal_t *p ) {
  246. bspface_t *f;
  247. f = AllocBspFace();
  248. f->w = CopyWinding( p->winding );
  249. f->planenum = p->onnode->planenum & ~1;
  250. return f;
  251. }
  252. /*
  253. =================
  254. MakeStructuralBspFaceList
  255. =================
  256. */
  257. bspface_t *MakeStructuralBspFaceList( bspbrush_t *list ) {
  258. bspbrush_t *b;
  259. int i;
  260. side_t *s;
  261. winding_t *w;
  262. bspface_t *f, *flist;
  263. flist = NULL;
  264. for ( b = list ; b ; b = b->next ) {
  265. if ( b->detail ) {
  266. continue;
  267. }
  268. for ( i = 0 ; i < b->numsides ; i++ ) {
  269. s = &b->sides[i];
  270. w = s->winding;
  271. if ( !w ) {
  272. continue;
  273. }
  274. f = AllocBspFace();
  275. f->w = CopyWinding( w );
  276. f->planenum = s->planenum & ~1;
  277. f->next = flist;
  278. if (s->surfaceFlags & SURF_HINT) {
  279. //f->priority = HINT_PRIORITY;
  280. f->hint = qtrue;
  281. }
  282. flist = f;
  283. }
  284. }
  285. return flist;
  286. }
  287. /*
  288. =================
  289. MakeVisibleBspFaceList
  290. =================
  291. */
  292. bspface_t *MakeVisibleBspFaceList( bspbrush_t *list ) {
  293. bspbrush_t *b;
  294. int i;
  295. side_t *s;
  296. winding_t *w;
  297. bspface_t *f, *flist;
  298. flist = NULL;
  299. for ( b = list ; b ; b = b->next ) {
  300. if ( b->detail ) {
  301. continue;
  302. }
  303. for ( i = 0 ; i < b->numsides ; i++ ) {
  304. s = &b->sides[i];
  305. w = s->visibleHull;
  306. if ( !w ) {
  307. continue;
  308. }
  309. f = AllocBspFace();
  310. f->w = CopyWinding( w );
  311. f->planenum = s->planenum & ~1;
  312. f->next = flist;
  313. if (s->surfaceFlags & SURF_HINT) {
  314. //f->priority = HINT_PRIORITY;
  315. f->hint = qtrue;
  316. }
  317. flist = f;
  318. }
  319. }
  320. return flist;
  321. }