Пример #1
0
/*
================
R_DrawSubmodelPolygons

All in one leaf
================
*/
void R_DrawSubmodelPolygons(mmodel_t *pmodel, int clipflags, mnode_t *topnode)
{
    int         i;
    vec_t       dot;
    mface_t *psurf;
    int         numsurfaces;
    cplane_t    *pplane;

// FIXME: use bounding-box-based frustum clipping info?

    psurf = pmodel->firstface;
    numsurfaces = pmodel->numfaces;

    for (i = 0; i < numsurfaces; i++, psurf++) {
        // find which side of the node we are on
        pplane = psurf->plane;

        dot = PlaneDiff(modelorg, pplane);

        // draw the polygon
        if (((psurf->drawflags & DSURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
            (!(psurf->drawflags & DSURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) {
            r_currentkey = ((mleaf_t *)topnode)->key;

            // FIXME: use bounding-box-based frustum clipping info?
            R_RenderFace(psurf, clipflags);
        }
    }
}
Пример #2
0
/*
================
R_DrawSolidClippedSubmodelPolygons

Bmodel crosses multiple leafs
================
*/
void R_DrawSolidClippedSubmodelPolygons(mmodel_t *pmodel, mnode_t *topnode)
{
    int         i, j;
    vec_t       dot;
    mface_t     *psurf;
    int         numsurfaces;
    cplane_t    *pplane;
    mvertex_t   bverts[MAX_BMODEL_VERTS];
    bedge_t     bedges[MAX_BMODEL_EDGES], *pbedge;
    msurfedge_t *surfedge;

// FIXME: use bounding-box-based frustum clipping info?

    psurf = pmodel->firstface;
    numsurfaces = pmodel->numfaces;

    for (i = 0; i < numsurfaces; i++, psurf++) {
        // find which side of the node we are on
        pplane = psurf->plane;

        dot = PlaneDiff(modelorg, pplane);

        // draw the polygon
        if ((!(psurf->drawflags & DSURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
            ((psurf->drawflags & DSURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
            continue;

        // FIXME: use bounding-box-based frustum clipping info?

        // copy the edges to bedges, flipping if necessary so always
        // clockwise winding
        // FIXME: if edges and vertices get caches, these assignments must move
        // outside the loop, and overflow checking must be done here
        pbverts = bverts;
        pbedges = bedges;
        numbverts = numbedges = 0;
        pbedge = &bedges[numbedges];
        numbedges += psurf->numsurfedges;

        if (numbedges >= MAX_BMODEL_EDGES) {
            Com_Printf("Out of edges for bmodel\n");
            return;
        }

        surfedge = psurf->firstsurfedge;
        for (j = 0; j < psurf->numsurfedges; j++, surfedge++) {
            pbedge[j].v[0] = surfedge->edge->v[surfedge->vert    ];
            pbedge[j].v[1] = surfedge->edge->v[surfedge->vert ^ 1];
            pbedge[j].pnext = &pbedge[j + 1];
        }

        pbedge[j - 1].pnext = NULL; // mark end of edges

        if (!(psurf->texinfo->c.flags & SURF_TRANS_MASK))
            R_RecursiveClipBPoly(pbedge, topnode, psurf);
        else
            R_RenderBmodelFace(pbedge, psurf);
    }
}
Пример #3
0
/*
* R_VisCullSphere
*/
qboolean R_VisCullSphere( const vec3_t origin, float radius )
{
	float dist;
	int stackdepth = 0;
	mnode_t *node, *localstack[2048];

	if( !rsh.worldModel || ( rn.refdef.rdflags & RDF_NOWORLDMODEL ) )
		return qfalse;
	if( rn.renderFlags & RF_NOVIS )
		return qfalse;

	radius += 4;
	for( node = rsh.worldBrushModel->nodes;; )
	{
		if( node->pvsframe != rf.pvsframecount )
		{
			if( !stackdepth )
				return qtrue;
			node = localstack[--stackdepth];
			continue;
		}

		if( !node->plane )
			return qfalse;

		dist = PlaneDiff( origin, node->plane );
		if( dist > radius )
		{
			node = node->children[0];
			continue;
		}
		else if( dist < -radius )
		{
			node = node->children[1];
			continue;
		}

		// go down both sides
		if( stackdepth < sizeof( localstack )/sizeof( mnode_t * ) )
			localstack[stackdepth++] = node->children[0];
		else
			assert( 0 );
		node = node->children[1];
	}

	return qtrue;
}
Пример #4
0
/*
===================
R_VisCullSphere
===================
*/
bool R_VisCullSphere( const Vector &origin, float radius )
{
	mnode_t *localstack[2048];
	int stackdepth = 0;

	if( !worldmodel || !RI.drawWorld )
		return false;

	if( r_novis->value )
		return false;

	radius += 4;

	for( mnode_t *node = worldmodel->nodes; ; )
	{
		if( node->visframe != tr.visframecount )
		{
			if( !stackdepth )
				return true;
			node = localstack[--stackdepth];
			continue;
		}

		if( node->contents < 0 )
			return false;

		float dist = PlaneDiff( origin, node->plane );

		if( dist > radius )
		{
			node = node->children[0];
			continue;
		}
		else if( dist < -radius )
		{
			node = node->children[1];
			continue;
		}

		// go down both sides
		if( stackdepth < ARRAYSIZE( localstack ))
			localstack[stackdepth++] = node->children[0];
		node = node->children[1];
	}

	return true;
}
Пример #5
0
/*
* R_SurfaceShadowBits
*/
static unsigned int R_SurfaceShadowBits( const msurface_t *surf, unsigned int checkShadowBits )
{
	unsigned int i, bit;
	shadowGroup_t *grp;
	unsigned int surfShadowBits = 0;

	if( !R_SurfPotentiallyShadowed( surf ) ) {
		return 0;
	}

	for( i = 0; i < rsc.numShadowGroups; i++ ) {
		if( !checkShadowBits ) {
			break;
		}

		grp = rsc.shadowGroups + i;
		bit = grp->bit;

		if( checkShadowBits & bit ) {
			switch( surf->facetype ) {
				case FACETYPE_PLANAR:
					if ( BoundsIntersect( surf->mins, surf->maxs, grp->visMins, grp->visMaxs ) ) {
						float dist = PlaneDiff( grp->visOrigin, surf->plane );
						if ( dist > -grp->visRadius && dist <= grp->visRadius ) {
							// crossed by plane
							surfShadowBits |= bit;
						}
					}
					break;
				case FACETYPE_PATCH:
				case FACETYPE_TRISURF:
				case FACETYPE_FOLIAGE:
					if( BoundsIntersect( surf->mins, surf->maxs, grp->visMins, grp->visMaxs ) ) {
						surfShadowBits |= bit;
					}
					break;
			}
			checkShadowBits &= ~bit;
		}
	}
	
	return surfShadowBits;
}
Пример #6
0
/*
* Mod_PointInLeaf
*/
mleaf_t *Mod_PointInLeaf( vec3_t p, model_t *model )
{
	mnode_t	*node;
	cplane_t *plane;
	mbrushmodel_t *bmodel;

	if( !model || !( bmodel = ( mbrushmodel_t * )model->extradata ) || !bmodel->nodes )
	{
		ri.Com_Error( ERR_DROP, "Mod_PointInLeaf: bad model" );
		return NULL;
	}

	node = bmodel->nodes;
	do
	{
		plane = node->plane;
		node = node->children[PlaneDiff( p, plane ) < 0];
	}
	while( node->plane != NULL );

	return ( mleaf_t * )node;
}
Пример #7
0
/*
* R_SurfaceDlightBits
*/
static unsigned int R_SurfaceDlightBits( const msurface_t *surf, unsigned int checkDlightBits )
{
	unsigned int i, bit;
	dlight_t *lt;
	float dist;
	unsigned int surfDlightBits = 0;

	if( !R_SurfPotentiallyLit( surf ) ) {
		return 0;
	}

	for( i = 0, bit = 1, lt = rsc.dlights; i < rsc.numDlights; i++, bit <<= 1, lt++ ) {
		if( !checkDlightBits ) {
			break;
		}
		if( checkDlightBits & bit ) {
			switch( surf->facetype ) {
				case FACETYPE_PLANAR:
					dist = PlaneDiff( lt->origin, surf->plane );
					if( dist > -lt->intensity && dist < lt->intensity ) {
						surfDlightBits |= bit;
					}
					break;
				case FACETYPE_PATCH:
				case FACETYPE_TRISURF:
				case FACETYPE_FOLIAGE:
					if( BoundsAndSphereIntersect( surf->mins, surf->maxs, lt->origin, lt->intensity ) ) {
						surfDlightBits |= bit;
					}
					break;
			}
			checkDlightBits &= ~bit;
		}
	}

	return surfDlightBits;
}
Пример #8
0
void R_RecursiveWorldNode (mnode_t *node, int clipflags) {
	int i, c, side, *pindex;
	vec3_t acceptpt, rejectpt;
	mplane_t *plane;
	msurface_t *surf, **mark;
	mleaf_t *pleaf;
	double d, dot;

	if (node->contents == CONTENTS_SOLID)
		return;		// solid

	if (node->visframe != r_visframecount)
		return;

	// cull the clipping planes if not trivial accept
	// FIXME: the compiler is doing a lousy job of optimizing here; it could be twice as fast in ASM
	if (clipflags) {
		for (i = 0; i < 4; i++) {
			if (!(clipflags & (1<<i)) )
				continue;	// don't need to clip against it

			// generate accept and reject points
			// FIXME: do with fast look-ups or integer tests based on the sign bit of the floating point values

			pindex = pfrustum_indexes[i];

			rejectpt[0] = (float)node->minmaxs[pindex[0]];
			rejectpt[1] = (float)node->minmaxs[pindex[1]];
			rejectpt[2] = (float)node->minmaxs[pindex[2]];

			d = DotProduct (rejectpt, view_clipplanes[i].normal);
			d -= view_clipplanes[i].dist;

			if (d <= 0)
				return;

			acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
			acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
			acceptpt[2] = (float)node->minmaxs[pindex[3+2]];

			d = DotProduct (acceptpt, view_clipplanes[i].normal);
			d -= view_clipplanes[i].dist;

			if (d >= 0)
				clipflags &= ~(1<<i);	// node is entirely on screen
		}
	}
	
	// if a leaf node, draw stuff
	if (node->contents < 0) {
		pleaf = (mleaf_t *)node;

		mark = pleaf->firstmarksurface;
		c = pleaf->nummarksurfaces;

		if (c) {
			do {
				(*mark)->visframe = r_framecount;
				mark++;
			} while (--c);
		}

		// deal with model fragments in this leaf
		if (pleaf->efrags)
			R_StoreEfrags (&pleaf->efrags);

		pleaf->key = r_currentkey;
		r_currentkey++;		// all bmodels in a leaf share the same key
	} else {
		// node is just a decision point, so go down the apropriate sides

		// find which side of the node we are on
		plane = node->plane;
		dot = PlaneDiff (modelorg, plane);
		side = (dot < 0);

		// recurse down the children, front side first
		R_RecursiveWorldNode (node->children[side], clipflags);

		// draw stuff
		c = node->numsurfaces;

		if (c) {
			surf = cl.worldmodel->surfaces + node->firstsurface;
			if (dot < -BACKFACE_EPSILON) {
				do {
					if ((surf->flags & SURF_PLANEBACK) && surf->visframe == r_framecount)
						R_RenderFace (surf, clipflags);

					surf++;
				} while (--c);
			} else if (dot > BACKFACE_EPSILON) {
				do
				{
					if (!(surf->flags & SURF_PLANEBACK) && surf->visframe == r_framecount)
						R_RenderFace (surf, clipflags);

					surf++;
				} while (--c);
			}

			// all surfaces on the same node share the same sequence number
			r_currentkey++;
		}

		// recurse down the back side
		R_RecursiveWorldNode (node->children[!side], clipflags);
	}
}
Пример #9
0
/*
================
R_RecursiveClipBPoly

Clip a bmodel poly down the world bsp tree
================
*/
static void R_RecursiveClipBPoly(bedge_t *pedges, mnode_t *pnode, mface_t *psurf)
{
    bedge_t     *psideedges[2], *pnextedge, *ptedge;
    int         i, side, lastside;
    float       dist, frac, lastdist;
    cplane_t    *splitplane, tplane;
    mvertex_t   *pvert, *plastvert, *ptvert;
    mnode_t     *pn;
    int         area;

    psideedges[0] = psideedges[1] = NULL;

    makeclippededge = qfalse;

// transform the BSP plane into model space
// FIXME: cache these?
    splitplane = pnode->plane;
    tplane.dist = -PlaneDiff(r_entorigin, splitplane);
    tplane.normal[0] = DotProduct(entity_rotation[0], splitplane->normal);
    tplane.normal[1] = DotProduct(entity_rotation[1], splitplane->normal);
    tplane.normal[2] = DotProduct(entity_rotation[2], splitplane->normal);

// clip edges to BSP plane
    for (; pedges; pedges = pnextedge) {
        pnextedge = pedges->pnext;

        // set the status for the last point as the previous point
        // FIXME: cache this stuff somehow?
        plastvert = pedges->v[0];
        lastdist = PlaneDiff(plastvert->point, &tplane);

        if (lastdist > 0)
            lastside = 0;
        else
            lastside = 1;

        pvert = pedges->v[1];
        dist = PlaneDiff(pvert->point, &tplane);

        if (dist > 0)
            side = 0;
        else
            side = 1;

        if (side != lastside) {
            // clipped
            if (numbverts >= MAX_BMODEL_VERTS)
                return;

            // generate the clipped vertex
            frac = lastdist / (lastdist - dist);
            ptvert = &pbverts[numbverts++];
            LerpVector(plastvert->point, pvert->point, frac, ptvert->point);

            // split into two edges, one on each side, and remember entering
            // and exiting points
            // FIXME: share the clip edge by having a winding direction flag?
            if (numbedges >= (MAX_BMODEL_EDGES - 1)) {
                Com_Printf("Out of edges for bmodel\n");
                return;
            }

            ptedge = &pbedges[numbedges];
            ptedge->pnext = psideedges[lastside];
            psideedges[lastside] = ptedge;
            ptedge->v[0] = plastvert;
            ptedge->v[1] = ptvert;

            ptedge = &pbedges[numbedges + 1];
            ptedge->pnext = psideedges[side];
            psideedges[side] = ptedge;
            ptedge->v[0] = ptvert;
            ptedge->v[1] = pvert;

            numbedges += 2;

            if (side == 0) {
                // entering for front, exiting for back
                pfrontenter = ptvert;
                makeclippededge = qtrue;
            } else {
                pfrontexit = ptvert;
                makeclippededge = qtrue;
            }
        } else {
            // add the edge to the appropriate side
            pedges->pnext = psideedges[side];
            psideedges[side] = pedges;
        }
    }

// if anything was clipped, reconstitute and add the edges along the clip
// plane to both sides (but in opposite directions)
    if (makeclippededge) {
        if (numbedges >= (MAX_BMODEL_EDGES - 2)) {
            Com_Error(ERR_DROP, "Out of edges for bmodel");
        }

        ptedge = &pbedges[numbedges];
        ptedge->pnext = psideedges[0];
        psideedges[0] = ptedge;
        ptedge->v[0] = pfrontexit;
        ptedge->v[1] = pfrontenter;

        ptedge = &pbedges[numbedges + 1];
        ptedge->pnext = psideedges[1];
        psideedges[1] = ptedge;
        ptedge->v[0] = pfrontenter;
        ptedge->v[1] = pfrontexit;

        numbedges += 2;
    }

// draw or recurse further
    for (i = 0; i < 2; i++) {
        if (psideedges[i]) {
            // draw if we've reached a non-solid leaf, done if all that's left is a
            // solid leaf, and continue down the tree if it's not a leaf
            pn = pnode->children[i];

            // we're done with this branch if the node or leaf isn't in the PVS
            if (pn->visframe == r_visframecount) {
                if (!pn->plane) {
                    mleaf_t *pl = (mleaf_t *)pn;
                    if (pl->contents != CONTENTS_SOLID) {
                        if (r_newrefdef.areabits) {
                            area = pl->area;
                            if (!Q_IsBitSet(r_newrefdef.areabits, area))
                                continue;       // not visible
                        }

                        r_currentbkey = pl->key;
                        R_RenderBmodelFace(psideedges[i], psurf);
                    }
                } else {
                    R_RecursiveClipBPoly(psideedges[i], pnode->children[i],
                                         psurf);
                }
            }
        }
    }
}
Пример #10
0
void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf) {
	int i;
	unsigned mask;
	mplane_t *pplane;
	float distinv;
	vec3_t p_normal;
	medge_t tedge;
	clipplane_t	*pclip;

	// skip out if no more surfs
	if (surface_p >= surf_max) {
		r_outofsurfaces++;
		return;
	}

	// ditto if not enough edges left, or switch to auxedges if possible
	if ((edge_p + psurf->numedges + 4) >= edge_max) {
		r_outofedges += psurf->numedges;
		return;
	}

	c_faceclip++;

	// this is a dummy to give the caching mechanism someplace to write to
	r_pedge = &tedge;

	// set up clip planes
	pclip = NULL;

	for (i = 3, mask = 0x08 ; i >= 0 ; i--, mask >>= 1) {
		if (r_clipflags & mask) {
			view_clipplanes[i].next = pclip;
			pclip = &view_clipplanes[i];
		}
	}

	// push the edges through
	r_emitted = 0;
	r_nearzi = 0;
	r_nearzionly = false;
	makeleftedge = makerightedge = false;
	// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching can be used?
	r_lastvertvalid = false;

	for ( ; pedges ; pedges = pedges->pnext) {
		r_leftclipped = r_rightclipped = false;
		R_ClipEdge (pedges->v[0], pedges->v[1], pclip);

		if (r_leftclipped)
			makeleftedge = true;
		if (r_rightclipped)
			makerightedge = true;
	}

	// if there was a clip off the left edge, add that edge too
	// FIXME: faster to do in screen space?
	// FIXME: share clipped edges?
	if (makeleftedge) {
		r_pedge = &tedge;
		R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
	}

	// if there was a clip off the right edge, get the right r_nearzi
	if (makerightedge) {
		r_pedge = &tedge;
		r_nearzionly = true;
		R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
	}

	// if no edges made it out, return without posting the surface
	if (!r_emitted)
		return;

	r_polycount++;

	surface_p->data = (void *)psurf;
	surface_p->nearzi = r_nearzi;
	surface_p->flags = psurf->flags;
	surface_p->insubmodel = true;
	surface_p->spanstate = 0;
	surface_p->entity = currententity;
	surface_p->key = r_currentbkey;
	surface_p->spans = NULL;

	pplane = psurf->plane;
	// FIXME: cache this?
	TransformVector (pplane->normal, p_normal);
	// FIXME: cache this?
	distinv = 1.0 / (-PlaneDiff(modelorg, pplane));

	surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
	surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
	surface_p->d_ziorigin = p_normal[2] * distinv - xcenter * surface_p->d_zistepu - ycenter * surface_p->d_zistepv;

	surface_p++;
}
Пример #11
0
static void R_TrackSprite(const entity_render_t *ent, vec3_t origin, vec3_t left, vec3_t up, int *edge, float *dir_angle)
{
	float distance;
	vec3_t bCoord; // body coordinates of object
	unsigned int i;

	// temporarily abuse bCoord as the vector player->sprite-origin
	VectorSubtract(origin, r_refdef.view.origin, bCoord);
	distance = VectorLength(bCoord);

	// Now get the bCoords :)
	Matrix4x4_Transform(&r_refdef.view.inverse_matrix, origin, bCoord);

	*edge = 0; // FIXME::should assume edge == 0, which is correct currently
	for(i = 0; i < 4; ++i)
	{
		if(PlaneDiff(origin, &r_refdef.view.frustum[i]) < -EPSILON)
			break;
	}

	// If it wasn't outside a plane, no tracking needed
	if(i < 4)
	{
		float x, y;    // screen X and Y coordinates
		float ax, ay;  // absolute coords, used for division
		// I divide x and y by the greater absolute value to get ranges -1.0 to +1.0
		
		bCoord[2] *= r_refdef.view.frustum_x;
		bCoord[1] *= r_refdef.view.frustum_y;

		//Con_Printf("%f %f %f\n", bCoord[0], bCoord[1], bCoord[2]);
		
		ax = fabs(bCoord[1]);
		ay = fabs(bCoord[2]);
		// get the greater value and determine the screen edge it's on
		if(ax < ay)
		{
			ax = ay;
			// 180 or 0 degrees
			if(bCoord[2] < 0.0f)
				*edge = SIDE_BOTTOM;
			else
				*edge = SIDE_TOP;
		} else {
			if(bCoord[1] < 0.0f)
				*edge = SIDE_RIGHT;
			else
				*edge = SIDE_LEFT;
		}
		
		// umm... 
		if(ax < MIN_EPSILON) // this was == 0.0f before --blub
			ax = MIN_EPSILON;
		// get the -1 to +1 range
		x = bCoord[1] / ax;
		y = bCoord[2] / ax;

		ax = (1.0f / VectorLength(left));
		ay = (1.0f / VectorLength(up));
		// Using the placement below the distance of a sprite is
		// real dist = sqrt(d*d + dfxa*dfxa + dgyb*dgyb)
		// d is the distance we use
		// f is frustum X
		// x is x
		// a is ax
		// g is frustum Y
		// y is y
		// b is ay
		
		// real dist (r) shall be d, so
		// r*r = d*d + dfxa*dfxa + dgyb*dgyb
		// r*r = d*d * (1 + fxa*fxa + gyb*gyb)
		// d*d = r*r / (1 + fxa*fxa + gyb*gyb)
		// d = sqrt(r*r / (1 + fxa*fxa + gyb*gyb))
		// thus:
		distance = sqrt((distance*distance) / (1.0 +
					r_refdef.view.frustum_x*r_refdef.view.frustum_x * x*x * ax*ax +
					r_refdef.view.frustum_y*r_refdef.view.frustum_y * y*y * ay*ay));
		// ^ the one we want        ^ the one we have       ^ our factors
		
		// Place the sprite a few units ahead of the player
		VectorCopy(r_refdef.view.origin, origin);
		VectorMA(origin, distance, r_refdef.view.forward, origin);
		// Move the sprite left / up the screeen height
		VectorMA(origin, distance * r_refdef.view.frustum_x * x * ax, left, origin);
		VectorMA(origin, distance * r_refdef.view.frustum_y * y * ay, up, origin);

		if(r_track_sprites_flags.integer & TSF_ROTATE_CONTINOUSLY)
		{
			// compute the rotation, negate y axis, we're pointing outwards
			*dir_angle = atan(-y / x) * 180.0f/M_PI;
			// we need the real, full angle
			if(x < 0.0f)
				*dir_angle += 180.0f;
		}

		left[0] *= r_track_sprites_scalew.value;
		left[1] *= r_track_sprites_scalew.value;
		left[2] *= r_track_sprites_scalew.value;

		up[0] *= r_track_sprites_scaleh.value;
		up[1] *= r_track_sprites_scaleh.value;
		up[2] *= r_track_sprites_scaleh.value;
	}
}
Пример #12
0
/*
=================
R_CullSurface

cull invisible surfaces
=================
*/
bool R_CullSurfaceExt( msurface_t *surf, const mplane_t frustum[6], unsigned int clipflags )
{
	mextrasurf_t	*info;
	cl_entity_t	*e = RI.currententity;

	if( !surf || !surf->texinfo || !surf->texinfo->texture )
		return true;

	if( surf->flags & SURF_WATERCSG && !( RI.currententity->curstate.effects & EF_NOWATERCSG ))
		return true;

	if( surf->flags & SURF_NOCULL )
		return false;

	// don't cull transparent surfaces because we should be draw decals on them
	if( surf->pdecals && ( e->curstate.rendermode == kRenderTransTexture || e->curstate.rendermode == kRenderTransAdd ))
		return false;

	if( r_nocull->value )
		return false;

	// world surfaces can be culled by vis frame too
	if( RI.currententity == GET_ENTITY( 0 ) && surf->visframe != tr.framecount )
		return true;

	if( r_faceplanecull->value && glState.faceCull != 0 )
	{
		if(!(surf->flags & SURF_DRAWTURB) || !RI.currentWaveHeight )
		{
			if( surf->plane->normal != g_vecZero )
			{
				float	dist;

				if( RI.drawOrtho ) dist = surf->plane->normal[2];
				else dist = PlaneDiff( tr.modelorg, surf->plane );

				if( glState.faceCull == GL_FRONT || ( RI.params & RP_MIRRORVIEW ))
				{
					if( surf->flags & SURF_PLANEBACK )
					{
						if( dist >= -BACKFACE_EPSILON )
							return true; // wrong side
					}
					else
					{
						if( dist <= BACKFACE_EPSILON )
							return true; // wrong side
					}
				}
				else if( glState.faceCull == GL_BACK )
				{
					if( surf->flags & SURF_PLANEBACK )
					{
						if( dist <= BACKFACE_EPSILON )
							return true; // wrong side
					}
					else
					{
						if( dist >= -BACKFACE_EPSILON )
							return true; // wrong side
					}
				}
			}
		}
	}

	info = SURF_INFO( surf, RI.currentmodel );

	return ( clipflags && R_CullBoxExt( frustum, info->mins, info->maxs, clipflags ));
}
Пример #13
0
/*
* R_UpdatePortalSurface
*/
void R_UpdatePortalSurface( portalSurface_t *portalSurface, const mesh_t *mesh,
	const vec3_t mins, const vec3_t maxs, const shader_t *shader ) {
	unsigned int i;
	float dist;
	cplane_t plane, untransformed_plane;
	vec3_t v[3];
	const entity_t *ent;

	if( !mesh || !portalSurface ) {
		return;
	}

	ent = portalSurface->entity;

	for( i = 0; i < 3; i++ ) {
		VectorCopy( mesh->xyzArray[mesh->elems[i]], v[i] );
	}

	PlaneFromPoints( v, &untransformed_plane );
	untransformed_plane.dist += DotProduct( ent->origin, untransformed_plane.normal );
	untransformed_plane.dist += 1; // nudge along the normal a bit
	CategorizePlane( &untransformed_plane );

	if( shader->flags & SHADER_AUTOSPRITE ) {
		vec3_t centre;

		// autosprites are quads, facing the viewer
		if( mesh->numVerts < 4 ) {
			return;
		}

		// compute centre as average of 4 vertices
		VectorCopy( mesh->xyzArray[mesh->elems[3]], centre );
		for( i = 0; i < 3; i++ )
			VectorAdd( centre, v[i], centre );
		VectorMA( ent->origin, 0.25, centre, centre );

		VectorNegate( &rn.viewAxis[AXIS_FORWARD], plane.normal );
		plane.dist = DotProduct( plane.normal, centre );
		CategorizePlane( &plane );
	} else {
		vec3_t temp;
		mat3_t entity_rotation;

		// regular surfaces
		if( !Matrix3_Compare( ent->axis, axis_identity ) ) {
			Matrix3_Transpose( ent->axis, entity_rotation );

			for( i = 0; i < 3; i++ ) {
				VectorCopy( v[i], temp );
				Matrix3_TransformVector( entity_rotation, temp, v[i] );
				VectorMA( ent->origin, ent->scale, v[i], v[i] );
			}

			PlaneFromPoints( v, &plane );
			CategorizePlane( &plane );
		} else {
			plane = untransformed_plane;
		}
	}

	if( ( dist = PlaneDiff( rn.viewOrigin, &plane ) ) <= BACKFACE_EPSILON ) {
		// behind the portal plane
		if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) {
			return;
		}

		// we need to render the backplane view
	}

	// check if portal view is opaque due to alphagen portal
	if( shader->portalDistance && dist > shader->portalDistance ) {
		return;
	}

	portalSurface->plane = plane;
	portalSurface->untransformed_plane = untransformed_plane;

	AddPointToBounds( mins, portalSurface->mins, portalSurface->maxs );
	AddPointToBounds( maxs, portalSurface->mins, portalSurface->maxs );
	VectorAdd( portalSurface->mins, portalSurface->maxs, portalSurface->centre );
	VectorScale( portalSurface->centre, 0.5, portalSurface->centre );
}
Пример #14
0
/*
* R_DrawPortalSurface
*
* Renders the portal view and captures the results from framebuffer if
* we need to do a $portalmap stage. Note that for $portalmaps we must
* use a different viewport.
*/
static void R_DrawPortalSurface( portalSurface_t *portalSurface ) {
	unsigned int i;
	int x, y, w, h;
	float dist, d, best_d;
	vec3_t viewerOrigin;
	vec3_t origin;
	mat3_t axis;
	entity_t *ent, *best;
	cplane_t *portal_plane = &portalSurface->plane, *untransformed_plane = &portalSurface->untransformed_plane;
	const shader_t *shader = portalSurface->shader;
	vec_t *portal_centre = portalSurface->centre;
	bool mirror, refraction = false;
	image_t *captureTexture;
	int captureTextureId = -1;
	int prevRenderFlags = 0;
	bool prevFlipped;
	bool doReflection, doRefraction;
	image_t *portalTexures[2] = { NULL, NULL };

	doReflection = doRefraction = true;
	if( shader->flags & SHADER_PORTAL_CAPTURE ) {
		shaderpass_t *pass;

		captureTexture = NULL;
		captureTextureId = 0;

		for( i = 0, pass = shader->passes; i < shader->numpasses; i++, pass++ ) {
			if( pass->program_type == GLSL_PROGRAM_TYPE_DISTORTION ) {
				if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 1 ) ) {
					doRefraction = false;
				} else if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 0 ) ) {
					doReflection = false;
				}
				break;
			}
		}
	} else {
		captureTexture = NULL;
		captureTextureId = -1;
	}

	x = y = 0;
	w = rn.refdef.width;
	h = rn.refdef.height;

	dist = PlaneDiff( rn.viewOrigin, portal_plane );
	if( dist <= BACKFACE_EPSILON || !doReflection ) {
		if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) || !doRefraction ) {
			return;
		}

		// even if we're behind the portal, we still need to capture
		// the second portal image for refraction
		refraction = true;
		captureTexture = NULL;
		captureTextureId = 1;
		if( dist < 0 ) {
			VectorInverse( portal_plane->normal );
			portal_plane->dist = -portal_plane->dist;
		}
	}

	mirror = true; // default to mirror view
	// it is stupid IMO that mirrors require a RT_PORTALSURFACE entity

	best = NULL;
	best_d = 100000000;
	for( i = 0; i < rn.numEntities; i++ ) {
		ent = R_NUM2ENT( rn.entities[i] );

		if( ent->rtype != RT_PORTALSURFACE ) {
			continue;
		}

		d = PlaneDiff( ent->origin, untransformed_plane );
		if( ( d >= -64 ) && ( d <= 64 ) ) {
			d = Distance( ent->origin, portal_centre );
			if( d < best_d ) {
				best = ent;
				best_d = d;
			}
		}
	}

	if( best == NULL ) {
		if( captureTextureId < 0 ) {
			// still do a push&pop because to ensure the clean state
			if( R_PushRefInst() ) {
				R_PopRefInst();
			}
			return;
		}
	} else {
		if( !VectorCompare( best->origin, best->origin2 ) ) { // portal
			mirror = false;
		}
		best->rtype = NUM_RTYPES;
	}

	prevRenderFlags = rn.renderFlags;
	prevFlipped = ( rn.refdef.rdflags & RDF_FLIPPED ) != 0;
	if( !R_PushRefInst() ) {
		return;
	}

	VectorCopy( rn.viewOrigin, viewerOrigin );
	if( prevFlipped ) {
		VectorInverse( &rn.viewAxis[AXIS_RIGHT] );
	}

setup_and_render:

	if( refraction ) {
		VectorInverse( portal_plane->normal );
		portal_plane->dist = -portal_plane->dist;
		CategorizePlane( portal_plane );
		VectorCopy( rn.viewOrigin, origin );
		Matrix3_Copy( rn.refdef.viewaxis, axis );
		VectorCopy( viewerOrigin, rn.pvsOrigin );

		rn.renderFlags |= RF_PORTALVIEW;
		if( prevFlipped ) {
			rn.renderFlags |= RF_FLIPFRONTFACE;
		}
	} else if( mirror ) {
		VectorReflect( rn.viewOrigin, portal_plane->normal, portal_plane->dist, origin );

		VectorReflect( &rn.viewAxis[AXIS_FORWARD], portal_plane->normal, 0, &axis[AXIS_FORWARD] );
		VectorReflect( &rn.viewAxis[AXIS_RIGHT], portal_plane->normal, 0, &axis[AXIS_RIGHT] );
		VectorReflect( &rn.viewAxis[AXIS_UP], portal_plane->normal, 0, &axis[AXIS_UP] );

		Matrix3_Normalize( axis );

		VectorCopy( viewerOrigin, rn.pvsOrigin );

		rn.renderFlags = ( prevRenderFlags ^ RF_FLIPFRONTFACE ) | RF_MIRRORVIEW;
	} else {
		vec3_t tvec;
		mat3_t A, B, C, rot;

		// build world-to-portal rotation matrix
		VectorNegate( portal_plane->normal, tvec );
		NormalVectorToAxis( tvec, A );

		// build portal_dest-to-world rotation matrix
		ByteToDir( best->frame, tvec );
		NormalVectorToAxis( tvec, B );
		Matrix3_Transpose( B, C );

		// multiply to get world-to-world rotation matrix
		Matrix3_Multiply( C, A, rot );

		// translate view origin
		VectorSubtract( rn.viewOrigin, best->origin, tvec );
		Matrix3_TransformVector( rot, tvec, origin );
		VectorAdd( origin, best->origin2, origin );

		Matrix3_Transpose( A, B );
		Matrix3_Multiply( rn.viewAxis, B, rot );
		Matrix3_Multiply( best->axis, rot, B );
		Matrix3_Transpose( C, A );
		Matrix3_Multiply( B, A, axis );

		// set up portal_plane
		VectorCopy( &axis[AXIS_FORWARD], portal_plane->normal );
		portal_plane->dist = DotProduct( best->origin2, portal_plane->normal );
		CategorizePlane( portal_plane );

		// for portals, vis data is taken from portal origin, not
		// view origin, because the view point moves around and
		// might fly into (or behind) a wall
		VectorCopy( best->origin2, rn.pvsOrigin );
		VectorCopy( best->origin2, rn.lodOrigin );

		rn.renderFlags |= RF_PORTALVIEW;

		// ignore entities, if asked politely
		if( best->renderfx & RF_NOPORTALENTS ) {
			rn.renderFlags |= RF_ENVVIEW;
		}
		if( prevFlipped ) {
			rn.renderFlags |= RF_FLIPFRONTFACE;
		}
	}

	rn.refdef.rdflags &= ~( RDF_UNDERWATER | RDF_CROSSINGWATER | RDF_FLIPPED );

	rn.meshlist = &r_portallist;
	rn.portalmasklist = NULL;

	rn.renderFlags |= RF_CLIPPLANE;
	rn.renderFlags &= ~RF_SOFT_PARTICLES;
	rn.clipPlane = *portal_plane;

	rn.nearClip = Z_NEAR;
	rn.farClip = R_DefaultFarClip();

	rn.polygonFactor = POLYOFFSET_FACTOR;
	rn.polygonUnits = POLYOFFSET_UNITS;

	rn.clipFlags |= 16;
	rn.frustum[4] = *portal_plane; // nearclip
	CategorizePlane( &rn.frustum[4] );

	// if we want to render to a texture, initialize texture
	// but do not try to render to it more than once
	if( captureTextureId >= 0 ) {
		int texFlags = shader->flags & SHADER_NO_TEX_FILTERING ? IT_NOFILTERING : 0;

		captureTexture = R_GetPortalTexture( rsc.refdef.width, rsc.refdef.height, texFlags,
											 rsc.frameCount );
		portalTexures[captureTextureId] = captureTexture;

		if( !captureTexture ) {
			// couldn't register a slot for this plane
			goto done;
		}

		x = y = 0;
		w = captureTexture->upload_width;
		h = captureTexture->upload_height;
		rn.refdef.width = w;
		rn.refdef.height = h;
		rn.refdef.x = 0;
		rn.refdef.y = 0;
		rn.renderTarget = captureTexture->fbo;
		rn.renderFlags |= RF_PORTAL_CAPTURE;
		Vector4Set( rn.viewport, rn.refdef.x + x, rn.refdef.y + y, w, h );
		Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h );
	} else {
		rn.renderFlags &= ~RF_PORTAL_CAPTURE;
	}

	VectorCopy( origin, rn.refdef.vieworg );
	Matrix3_Copy( axis, rn.refdef.viewaxis );

	R_SetupViewMatrices( &rn.refdef );

	R_SetupFrustum( &rn.refdef, rn.nearClip, rn.farClip, rn.frustum, rn.frustumCorners );

	R_SetupPVS( &rn.refdef );

	R_RenderView( &rn.refdef );

	if( doRefraction && !refraction && ( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) {
		rn.renderFlags = prevRenderFlags;
		refraction = true;
		captureTexture = NULL;
		captureTextureId = 1;
		goto setup_and_render;
	}

done:
	portalSurface->texures[0] = portalTexures[0];
	portalSurface->texures[1] = portalTexures[1];

	R_PopRefInst();
}
Пример #15
0
/*
===========
PointInLeaf

Vic: rewrote to be faster
LordHavoc: shortened a little
===========
*/
node_t	*PointInLeaf (node_t *node, vec3_t point)
{
	while (!node->contents)
		node = node->children[PlaneDiff( point, &mapplanes[node->planenum] ) <= 0];
	return node;
}
Пример #16
0
/*
=================
R_RecursiveFragmentNode
=================
*/
static void R_RecursiveFragmentNode( void )
{
	int stackdepth = 0;
	float dist;
	bool inside;
	mnode_t	*node, *localstack[2048];
	mleaf_t	*leaf;
	msurface_t *surf, **mark;

	for( node = r_worldbrushmodel->nodes, stackdepth = 0;; )
	{
		if( node->plane == NULL )
		{
			leaf = ( mleaf_t * )node;
			mark = leaf->firstFragmentSurface;
			if( !mark )
				goto nextNodeOnStack;

			do
			{
				if( numFragmentVerts == maxFragmentVerts || numClippedFragments == maxClippedFragments )
					return; // already reached the limit

				surf = *mark++;
				if( surf->fragmentframe == r_fragmentframecount )
					continue;
				surf->fragmentframe = r_fragmentframecount;

				if( !BoundsAndSphereIntersect( surf->mins, surf->maxs, fragmentOrigin, fragmentRadius ) )
					continue;

				if( surf->facetype == MST_PATCH )
					inside = R_PatchSurfClipFragment( surf, fragmentNormal );
				else
					inside = R_PlanarSurfClipFragment( surf, fragmentNormal );

				if( inside )
					return;
			} while( *mark );

			if( numFragmentVerts == maxFragmentVerts || numClippedFragments == maxClippedFragments )
				return; // already reached the limit

nextNodeOnStack:
			if( !stackdepth )
				break;
			node = localstack[--stackdepth];
			continue;
		}

		dist = PlaneDiff( fragmentOrigin, node->plane );
		if( dist > fragmentRadius )
		{
			node = node->children[0];
			continue;
		}

		if( ( dist >= -fragmentRadius ) && ( stackdepth < sizeof( localstack ) / sizeof( mnode_t * )))
			localstack[stackdepth++] = node->children[0];
		node = node->children[1];
	}
}
Пример #17
0
void R_RenderFace (msurface_t *fa, int clipflags) {
	int i, lindex;
	unsigned mask;
	mplane_t *pplane;
	float distinv;
	vec3_t p_normal;
	medge_t *pedges, tedge;
	clipplane_t *pclip;

	// skip out if no more surfs
	if (surface_p >= surf_max) {
		r_outofsurfaces++;
		return;
	}

	// ditto if not enough edges left, or switch to auxedges if possible
	if ((edge_p + fa->numedges + 4) >= edge_max) {
		r_outofedges += fa->numedges;
		return;
	}

	c_faceclip++;

	// set up clip planes
	pclip = NULL;

	for (i = 3, mask = 0x08; i >= 0; i--, mask >>= 1) {
		if (clipflags & mask) {
			view_clipplanes[i].next = pclip;
			pclip = &view_clipplanes[i];
		}
	}

	// push the edges through
	r_emitted = 0;
	r_nearzi = 0;
	r_nearzionly = false;
	makeleftedge = makerightedge = false;
	pedges = currententity->model->edges;
	r_lastvertvalid = false;

	for (i = 0; i < fa->numedges; i++) {
		lindex = currententity->model->surfedges[fa->firstedge + i];

		if (lindex > 0) {
			r_pedge = &pedges[lindex];

			// if the edge is cached, we can just reuse the edge
			if (!insubmodel) {
				if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) {
					if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == r_framecount) {
						r_lastvertvalid = false;
						continue;
					}
				} else {
					if ((((unsigned long)edge_p - (unsigned long)r_edges) > r_pedge->cachededgeoffset) &&
						(((edge_t *)((unsigned long) r_edges + r_pedge->cachededgeoffset))->owner == r_pedge))
					{
						R_EmitCachedEdge ();
						r_lastvertvalid = false;
						continue;
					}
				}
			}

			// assume it's cacheable
			cacheoffset = (byte *)edge_p - (byte *)r_edges;
			r_leftclipped = r_rightclipped = false;
			R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]], &r_pcurrentvertbase[r_pedge->v[1]], pclip);
			r_pedge->cachededgeoffset = cacheoffset;

			if (r_leftclipped)
				makeleftedge = true;
			if (r_rightclipped)
				makerightedge = true;
			r_lastvertvalid = true;
		} else {
			lindex = -lindex;
			r_pedge = &pedges[lindex];
			// if the edge is cached, we can just reuse the edge
			if (!insubmodel) {
				if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) {
					if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == r_framecount) {
						r_lastvertvalid = false;
						continue;
					}
				} else {
					// it's cached if the cached edge is valid and is owned by this medge_t
					if ((((unsigned long)edge_p - (unsigned long)r_edges) > r_pedge->cachededgeoffset) &&
						(((edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset))->owner == r_pedge))
					{
						R_EmitCachedEdge ();
						r_lastvertvalid = false;
						continue;
					}
				}
			}

			// assume it's cacheable
			cacheoffset = (byte *)edge_p - (byte *)r_edges;
			r_leftclipped = r_rightclipped = false;
			R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]], &r_pcurrentvertbase[r_pedge->v[0]], pclip);
			r_pedge->cachededgeoffset = cacheoffset;

			if (r_leftclipped)
				makeleftedge = true;
			if (r_rightclipped)
				makerightedge = true;
			r_lastvertvalid = true;
		}
	}

	// if there was a clip off the left edge, add that edge too
	// FIXME: faster to do in screen space?
	// FIXME: share clipped edges?
	if (makeleftedge) {
		r_pedge = &tedge;
		r_lastvertvalid = false;
		R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
	}

	// if there was a clip off the right edge, get the right r_nearzi
	if (makerightedge) {
		r_pedge = &tedge;
		r_lastvertvalid = false;
		r_nearzionly = true;
		R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
	}

	// if no edges made it out, return without posting the surface
	if (!r_emitted)
		return;

	r_polycount++;

	surface_p->data = (void *)fa;
	surface_p->nearzi = r_nearzi;
	surface_p->flags = fa->flags;
	surface_p->insubmodel = insubmodel;
	surface_p->spanstate = 0;
	surface_p->entity = currententity;
	surface_p->key = r_currentkey++;
	surface_p->spans = NULL;

	pplane = fa->plane;
	// FIXME: cache this?
	TransformVector (pplane->normal, p_normal);
	// FIXME: cache this?
	distinv = 1.0 / (-PlaneDiff(modelorg, pplane));

	surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
	surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
	surface_p->d_ziorigin = p_normal[2] * distinv - xcenter * surface_p->d_zistepu - ycenter * surface_p->d_zistepv;

	surface_p++;
}
Пример #18
0
/*
* R_WindingClipFragment
* 
* This function operates on windings (convex polygons without
* any points inside) like triangles, quads, etc. The output is
* a convex fragment (polygon, trifan) which the result of clipping
* the input winding by six fragment planes.
*/
static qboolean R_WindingClipFragment( vec3_t *wVerts, int numVerts, msurface_t *surf, vec3_t snorm )
{
	int i, j;
	int stage, newc, numv;
	cplane_t *plane;
	qboolean front;
	float *v, *nextv, d;
	float dists[MAX_FRAGMENT_VERTS+1];
	int sides[MAX_FRAGMENT_VERTS+1];
	vec3_t *verts, *newverts, newv[2][MAX_FRAGMENT_VERTS], t;
	fragment_t *fr;

	numv = numVerts;
	verts = wVerts;

	for( stage = 0, plane = fragmentPlanes; stage < 6; stage++, plane++ )
	{
		for( i = 0, v = verts[0], front = qfalse; i < numv; i++, v += 3 )
		{
			d = PlaneDiff( v, plane );

			if( d > ON_EPSILON )
			{
				front = qtrue;
				sides[i] = SIDE_FRONT;
			}
			else if( d < -ON_EPSILON )
			{
				sides[i] = SIDE_BACK;
			}
			else
			{
				front = qtrue;
				sides[i] = SIDE_ON;
			}
			dists[i] = d;
		}

		if( !front )
			return qfalse;

		// clip it
		sides[i] = sides[0];
		dists[i] = dists[0];

		newc = 0;
		newverts = newv[stage & 1];
		for( i = 0, v = verts[0]; i < numv; i++, v += 3 )
		{
			switch( sides[i] )
			{
			case SIDE_FRONT:
				if( newc == MAX_FRAGMENT_VERTS )
					return qfalse;
				VectorCopy( v, newverts[newc] );
				newc++;
				break;
			case SIDE_BACK:
				break;
			case SIDE_ON:
				if( newc == MAX_FRAGMENT_VERTS )
					return qfalse;
				VectorCopy( v, newverts[newc] );
				newc++;
				break;
			}

			if( sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i] )
				continue;
			if( newc == MAX_FRAGMENT_VERTS )
				return qfalse;

			d = dists[i] / ( dists[i] - dists[i+1] );
			nextv = ( i == numv - 1 ) ? verts[0] : v + 3;
			for( j = 0; j < 3; j++ )
				newverts[newc][j] = v[j] + d * ( nextv[j] - v[j] );
			newc++;
		}

		if( newc <= 2 )
			return qfalse;

		// continue with new verts
		numv = newc;
		verts = newverts;
	}

	// fully clipped
	if( numFragmentVerts + numv > maxFragmentVerts )
		return qfalse;

	fr = &clippedFragments[numClippedFragments++];
	fr->numverts = numv;
	fr->firstvert = numFragmentVerts;
	fr->fognum = surf->fog ? surf->fog - rsh.worldBrushModel->fogs + 1 : -1;
	VectorCopy( snorm, fr->normal );
	for( i = 0, v = verts[0], nextv = fragmentVerts[numFragmentVerts]; i < numv; i++, v += 3, nextv += 4 )
	{
		VectorCopy( v, nextv );
		nextv[3] = 1;
	}

	numFragmentVerts += numv;
	if( numFragmentVerts == maxFragmentVerts && numClippedFragments == maxClippedFragments )
		return qtrue;

	// if all of the following is true:
	// a) all clipping planes are perpendicular
	// b) there are 4 in a clipped fragment
	// c) all sides of the fragment are equal (it is a quad)
	// d) all sides are radius*2 +- epsilon (0.001)
	// then it is safe to assume there's only one fragment possible
	// not sure if it's 100% correct, but sounds convincing
	if( numv == 4 )
	{
		for( i = 0, v = verts[0]; i < numv; i++, v += 3 )
		{
			nextv = ( i == 3 ) ? verts[0] : v + 3;
			VectorSubtract( v, nextv, t );

			d = fragmentDiameterSquared - DotProduct( t, t );
			if( d > 0.01 || d < -0.01 )
				return qfalse;
		}
		return qtrue;
	}

	return qfalse;
}
Пример #19
0
/*
* R_RecursiveFragmentNode
*/
static void R_RecursiveFragmentNode( void )
{
	int stackdepth = 0;
	float dist;
	qboolean inside;
	mnode_t	*node, *localstack[2048];
	mleaf_t	*leaf;
	msurface_t *surf, **mark;

	for( node = rsh.worldBrushModel->nodes, stackdepth = 0;; )
	{
		if( node->plane == NULL )
		{
			leaf = ( mleaf_t * )node;
			mark = leaf->firstFragmentSurface;
			if( !mark )
				goto nextNodeOnStack;

			do
			{
				if( numFragmentVerts == maxFragmentVerts || numClippedFragments == maxClippedFragments )
					return; // already reached the limit

				surf = *mark++;
				if( surf->fragmentframe == r_fragmentframecount )
					continue;
				surf->fragmentframe = r_fragmentframecount;

				if( !BoundsAndSphereIntersect( surf->mins, surf->maxs, fragmentOrigin, fragmentRadius ) )
					continue;

				if( surf->facetype == FACETYPE_PATCH )
					inside = R_PatchSurfClipFragment( surf, fragmentNormal );
				else
					inside = R_PlanarSurfClipFragment( surf, fragmentNormal );

				// if there some fragments that are inside a surface, that doesn't mean that
				// there are no fragments that are OUTSIDE, so the check below is disabled
				//if( inside )
				//	return;
				(void)inside; // hush compiler warning
			} while( *mark );

			if( numFragmentVerts == maxFragmentVerts || numClippedFragments == maxClippedFragments )
				return; // already reached the limit

nextNodeOnStack:
			if( !stackdepth )
				break;
			node = localstack[--stackdepth];
			continue;
		}

		dist = PlaneDiff( fragmentOrigin, node->plane );
		if( dist > fragmentRadius )
		{
			node = node->children[0];
			continue;
		}

		if( ( dist >= -fragmentRadius ) && ( stackdepth < sizeof( localstack )/sizeof( mnode_t * ) ) )
			localstack[stackdepth++] = node->children[0];
		node = node->children[1];
	}
}
Пример #20
0
/*
================
R_RecursiveMirrorNode
================
*/
void R_RecursiveMirrorNode( mnode_t *node, uint clipflags )
{
	mextrasurf_t	*extrasurf;
	const mplane_t	*clipplane;
	int		i, clipped;
	msurface_t	*surf, **mark;
	mleaf_t		*pleaf;
	int		c, side;
	float		dot;

	if( node->contents == CONTENTS_SOLID )
		return; // hit a solid leaf

	if( node->visframe != tr.visframecount )
		return;

	if( clipflags )
	{
		for( i = 0, clipplane = RI.frustum; i < 6; i++, clipplane++ )
		{
			if(!( clipflags & ( 1<<i )))
				continue;

			clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, clipplane );
			if( clipped == 2 ) return;
			if( clipped == 1 ) clipflags &= ~(1<<i);
		}
	}

	// if a leaf node, draw stuff
	if( node->contents < 0 )
	{
		pleaf = (mleaf_t *)node;

		mark = pleaf->firstmarksurface;
		c = pleaf->nummarksurfaces;

		if( c )
		{
			do
			{
				(*mark)->visframe = tr.framecount;
				mark++;
			} while( --c );
		}
		return;
	}

	// node is just a decision point, so go down the apropriate sides

	// find which side of the node we are on
	dot = PlaneDiff( tr.modelorg, node->plane );
	side = (dot >= 0) ? 0 : 1;

	// recurse down the children, front side first
	R_RecursiveMirrorNode( node->children[side], clipflags );

	// draw stuff
	for( c = node->numsurfaces, surf = cl.worldmodel->surfaces + node->firstsurface; c; c--, surf++ )
	{
		if(!( surf->flags & SURF_REFLECT ))
			continue;

		if( R_CullSurface( surf, clipflags ))
			continue;

		extrasurf = SURF_INFO( surf, RI.currentmodel );
		extrasurf->mirrorchain = tr.mirror_entities[0].chain;
		tr.mirror_entities[0].chain = extrasurf;
	}

	// recurse down the back side
	R_RecursiveMirrorNode( node->children[!side], clipflags );
}
Пример #21
0
/*
================
R_RecursiveWorldNode
================
*/
static void R_RecursiveWorldNode(mnode_t *node, int clipflags)
{
    int         i, c, side, *pindex;
    vec3_t      acceptpt, rejectpt;
    cplane_t    *plane;
    mface_t     *surf, **mark;
    float       d, dot;
    mleaf_t     *pleaf;

    while (node->visframe == r_visframecount) {
        // cull the clipping planes if not trivial accept
        // FIXME: the compiler is doing a lousy job of optimizing here; it could be
        //  twice as fast in ASM
        if (clipflags) {
            for (i = 0; i < 4; i++) {
                if (!(clipflags & (1 << i)))
                    continue;   // don't need to clip against it

                // generate accept and reject points
                // FIXME: do with fast look-ups or integer tests based on the sign bit
                // of the floating point values

                pindex = pfrustum_indexes[i];

                rejectpt[0] = (float)node->minmaxs[pindex[0]];
                rejectpt[1] = (float)node->minmaxs[pindex[1]];
                rejectpt[2] = (float)node->minmaxs[pindex[2]];

                d = PlaneDiff(rejectpt, &view_clipplanes[i]);
                if (d <= 0)
                    return;

                acceptpt[0] = (float)node->minmaxs[pindex[3 + 0]];
                acceptpt[1] = (float)node->minmaxs[pindex[3 + 1]];
                acceptpt[2] = (float)node->minmaxs[pindex[3 + 2]];

                d = PlaneDiff(acceptpt, &view_clipplanes[i]);
                if (d >= 0)
                    clipflags &= ~(1 << i); // node is entirely on screen
            }
        }

        c_drawnode++;

        // if a leaf node, draw stuff
        if (!node->plane) {
            pleaf = (mleaf_t *)node;

            if (pleaf->contents == CONTENTS_SOLID)
                return;     // solid

            // check for door connected areas
            if (r_newrefdef.areabits) {
                if (! Q_IsBitSet(r_newrefdef.areabits, pleaf->area))
                    return;     // not visible
            }

            mark = pleaf->firstleafface;
            c = pleaf->numleaffaces;
            if (c) {
                do {
                    (*mark)->drawframe = r_framecount;
                    mark++;
                } while (--c);
            }

            pleaf->key = r_currentkey;
            r_currentkey++;     // all bmodels in a leaf share the same key
            return;
        }
        // node is just a decision point, so go down the apropriate sides

        // find which side of the node we are on
        plane = node->plane;

        dot = PlaneDiffFast(modelorg, plane);

        if (dot >= 0)
            side = 0;
        else
            side = 1;

        // recurse down the children, front side first
        R_RecursiveWorldNode(node->children[side], clipflags);

        // draw stuff
        c = node->numfaces;
        if (c) {
            surf = node->firstface;
            if (dot < -BACKFACE_EPSILON) {
                do {
                    if ((surf->drawflags & DSURF_PLANEBACK) &&
                        (surf->drawframe == r_framecount)) {
                        R_RenderFace(surf, clipflags);
                    }
                    surf++;
                } while (--c);
            } else if (dot > BACKFACE_EPSILON) {
                do {
                    if (!(surf->drawflags & DSURF_PLANEBACK) &&
                        (surf->drawframe == r_framecount)) {
                        R_RenderFace(surf, clipflags);
                    }
                    surf++;
                } while (--c);
            }

            // all surfaces on the same node share the same sequence number
            r_currentkey++;
        }

        // recurse down the back side
        node = node->children[side ^ 1];
    }
}
Пример #22
0
/*
* R_DrawPortalSurface
* 
* Renders the portal view and captures the results from framebuffer if
* we need to do a $portalmap stage. Note that for $portalmaps we must
* use a different viewport.
*/
static void R_DrawPortalSurface( portalSurface_t *portalSurface )
{
	unsigned int i;
	int x, y, w, h;
	float dist, d, best_d;
	vec3_t viewerOrigin;
	vec3_t origin;
	mat3_t axis;
	entity_t *ent, *best;
	const entity_t *portal_ent = portalSurface->entity;
	cplane_t *portal_plane = &portalSurface->plane, *untransformed_plane = &portalSurface->untransformed_plane;
	const shader_t *shader = portalSurface->shader;
	vec_t *portal_mins = portalSurface->mins, *portal_maxs = portalSurface->maxs;
	vec_t *portal_centre = portalSurface->centre;
	qboolean mirror, refraction = qfalse;
	image_t *captureTexture;
	int captureTextureId = -1;
	int prevRenderFlags = 0;
	qboolean doReflection, doRefraction;
	image_t *portalTexures[2] = { NULL, NULL };

	doReflection = doRefraction = qtrue;
	if( shader->flags & SHADER_PORTAL_CAPTURE )
	{
		shaderpass_t *pass;

		captureTexture = NULL;
		captureTextureId = 0;

		for( i = 0, pass = shader->passes; i < shader->numpasses; i++, pass++ )
		{
			if( pass->program_type == GLSL_PROGRAM_TYPE_DISTORTION )
			{
				if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 1 ) )
					doRefraction = qfalse;
				else if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 0 ) )
					doReflection = qfalse;
				break;
			}
		}
	}
	else
	{
		captureTexture = NULL;
		captureTextureId = -1;
	}

	x = y = 0;
	w = rn.refdef.width;
	h = rn.refdef.height;

	dist = PlaneDiff( rn.viewOrigin, portal_plane );
	if( dist <= BACKFACE_EPSILON || !doReflection )
	{
		if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) || !doRefraction )
			return;

		// even if we're behind the portal, we still need to capture
		// the second portal image for refraction
		refraction = qtrue;
		captureTexture = NULL;
		captureTextureId = 1;
		if( dist < 0 )
		{
			VectorInverse( portal_plane->normal );
			portal_plane->dist = -portal_plane->dist;
		}
	}

	if( !(rn.renderFlags & RF_NOVIS) && !R_ScissorForEntity( portal_ent, portal_mins, portal_maxs, &x, &y, &w, &h ) )
		return;

	mirror = qtrue; // default to mirror view
	// it is stupid IMO that mirrors require a RT_PORTALSURFACE entity

	best = NULL;
	best_d = 100000000;
	for( i = 1; i < rsc.numEntities; i++ )
	{
		ent = R_NUM2ENT(i);
		if( ent->rtype != RT_PORTALSURFACE )
			continue;

		d = PlaneDiff( ent->origin, untransformed_plane );
		if( ( d >= -64 ) && ( d <= 64 ) )
		{
			d = Distance( ent->origin, portal_centre );
			if( d < best_d )
			{
				best = ent;
				best_d = d;
			}
		}
	}

	if( best == NULL )
	{
		if( captureTextureId < 0 )
			return;
	}
	else
	{
		if( !VectorCompare( best->origin, best->origin2 ) )	// portal
			mirror = qfalse;
		best->rtype = NUM_RTYPES;
	}

	prevRenderFlags = rn.renderFlags;
	if( !R_PushRefInst() ) {
		return;
	}

	VectorCopy( rn.viewOrigin, viewerOrigin );

