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