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