setup_and_render:

	if( refraction )
	{
		VectorInverse( portal_plane->normal );
		portal_plane->dist = -portal_plane->dist - 1;
		CategorizePlane( portal_plane );
		VectorCopy( rn.viewOrigin, origin );
		Matrix3_Copy( rn.refdef.viewaxis, axis );
		VectorCopy( viewerOrigin, rn.pvsOrigin );

		rn.renderFlags = RF_PORTALVIEW;
		if( !mirror )
			rn.renderFlags |= RF_PVSCULL;
	}
	else if( mirror )
	{
		VectorReflect( rn.viewOrigin, portal_plane->normal, portal_plane->dist, origin );

		VectorReflect( &rn.viewAxis[AXIS_FORWARD], portal_plane->normal, 0, &axis[AXIS_FORWARD] );
		VectorReflect( &rn.viewAxis[AXIS_RIGHT], portal_plane->normal, 0, &axis[AXIS_RIGHT] );
		VectorReflect( &rn.viewAxis[AXIS_UP], portal_plane->normal, 0, &axis[AXIS_UP] );

		Matrix3_Normalize( axis );

		VectorCopy( viewerOrigin, rn.pvsOrigin );

		rn.renderFlags = RF_MIRRORVIEW|RF_FLIPFRONTFACE;
	}
	else
	{
		vec3_t tvec;
		mat3_t A, B, C, rot;

		// build world-to-portal rotation matrix
		VectorNegate( portal_plane->normal, tvec );
		NormalVectorToAxis( tvec, A );

		// build portal_dest-to-world rotation matrix
		ByteToDir( best->frame, tvec );
		NormalVectorToAxis( tvec, B );
		Matrix3_Transpose( B, C );

		// multiply to get world-to-world rotation matrix
		Matrix3_Multiply( C, A, rot );

		// translate view origin
		VectorSubtract( rn.viewOrigin, best->origin, tvec );
		Matrix3_TransformVector( rot, tvec, origin );
		VectorAdd( origin, best->origin2, origin );

		Matrix3_Transpose( A, B );
		Matrix3_Multiply( rn.viewAxis, B, rot );
		Matrix3_Multiply( best->axis, rot, B );
		Matrix3_Transpose( C, A );
		Matrix3_Multiply( B, A, axis );

		// set up portal_plane
		VectorCopy( &axis[AXIS_FORWARD], portal_plane->normal );
		portal_plane->dist = DotProduct( best->origin2, portal_plane->normal );
		CategorizePlane( portal_plane );

		// for portals, vis data is taken from portal origin, not
		// view origin, because the view point moves around and
		// might fly into (or behind) a wall
		rn.renderFlags = RF_PORTALVIEW|RF_PVSCULL;
		VectorCopy( best->origin2, rn.pvsOrigin );
		VectorCopy( best->origin2, rn.lodOrigin );

		// ignore entities, if asked politely
		if( best->renderfx & RF_NOPORTALENTS )
			rn.renderFlags |= RF_NOENTS;
	}

	rn.renderFlags |= (prevRenderFlags & RF_SOFT_PARTICLES);
	rn.refdef.rdflags &= ~( RDF_UNDERWATER|RDF_CROSSINGWATER );

	rn.shadowGroup = NULL;
	rn.meshlist = &r_portallist;

	rn.renderFlags |= RF_CLIPPLANE;
	rn.clipPlane = *portal_plane;

	rn.farClip = R_DefaultFarClip();

	rn.clipFlags |= ( 1<<5 );
	rn.frustum[5] = *portal_plane;
	CategorizePlane( &rn.frustum[5] );

	// if we want to render to a texture, initialize texture
	// but do not try to render to it more than once
	if( captureTextureId >= 0 )
	{
		int texFlags = shader->flags & SHADER_NO_TEX_FILTERING ? IT_NOFILTERING : 0;

		captureTexture = R_GetPortalTexture( rsc.refdef.width, rsc.refdef.height, texFlags,
			rsc.frameCount );
		portalTexures[captureTextureId] = captureTexture;

		if( !captureTexture ) {
			// couldn't register a slot for this plane
			goto done;
		}

		x = y = 0;
		w = captureTexture->upload_width;
		h = captureTexture->upload_height;
		rn.refdef.width = w;
		rn.refdef.height = h;
		rn.refdef.x = 0;
		rn.refdef.y = 0;
		rn.fbColorAttachment = captureTexture;
		// no point in capturing the depth buffer due to oblique frustum messing up
		// the far plane and depth values
		rn.fbDepthAttachment = NULL;
		Vector4Set( rn.viewport, rn.refdef.x + x, rn.refdef.y + y, w, h );
		Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h );
	}
	else {
		// no point in capturing the depth buffer due to oblique frustum messing up
		// the far plane and depth values
		rn.fbDepthAttachment = NULL;
		Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h );
	}

	VectorCopy( origin, rn.refdef.vieworg );
	Matrix3_Copy( axis, rn.refdef.viewaxis );

	R_RenderView( &rn.refdef );

	if( doRefraction && !refraction && ( shader->flags & SHADER_PORTAL_CAPTURE2 ) )
	{
		refraction = qtrue;
		captureTexture = NULL;
		captureTextureId = 1;
		goto setup_and_render;
	}

