Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

r_bsp.c (14300B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 // r_bsp.c
     21 
     22 #include "r_local.h"
     23 
     24 //
     25 // current entity info
     26 //
     27 qboolean		insubmodel;
     28 entity_t		*currententity;
     29 vec3_t			modelorg;		// modelorg is the viewpoint reletive to
     30 								// the currently rendering entity
     31 vec3_t			r_entorigin;	// the currently rendering entity in world
     32 								// coordinates
     33 
     34 float			entity_rotation[3][3];
     35 
     36 int				r_currentbkey;
     37 
     38 typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t;
     39 
     40 #define MAX_BMODEL_VERTS	500			// 6K
     41 #define MAX_BMODEL_EDGES	1000		// 12K
     42 
     43 static mvertex_t	*pbverts;
     44 static bedge_t		*pbedges;
     45 static int			numbverts, numbedges;
     46 
     47 static mvertex_t	*pfrontenter, *pfrontexit;
     48 
     49 static qboolean		makeclippededge;
     50 
     51 
     52 //===========================================================================
     53 
     54 /*
     55 ================
     56 R_EntityRotate
     57 ================
     58 */
     59 void R_EntityRotate (vec3_t vec)
     60 {
     61 	vec3_t	tvec;
     62 
     63 	VectorCopy (vec, tvec);
     64 	vec[0] = DotProduct (entity_rotation[0], tvec);
     65 	vec[1] = DotProduct (entity_rotation[1], tvec);
     66 	vec[2] = DotProduct (entity_rotation[2], tvec);
     67 }
     68 
     69 
     70 /*
     71 ================
     72 R_RotateBmodel
     73 ================
     74 */
     75 void R_RotateBmodel (void)
     76 {
     77 	float	angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
     78 
     79 // TODO: should use a look-up table
     80 // TODO: should really be stored with the entity instead of being reconstructed
     81 // TODO: could cache lazily, stored in the entity
     82 // TODO: share work with R_SetUpAliasTransform
     83 
     84 // yaw
     85 	angle = currententity->angles[YAW];		
     86 	angle = angle * M_PI*2 / 360;
     87 	s = sin(angle);
     88 	c = cos(angle);
     89 
     90 	temp1[0][0] = c;
     91 	temp1[0][1] = s;
     92 	temp1[0][2] = 0;
     93 	temp1[1][0] = -s;
     94 	temp1[1][1] = c;
     95 	temp1[1][2] = 0;
     96 	temp1[2][0] = 0;
     97 	temp1[2][1] = 0;
     98 	temp1[2][2] = 1;
     99 
    100 
    101 // pitch
    102 	angle = currententity->angles[PITCH];		
    103 	angle = angle * M_PI*2 / 360;
    104 	s = sin(angle);
    105 	c = cos(angle);
    106 
    107 	temp2[0][0] = c;
    108 	temp2[0][1] = 0;
    109 	temp2[0][2] = -s;
    110 	temp2[1][0] = 0;
    111 	temp2[1][1] = 1;
    112 	temp2[1][2] = 0;
    113 	temp2[2][0] = s;
    114 	temp2[2][1] = 0;
    115 	temp2[2][2] = c;
    116 
    117 	R_ConcatRotations (temp2, temp1, temp3);
    118 
    119 // roll
    120 	angle = currententity->angles[ROLL];		
    121 	angle = angle * M_PI*2 / 360;
    122 	s = sin(angle);
    123 	c = cos(angle);
    124 
    125 	temp1[0][0] = 1;
    126 	temp1[0][1] = 0;
    127 	temp1[0][2] = 0;
    128 	temp1[1][0] = 0;
    129 	temp1[1][1] = c;
    130 	temp1[1][2] = s;
    131 	temp1[2][0] = 0;
    132 	temp1[2][1] = -s;
    133 	temp1[2][2] = c;
    134 
    135 	R_ConcatRotations (temp1, temp3, entity_rotation);
    136 
    137 //
    138 // rotate modelorg and the transformation matrix
    139 //
    140 	R_EntityRotate (modelorg);
    141 	R_EntityRotate (vpn);
    142 	R_EntityRotate (vright);
    143 	R_EntityRotate (vup);
    144 
    145 	R_TransformFrustum ();
    146 }
    147 
    148 
    149 /*
    150 ================
    151 R_RecursiveClipBPoly
    152 
    153 Clip a bmodel poly down the world bsp tree
    154 ================
    155 */
    156 void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
    157 {
    158 	bedge_t		*psideedges[2], *pnextedge, *ptedge;
    159 	int			i, side, lastside;
    160 	float		dist, frac, lastdist;
    161 	mplane_t	*splitplane, tplane;
    162 	mvertex_t	*pvert, *plastvert, *ptvert;
    163 	mnode_t		*pn;
    164 	int			area;
    165 
    166 	psideedges[0] = psideedges[1] = NULL;
    167 
    168 	makeclippededge = false;
    169 
    170 // transform the BSP plane into model space
    171 // FIXME: cache these?
    172 	splitplane = pnode->plane;
    173 	tplane.dist = splitplane->dist -
    174 			DotProduct(r_entorigin, splitplane->normal);
    175 	tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
    176 	tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
    177 	tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
    178 
    179 // clip edges to BSP plane
    180 	for ( ; pedges ; pedges = pnextedge)
    181 	{
    182 		pnextedge = pedges->pnext;
    183 
    184 	// set the status for the last point as the previous point
    185 	// FIXME: cache this stuff somehow?
    186 		plastvert = pedges->v[0];
    187 		lastdist = DotProduct (plastvert->position, tplane.normal) -
    188 				   tplane.dist;
    189 
    190 		if (lastdist > 0)
    191 			lastside = 0;
    192 		else
    193 			lastside = 1;
    194 
    195 		pvert = pedges->v[1];
    196 
    197 		dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
    198 
    199 		if (dist > 0)
    200 			side = 0;
    201 		else
    202 			side = 1;
    203 
    204 		if (side != lastside)
    205 		{
    206 		// clipped
    207 			if (numbverts >= MAX_BMODEL_VERTS)
    208 				return;
    209 
    210 		// generate the clipped vertex
    211 			frac = lastdist / (lastdist - dist);
    212 			ptvert = &pbverts[numbverts++];
    213 			ptvert->position[0] = plastvert->position[0] +
    214 					frac * (pvert->position[0] -
    215 					plastvert->position[0]);
    216 			ptvert->position[1] = plastvert->position[1] +
    217 					frac * (pvert->position[1] -
    218 					plastvert->position[1]);
    219 			ptvert->position[2] = plastvert->position[2] +
    220 					frac * (pvert->position[2] -
    221 					plastvert->position[2]);
    222 
    223 		// split into two edges, one on each side, and remember entering
    224 		// and exiting points
    225 		// FIXME: share the clip edge by having a winding direction flag?
    226 			if (numbedges >= (MAX_BMODEL_EDGES - 1))
    227 			{
    228 				ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
    229 				return;
    230 			}
    231 
    232 			ptedge = &pbedges[numbedges];
    233 			ptedge->pnext = psideedges[lastside];
    234 			psideedges[lastside] = ptedge;
    235 			ptedge->v[0] = plastvert;
    236 			ptedge->v[1] = ptvert;
    237 
    238 			ptedge = &pbedges[numbedges + 1];
    239 			ptedge->pnext = psideedges[side];
    240 			psideedges[side] = ptedge;
    241 			ptedge->v[0] = ptvert;
    242 			ptedge->v[1] = pvert;
    243 
    244 			numbedges += 2;
    245 
    246 			if (side == 0)
    247 			{
    248 			// entering for front, exiting for back
    249 				pfrontenter = ptvert;
    250 				makeclippededge = true;
    251 			}
    252 			else
    253 			{
    254 				pfrontexit = ptvert;
    255 				makeclippededge = true;
    256 			}
    257 		}
    258 		else
    259 		{
    260 		// add the edge to the appropriate side
    261 			pedges->pnext = psideedges[side];
    262 			psideedges[side] = pedges;
    263 		}
    264 	}
    265 
    266 // if anything was clipped, reconstitute and add the edges along the clip
    267 // plane to both sides (but in opposite directions)
    268 	if (makeclippededge)
    269 	{
    270 		if (numbedges >= (MAX_BMODEL_EDGES - 2))
    271 		{
    272 			ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
    273 			return;
    274 		}
    275 
    276 		ptedge = &pbedges[numbedges];
    277 		ptedge->pnext = psideedges[0];
    278 		psideedges[0] = ptedge;
    279 		ptedge->v[0] = pfrontexit;
    280 		ptedge->v[1] = pfrontenter;
    281 
    282 		ptedge = &pbedges[numbedges + 1];
    283 		ptedge->pnext = psideedges[1];
    284 		psideedges[1] = ptedge;
    285 		ptedge->v[0] = pfrontenter;
    286 		ptedge->v[1] = pfrontexit;
    287 
    288 		numbedges += 2;
    289 	}
    290 
    291 // draw or recurse further
    292 	for (i=0 ; i<2 ; i++)
    293 	{
    294 		if (psideedges[i])
    295 		{
    296 		// draw if we've reached a non-solid leaf, done if all that's left is a
    297 		// solid leaf, and continue down the tree if it's not a leaf
    298 			pn = pnode->children[i];
    299 
    300 		// we're done with this branch if the node or leaf isn't in the PVS
    301 			if (pn->visframe == r_visframecount)
    302 			{
    303 				if (pn->contents != CONTENTS_NODE)
    304 				{
    305 					if (pn->contents != CONTENTS_SOLID)
    306 					{
    307 						if (r_newrefdef.areabits)
    308 						{
    309 							area = ((mleaf_t *)pn)->area;
    310 							if (! (r_newrefdef.areabits[area>>3] & (1<<(area&7)) ) )
    311 								continue;		// not visible
    312 						}
    313 
    314 						r_currentbkey = ((mleaf_t *)pn)->key;
    315 						R_RenderBmodelFace (psideedges[i], psurf);
    316 					}
    317 				}
    318 				else
    319 				{
    320 					R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
    321 									  psurf);
    322 				}
    323 			}
    324 		}
    325 	}
    326 }
    327 
    328 
    329 /*
    330 ================
    331 R_DrawSolidClippedSubmodelPolygons
    332 
    333 Bmodel crosses multiple leafs
    334 ================
    335 */
    336 void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode)
    337 {
    338 	int			i, j, lindex;
    339 	vec_t		dot;
    340 	msurface_t	*psurf;
    341 	int			numsurfaces;
    342 	mplane_t	*pplane;
    343 	mvertex_t	bverts[MAX_BMODEL_VERTS];
    344 	bedge_t		bedges[MAX_BMODEL_EDGES], *pbedge;
    345 	medge_t		*pedge, *pedges;
    346 
    347 // FIXME: use bounding-box-based frustum clipping info?
    348 
    349 	psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
    350 	numsurfaces = pmodel->nummodelsurfaces;
    351 	pedges = pmodel->edges;
    352 
    353 	for (i=0 ; i<numsurfaces ; i++, psurf++)
    354 	{
    355 	// find which side of the node we are on
    356 		pplane = psurf->plane;
    357 
    358 		dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
    359 
    360 	// draw the polygon
    361 		if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
    362 			((psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
    363 			continue;
    364 
    365 	// FIXME: use bounding-box-based frustum clipping info?
    366 
    367 	// copy the edges to bedges, flipping if necessary so always
    368 	// clockwise winding
    369 	// FIXME: if edges and vertices get caches, these assignments must move
    370 	// outside the loop, and overflow checking must be done here
    371 		pbverts = bverts;
    372 		pbedges = bedges;
    373 		numbverts = numbedges = 0;
    374 		pbedge = &bedges[numbedges];
    375 		numbedges += psurf->numedges;
    376 
    377 		for (j=0 ; j<psurf->numedges ; j++)
    378 		{
    379 		   lindex = pmodel->surfedges[psurf->firstedge+j];
    380 
    381 			if (lindex > 0)
    382 			{
    383 				pedge = &pedges[lindex];
    384 				pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
    385 				pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
    386 			}
    387 			else
    388 			{
    389 				lindex = -lindex;
    390 				pedge = &pedges[lindex];
    391 				pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
    392 				pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
    393 			}
    394 
    395 			pbedge[j].pnext = &pbedge[j+1];
    396 		}
    397 
    398 		pbedge[j-1].pnext = NULL;	// mark end of edges
    399 
    400 		if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) )
    401 			R_RecursiveClipBPoly (pbedge, topnode, psurf);
    402 		else
    403 			R_RenderBmodelFace( pbedge, psurf );
    404 	}
    405 }
    406 
    407 
    408 /*
    409 ================
    410 R_DrawSubmodelPolygons
    411 
    412 All in one leaf
    413 ================
    414 */
    415 void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode)
    416 {
    417 	int			i;
    418 	vec_t		dot;
    419 	msurface_t	*psurf;
    420 	int			numsurfaces;
    421 	mplane_t	*pplane;
    422 
    423 // FIXME: use bounding-box-based frustum clipping info?
    424 
    425 	psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
    426 	numsurfaces = pmodel->nummodelsurfaces;
    427 
    428 	for (i=0 ; i<numsurfaces ; i++, psurf++)
    429 	{
    430 	// find which side of the node we are on
    431 		pplane = psurf->plane;
    432 
    433 		dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
    434 
    435 	// draw the polygon
    436 		if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
    437 			(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
    438 		{
    439 			r_currentkey = ((mleaf_t *)topnode)->key;
    440 
    441 		// FIXME: use bounding-box-based frustum clipping info?
    442 			R_RenderFace (psurf, clipflags);
    443 		}
    444 	}
    445 }
    446 
    447 
    448 int c_drawnode;
    449 
    450 /*
    451 ================
    452 R_RecursiveWorldNode
    453 ================
    454 */
    455 void R_RecursiveWorldNode (mnode_t *node, int clipflags)
    456 {
    457 	int			i, c, side, *pindex;
    458 	vec3_t		acceptpt, rejectpt;
    459 	mplane_t	*plane;
    460 	msurface_t	*surf, **mark;
    461 	float		d, dot;
    462 	mleaf_t		*pleaf;
    463 
    464 	if (node->contents == CONTENTS_SOLID)
    465 		return;		// solid
    466 
    467 	if (node->visframe != r_visframecount)
    468 		return;
    469 
    470 // cull the clipping planes if not trivial accept
    471 // FIXME: the compiler is doing a lousy job of optimizing here; it could be
    472 //  twice as fast in ASM
    473 	if (clipflags)
    474 	{
    475 		for (i=0 ; i<4 ; i++)
    476 		{
    477 			if (! (clipflags & (1<<i)) )
    478 				continue;	// don't need to clip against it
    479 
    480 		// generate accept and reject points
    481 		// FIXME: do with fast look-ups or integer tests based on the sign bit
    482 		// of the floating point values
    483 
    484 			pindex = pfrustum_indexes[i];
    485 
    486 			rejectpt[0] = (float)node->minmaxs[pindex[0]];
    487 			rejectpt[1] = (float)node->minmaxs[pindex[1]];
    488 			rejectpt[2] = (float)node->minmaxs[pindex[2]];
    489 			
    490 			d = DotProduct (rejectpt, view_clipplanes[i].normal);
    491 			d -= view_clipplanes[i].dist;
    492 			if (d <= 0)
    493 				return;
    494 			acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
    495 			acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
    496 			acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
    497 
    498 			d = DotProduct (acceptpt, view_clipplanes[i].normal);
    499 			d -= view_clipplanes[i].dist;
    500 
    501 			if (d >= 0)
    502 				clipflags &= ~(1<<i);	// node is entirely on screen
    503 		}
    504 	}
    505 
    506 c_drawnode++;
    507 
    508 // if a leaf node, draw stuff
    509 	if (node->contents != -1)
    510 	{
    511 		pleaf = (mleaf_t *)node;
    512 
    513 		// check for door connected areas
    514 		if (r_newrefdef.areabits)
    515 		{
    516 			if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
    517 				return;		// not visible
    518 		}
    519 
    520 		mark = pleaf->firstmarksurface;
    521 		c = pleaf->nummarksurfaces;
    522 
    523 		if (c)
    524 		{
    525 			do
    526 			{
    527 				(*mark)->visframe = r_framecount;
    528 				mark++;
    529 			} while (--c);
    530 		}
    531 
    532 		pleaf->key = r_currentkey;
    533 		r_currentkey++;		// all bmodels in a leaf share the same key
    534 	}
    535 	else
    536 	{
    537 	// node is just a decision point, so go down the apropriate sides
    538 
    539 	// find which side of the node we are on
    540 		plane = node->plane;
    541 
    542 		switch (plane->type)
    543 		{
    544 		case PLANE_X:
    545 			dot = modelorg[0] - plane->dist;
    546 			break;
    547 		case PLANE_Y:
    548 			dot = modelorg[1] - plane->dist;
    549 			break;
    550 		case PLANE_Z:
    551 			dot = modelorg[2] - plane->dist;
    552 			break;
    553 		default:
    554 			dot = DotProduct (modelorg, plane->normal) - plane->dist;
    555 			break;
    556 		}
    557 	
    558 		if (dot >= 0)
    559 			side = 0;
    560 		else
    561 			side = 1;
    562 
    563 	// recurse down the children, front side first
    564 		R_RecursiveWorldNode (node->children[side], clipflags);
    565 
    566 	// draw stuff
    567 		c = node->numsurfaces;
    568 
    569 		if (c)
    570 		{
    571 			surf = r_worldmodel->surfaces + node->firstsurface;
    572 
    573 			if (dot < -BACKFACE_EPSILON)
    574 			{
    575 				do
    576 				{
    577 					if ((surf->flags & SURF_PLANEBACK) &&
    578 						(surf->visframe == r_framecount))
    579 					{
    580 						R_RenderFace (surf, clipflags);
    581 					}
    582 
    583 					surf++;
    584 				} while (--c);
    585 			}
    586 			else if (dot > BACKFACE_EPSILON)
    587 			{
    588 				do
    589 				{
    590 					if (!(surf->flags & SURF_PLANEBACK) &&
    591 						(surf->visframe == r_framecount))
    592 					{
    593 						R_RenderFace (surf, clipflags);
    594 					}
    595 
    596 					surf++;
    597 				} while (--c);
    598 			}
    599 
    600 		// all surfaces on the same node share the same sequence number
    601 			r_currentkey++;
    602 		}
    603 
    604 	// recurse down the back side
    605 		R_RecursiveWorldNode (node->children[!side], clipflags);
    606 	}
    607 }
    608 
    609 
    610 
    611 /*
    612 ================
    613 R_RenderWorld
    614 ================
    615 */
    616 void R_RenderWorld (void)
    617 {
    618 
    619 	if (!r_drawworld->value)
    620 		return;
    621 	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
    622 		return;
    623 
    624 	c_drawnode=0;
    625 
    626 	// auto cycle the world frame for texture animation
    627 	r_worldentity.frame = (int)(r_newrefdef.time*2);
    628 	currententity = &r_worldentity;
    629 
    630 	VectorCopy (r_origin, modelorg);
    631 	currentmodel = r_worldmodel;
    632 	r_pcurrentvertbase = currentmodel->vertexes;
    633 
    634 	R_RecursiveWorldNode (currentmodel->nodes, 15);
    635 }
    636 
    637