Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

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