done:
	portalSurface->texures[0] = portalTexures[0];
	portalSurface->texures[1] = portalTexures[1];

	R_PopRefInst( rn.fbDepthAttachment != NULL ? 0 : GL_DEPTH_BUFFER_BIT );
}
Пример #23
0
/*
* R_RecursiveWorldNode
*/
static void R_RecursiveWorldNode( mnode_t *node, unsigned int clipFlags, 
	unsigned int dlightBits, unsigned int shadowBits )
{
	unsigned int i;
	unsigned int dlightBits1;
	unsigned int shadowBits1;
	unsigned int bit;
	const cplane_t *clipplane;
	mleaf_t	*pleaf;

	while( 1 )
	{
		if( node->pvsframe != rf.pvsframecount )
			return;

		if( clipFlags )
		{
			for( i = sizeof( rn.frustum )/sizeof( rn.frustum[0] ), bit = 1, clipplane = rn.frustum; i > 0; i--, bit<<=1, clipplane++ )
			{
				if( clipFlags & bit )
				{
					int clipped = BoxOnPlaneSide( node->mins, node->maxs, clipplane );
					if( clipped == 2 )
						return;
					else if( clipped == 1 )
						clipFlags &= ~bit; // node is entirely on screen
				}
			}
		}

		if( !node->plane )
			break;

		dlightBits1 = 0;
		if( dlightBits )
		{
			float dist;
			unsigned int checkBits = dlightBits;

			for( i = 0, bit = 1; i < rsc.numDlights; i++, bit <<= 1 )
			{
				dlight_t *dl = rsc.dlights + i;
				if( dlightBits & bit )
				{
					dist = PlaneDiff( dl->origin, node->plane );
					if( dist < -dl->intensity )
						dlightBits &= ~bit;
					if( dist < dl->intensity )
						dlightBits1 |= bit;

					checkBits &= ~bit;
					if( !checkBits )
						break;
				}
			}
		}

		shadowBits1 = 0;
		if( shadowBits )
		{
			unsigned int checkBits = shadowBits;

			for( i = 0; i < rsc.numShadowGroups; i++ )
			{
				shadowGroup_t *group = rsc.shadowGroups + i;
				bit = group->bit;
				if( checkBits & bit )
				{
					int clipped = BOX_ON_PLANE_SIDE( group->visMins, group->visMaxs, node->plane );
					if( !(clipped & 1) )
						shadowBits &= ~bit;
					if( clipped & 2 )
						shadowBits1 |= bit;

					checkBits &= ~bit;
					if( !checkBits )
						break;
				}
			}
		}

		R_RecursiveWorldNode( node->children[0], clipFlags, dlightBits, shadowBits );

		node = node->children[1];
		dlightBits = dlightBits1;
		shadowBits = shadowBits1;
	}

	// if a leaf node, draw stuff
	pleaf = ( mleaf_t * )node;
	pleaf->visframe = rf.frameCount;

	// add leaf bounds to view bounds
	for( i = 0; i < 3; i++ )
	{
		rn.visMins[i] = min( rn.visMins[i], pleaf->mins[i] );
		rn.visMaxs[i] = max( rn.visMaxs[i], pleaf->maxs[i] );
	}

	rn.dlightBits |= dlightBits;
	rn.shadowBits |= shadowBits;

	R_MarkLeafSurfaces( pleaf->firstVisSurface, clipFlags, dlightBits, shadowBits );
	rf.stats.c_world_leafs++;
}
Пример #24
0
/*
* R_AddPortalSurface
*/
portalSurface_t *R_AddPortalSurface( const entity_t *ent, const mesh_t *mesh, 
	const vec3_t mins, const vec3_t maxs, const shader_t *shader )
{
	unsigned int i;
	float dist;
	cplane_t plane, untransformed_plane;
	vec3_t v[3];
	portalSurface_t *portalSurface;

	if( !mesh ) {
		return NULL;
	}

	if( R_FASTSKY() && !( shader->flags & (SHADER_PORTAL_CAPTURE|SHADER_PORTAL_CAPTURE2) ) ) {
		// r_fastsky doesn't affect portalmaps
		return NULL;
	}

	for( i = 0; i < 3; i++ ) {
		VectorCopy( mesh->xyzArray[mesh->elems[i]], v[i] );
	}

	PlaneFromPoints( v, &untransformed_plane );
	untransformed_plane.dist += DotProduct( ent->origin, untransformed_plane.normal );
	CategorizePlane( &untransformed_plane );

	if( shader->flags & SHADER_AUTOSPRITE )
	{
		vec3_t centre;

		// autosprites are quads, facing the viewer
		if( mesh->numVerts < 4 ) {
			return NULL;
		}

		// compute centre as average of 4 vertices
		VectorCopy( mesh->xyzArray[mesh->elems[3]], centre );
		for( i = 0; i < 3; i++ )
			VectorAdd( centre, v[i], centre );
		VectorMA( ent->origin, 0.25, centre, centre );

		VectorNegate( &rn.viewAxis[AXIS_FORWARD], plane.normal );
		plane.dist = DotProduct( plane.normal, centre );
		CategorizePlane( &plane );
	}
	else
	{
		vec3_t temp;
		mat3_t entity_rotation;

		// regular surfaces
		if( !Matrix3_Compare( ent->axis, axis_identity ) )
		{
			Matrix3_Transpose( ent->axis, entity_rotation );

			for( i = 0; i < 3; i++ ) {
				VectorCopy( v[i], temp );
				Matrix3_TransformVector( entity_rotation, temp, v[i] ); 
				VectorMA( ent->origin, ent->scale, v[i], v[i] );
			}

			PlaneFromPoints( v, &plane );
			CategorizePlane( &plane );
		}
		else
		{
			plane = untransformed_plane;
		}
	}

	if( ( dist = PlaneDiff( rn.viewOrigin, &plane ) ) <= BACKFACE_EPSILON )
	{
		// behind the portal plane
		if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) {
			return NULL;
		}

		// we need to render the backplane view
	}

	// check if portal view is opaque due to alphagen portal
	if( shader->portalDistance && dist > shader->portalDistance ) {
		return NULL;
	}

	// find the matching portal plane
	for( i = 0; i < rn.numPortalSurfaces; i++ ) {
		portalSurface = &rn.portalSurfaces[i];

		if( portalSurface->entity == ent &&
			portalSurface->shader == shader &&
			DotProduct( portalSurface->plane.normal, plane.normal ) > 0.99f &&
			fabs( portalSurface->plane.dist - plane.dist ) < 0.1f ) {
				goto addsurface;
		}
	}

	if( i == MAX_PORTAL_SURFACES ) {
		// not enough space
		return NULL;
	}

	portalSurface = &rn.portalSurfaces[rn.numPortalSurfaces++];
	portalSurface->entity = ent;
	portalSurface->plane = plane;
	portalSurface->shader = shader;
	portalSurface->untransformed_plane = untransformed_plane;
	ClearBounds( portalSurface->mins, portalSurface->maxs );
	memset( portalSurface->texures, 0, sizeof( portalSurface->texures ) );

addsurface:
	AddPointToBounds( mins, portalSurface->mins, portalSurface->maxs );
	AddPointToBounds( maxs, portalSurface->mins, portalSurface->maxs );
	VectorAdd( portalSurface->mins, portalSurface->maxs, portalSurface->centre );
	VectorScale( portalSurface->centre, 0.5, portalSurface->centre );

	return portalSurface;
}
Пример #25
0
/*
* R_RenderMeshGLSL_Distortion
*/
static void R_RenderMeshGLSL_Distortion( r_glslfeat_t programFeatures )
{
	int i, last_slot;
	unsigned last_framenum;
	int state, tcgen;
	int width = 1, height = 1;
	int program, object;
	mat4x4_t unused;
	cplane_t plane;
	const char *key;
	shaderpass_t *pass = r_back.accumPasses[0];
	image_t *portaltexture[2];
	qboolean frontPlane;

	PlaneFromPoints( r_back.r_triangle0Copy, &plane );
	plane.dist += DotProduct( ri.currententity->origin, plane.normal );
	key = R_PortalKeyForPlane( &plane );
	last_framenum = last_slot = 0;

	for( i = 0; i < 2; i++ )
	{
		int slot;

		portaltexture[i] = NULL;

		slot = R_FindPortalTextureSlot( key, i+1 );
		if( slot )
			portaltexture[i] = r_portaltextures[slot-1];

		if( portaltexture[i] == NULL )
		{
			portaltexture[i] = r_blacktexture;
		}
		else
		{
			width = portaltexture[i]->upload_width;
			height = portaltexture[i]->upload_height;
		}

		// find the most recently updated texture
		if( portaltexture[i]->framenum > last_framenum )
		{
			last_slot = i;
			last_framenum = i;
		}
	}

	// if textures were not updated sequentially, use the most recent one
	// and reset the remaining to black
	if( portaltexture[0]->framenum+1 != portaltexture[1]->framenum )
		portaltexture[(last_slot+1)&1] = r_blacktexture;

	if( pass->anim_frames[0] != r_blankbumptexture )
		programFeatures |= GLSL_DISTORTION_APPLY_DUDV;
	if( ri.params & RP_CLIPPLANE )
		programFeatures |= GLSL_COMMON_APPLY_CLIPPING;
	if( pass->flags & SHADERPASS_GRAYSCALE )
		programFeatures |= GLSL_COMMON_APPLY_GRAYSCALE;
	if( portaltexture[0] != r_blacktexture )
		programFeatures |= GLSL_DISTORTION_APPLY_REFLECTION;
	if( portaltexture[1] != r_blacktexture )
		programFeatures |= GLSL_DISTORTION_APPLY_REFRACTION;

	frontPlane = (PlaneDiff( ri.viewOrigin, &ri.portalPlane ) > 0 ? qtrue : qfalse);

	if( frontPlane )
	{
		if( pass->alphagen.type != ALPHA_GEN_IDENTITY )
			programFeatures |= GLSL_DISTORTION_APPLY_DISTORTION_ALPHA;
	}

	tcgen = pass->tcgen;                // store the original tcgen

	R_BindShaderpass( pass, pass->anim_frames[0], 0, NULL );  // dudvmap

	// calculate the fragment color
	R_ModifyColor( pass, programFeatures & GLSL_DISTORTION_APPLY_DISTORTION_ALPHA ? qtrue : qfalse, qfalse );

	GL_TexEnv( GL_MODULATE );

	// set shaderpass state (blending, depthwrite, etc)
	state = r_back.currentShaderState | ( pass->flags & r_back.currentShaderPassMask ) | GLSTATE_BLEND_MTEX;
	GL_SetState( state );

	if( pass->anim_frames[1] )
	{	// eyeDot
		programFeatures |= GLSL_DISTORTION_APPLY_EYEDOT;

		pass->tcgen = TC_GEN_SVECTORS;
		GL_Bind( 1, pass->anim_frames[1] ); // normalmap
		GL_SetTexCoordArrayMode( GL_TEXTURE_COORD_ARRAY );
		R_VertexTCBase( pass, 1, unused, NULL );
	}

	GL_Bind( 2, portaltexture[0] );            // reflection
	GL_Bind( 3, portaltexture[1] );           // refraction

	pass->tcgen = tcgen;    // restore original tcgen

	// update uniforms
	program = R_RegisterGLSLProgram( pass->program_type, pass->program, NULL, NULL, NULL, 0, programFeatures );
	object = R_GetProgramObject( program );
	if( object )
	{
		qglUseProgramObjectARB( object );

		R_UpdateProgramUniforms( program, ri.viewOrigin, vec3_origin, vec3_origin, NULL, NULL, NULL,
			frontPlane, width, height, 0, 0, 0, 
			colorArrayCopy[0], r_back.overBrightBits, r_back.currentShaderTime, r_back.entityColor );

		R_FlushArrays();

		qglUseProgramObjectARB( 0 );
	}
}
Пример #26
0
void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) {
	int i, j, lindex, numsurfaces;
	vec_t dot;
	msurface_t *psurf;
	mplane_t *pplane;
	mvertex_t bverts[MAX_BMODEL_VERTS];
	bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
	medge_t *pedge, *pedges;

	// FIXME: use bounding-box-based frustum clipping info?

	psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
	numsurfaces = pmodel->nummodelsurfaces;
	pedges = pmodel->edges;

	for (i = 0 ; i < numsurfaces; i++, psurf++) {
		// find which side of the node we are on
		pplane = psurf->plane;

		dot = PlaneDiff (modelorg, pplane);

		// draw the polygon
		if (((psurf->flags & SURF_PLANEBACK) && dot < -BACKFACE_EPSILON) ||
			(!(psurf->flags & SURF_PLANEBACK) && dot > BACKFACE_EPSILON))
		{
			// FIXME: use bounding-box-based frustum clipping info?

			// copy the edges to bedges, flipping if necessary so always clockwise winding
			// FIXME: if edges and vertices get caches, these assignments must move
			// outside the loop, and overflow checking must be done here
			pbverts = bverts;
			pbedges = bedges;
			numbverts = numbedges = 0;

			if (psurf->numedges > 0) {
				pbedge = &bedges[numbedges];
				numbedges += psurf->numedges;

				for (j = 0; j < psurf->numedges; j++) {
				   lindex = pmodel->surfedges[psurf->firstedge + j];

					if (lindex > 0) {
						pedge = &pedges[lindex];
						pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
						pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
					} else {
						lindex = -lindex;
						pedge = &pedges[lindex];
						pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
						pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
					}

					pbedge[j].pnext = &pbedge[j + 1];
				}

				pbedge[j-1].pnext = NULL;	// mark end of edges

				R_RecursiveClipBPoly (pbedge, currententity->topnode, psurf);
			} else {
				Sys_Error ("no edges in bmodel");
			}
		}
	}
}