示例#1
0
/*
** SurfIsOffscreen
**
** Determines if a surface is completely offscreen.
*/
static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {
	float shortest = 100000000;
	int entityNum;
	int numTriangles;
	shader_t *shader;
	int		fogNum;
	int dlighted;
	vec4_t clip, eye;
	int i;
	unsigned int pointOr = 0;
	unsigned int pointAnd = (unsigned int)~0;

	R_RotateForViewer();

	R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
	RB_BeginSurface( shader, fogNum );
	rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );

	assert( tess.numVertexes < 128 );

	for ( i = 0; i < tess.numVertexes; i++ )
	{
		int j;
		unsigned int pointFlags = 0;

		R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip );

		for ( j = 0; j < 3; j++ )
		{
			if ( clip[j] >= clip[3] )
			{
				pointFlags |= (1 << (j*2));
			}
			else if ( clip[j] <= -clip[3] )
			{
				pointFlags |= ( 1 << (j*2+1));
			}
		}
		pointAnd &= pointFlags;
		pointOr |= pointFlags;
	}

	// trivially reject
	if ( pointAnd )
	{
		return qtrue;
	}

	// determine if this surface is backfaced and also determine the distance
	// to the nearest vertex so we can cull based on portal range.  Culling
	// based on vertex distance isn't 100% correct (we should be checking for
	// range to the surface), but it's good enough for the types of portals
	// we have in the game right now.
	numTriangles = tess.numIndexes / 3;

	for ( i = 0; i < tess.numIndexes; i += 3 )
	{
		vec3_t normal;
		float len;

		VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal );

		len = VectorLengthSquared( normal );			// lose the sqrt
		if ( len < shortest )
		{
			shortest = len;
		}

		if ( DotProduct( normal, tess.normal[tess.indexes[i]] ) >= 0 )
		{
			numTriangles--;
		}
	}
	if ( !numTriangles )
	{
		return qtrue;
	}

	// mirrors can early out at this point, since we don't do a fade over distance
	// with them (although we could)
	if ( IsMirror( drawSurf, entityNum ) )
	{
		return qfalse;
	}

	if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) )
	{
		return qtrue;
	}

	return qfalse;
}
示例#2
0
/*
==================
RB_AddFlare

This is called at surface tesselation time
==================
*/
void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal, float lightScale) {
	int				i;
	flare_t			*f, *oldest;
	vec3_t			local;
	float			d;
	vec4_t			eye, clip, normalized, window;

	backEnd.pc.c_flareAdds++;

	// if the point is off the screen, don't bother adding it
	// calculate screen coordinates and depth
	R_TransformModelToClip( point, backEnd.or.modelMatrix, 
		backEnd.viewParms.projectionMatrix, eye, clip );

	// check to see if the point is completely off screen
	for ( i = 0 ; i < 3 ; i++ ) {
		if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) {
			return;
		}
	}

	R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window );

	if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
		|| window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) {
		return;	// shouldn't happen, since we check the clip[] above, except for FP rounding
	}

	// see if a flare with a matching surface, scene, and view exists
	oldest = r_flareStructs;
	for ( f = r_activeFlares ; f ; f = f->next ) {
		if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum
			&& f->inPortal == backEnd.viewParms.isPortal ) {
			break;
		}
	}

	// allocate a new one
	if (!f ) {
		if ( !r_inactiveFlares ) {
			// the list is completely full
			return;
		}
		f = r_inactiveFlares;
		r_inactiveFlares = r_inactiveFlares->next;
		f->next = r_activeFlares;
		r_activeFlares = f;

		f->surface = surface;
		f->frameSceneNum = backEnd.viewParms.frameSceneNum;
		f->inPortal = backEnd.viewParms.isPortal;
		f->addedFrame = -1;
	}

	if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) {
		f->visible = qfalse;
		f->fadeTime = backEnd.refdef.time - 2000;
	}

	f->addedFrame = backEnd.viewParms.frameCount;
	f->fogNum = fogNum;
	f->lightScale = lightScale;

	VectorCopy( color, f->color );

	// fade the intensity of the flare down as the
	// light surface turns away from the viewer
	if ( normal ) {
		VectorSubtract( backEnd.viewParms.or.origin, point, local );
		VectorNormalizeFast( local );
		d = DotProduct( local, normal );
		VectorScale( f->color, d, f->color ); 
	}

	// save info needed to test
	f->windowX = backEnd.viewParms.viewportX + window[0];
	f->windowY = backEnd.viewParms.viewportY + window[1];

	f->eyeZ = eye[2];
}
示例#3
0
/*
=========================
R_PreciseCullSurface

Check the surface for visibility on a per-triangle basis
for cases when it is going to be VERY expensive to draw (subviews)

If not culled, also returns the bounding box of the surface in
Normalized Device Coordinates, so it can be used to crop the scissor rect.

OPTIMIZE: we could also take exact portal passing into consideration
=========================
*/
bool R_PreciseCullSurface( const drawSurf_t *drawSurf, idBounds &ndcBounds ) {
	const srfTriangles_t	*tri;
	int						numTriangles;
	idPlane					clip, eye;
	int						i, j, k;
	unsigned int			pointOr;
	unsigned int			pointAnd;
	unsigned int			pointFlags;
	idVec3					localView;
	idFixedWinding			w;
	tri = drawSurf->geo;
	pointOr = 0;
	pointAnd = ( unsigned int )~0;
	// get an exact bounds of the triangles for scissor cropping
	ndcBounds.Clear();
	for( i = 0; i < tri->numVerts; i++ ) {
		R_TransformModelToClip( tri->verts[i].xyz, drawSurf->space->modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip );
		pointFlags = 0;
		for( k = 0; k < 3; k++ ) {
			if( clip[k] >= clip[3] ) {
				pointFlags |= ( 1 << ( k * 2 ) );
			} else if( clip[k] <= -clip[3] ) {
				pointFlags |= ( 1 << ( k * 2 + 1 ) );
			}
		}
		pointAnd &= pointFlags;
		pointOr |= pointFlags;
	}
	// trivially reject
	if( pointAnd ) {
		return true;
	}
	// backface and frustum cull
	numTriangles = tri->numIndexes / 3;
	R_GlobalPointToLocal( drawSurf->space->modelMatrix, tr.viewDef->renderView.vieworg, localView );
	for( i = 0; i < tri->numIndexes; i += 3 ) {
		idVec3			dir, normal;
		float			dot;
		idVec3			d1, d2;
		const idVec3	&v1 = tri->verts[tri->indexes[i]].xyz;
		const idVec3	&v2 = tri->verts[tri->indexes[i + 1]].xyz;
		const idVec3	&v3 = tri->verts[tri->indexes[i + 2]].xyz;
		// this is a hack, because R_GlobalPointToLocal doesn't work with the non-normalized
		// axis that we get from the gui view transform.  It doesn't hurt anything, because
		// we know that all gui generated surfaces are front facing
		if( tr.guiRecursionLevel == 0 ) {
			// we don't care that it isn't normalized,
			// all we want is the sign
			d1 = v2 - v1;
			d2 = v3 - v1;
			normal = d2.Cross( d1 );
			dir = v1 - localView;
			dot = normal * dir;
			if( dot >= 0.0f ) {
				return true;
			}
		}
		// now find the exact screen bounds of the clipped triangle
		w.SetNumPoints( 3 );
		R_LocalPointToGlobal( drawSurf->space->modelMatrix, v1, w[0].ToVec3() );
		R_LocalPointToGlobal( drawSurf->space->modelMatrix, v2, w[1].ToVec3() );
		R_LocalPointToGlobal( drawSurf->space->modelMatrix, v3, w[2].ToVec3() );
		w[0].s = w[0].t = w[1].s = w[1].t = w[2].s = w[2].t = 0.0f;
		for( j = 0; j < 4; j++ ) {
			if( !w.ClipInPlace( -tr.viewDef->frustum[j], 0.1f ) ) {
				break;
			}
		}
		for( j = 0; j < w.GetNumPoints(); j++ ) {
			idVec3	screen;
			R_GlobalToNormalizedDeviceCoordinates( w[j].ToVec3(), screen );
			ndcBounds.AddPoint( screen );
		}
	}
	// if we don't enclose any area, return
	if( ndcBounds.IsCleared() ) {
		return true;
	}
	return false;
}
示例#4
0
idScreenRect R_CalcLightScissorRectangle( viewLight_t *vLight )
{
	idScreenRect		r;
	srfTriangles_t		*tri;
	idPlane				eye, clip;
	idVec3				ndc;
	
	if( vLight->lightDef->parms.pointLight )
	{
		idBounds			bounds;
		idRenderLightLocal	*lightDef = vLight->lightDef;
		tr.viewDef->viewFrustum.ProjectionBounds( idBox( lightDef->parms.origin, lightDef->parms.lightRadius, lightDef->parms.axis ), bounds );
		return R_ScreenRectFromViewFrustumBounds( bounds );
	}
	
	if( r_useClippedLightScissors.GetInteger() == 2 )
	{
		return R_ClippedLightScissorRectangle( vLight );
	}
	r.Clear();
	
	tri = vLight->lightDef->frustumTris;
	
	for( int i = 0; i < tri->numVerts; i++ )
	{
		R_TransformModelToClip( tri->verts[i].xyz, tr.viewDef->worldSpace.modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip );
		
		// if it is near clipped, clip the winding polygons to the view frustum
		if( clip[3] <= 1 )
		{
			c_clippedLight++;
			
			if( r_useClippedLightScissors.GetInteger() )
			{
				return R_ClippedLightScissorRectangle( vLight );
			}
			else
			{
				r.x1 = r.y1 = 0;
				r.x2 = ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) - 1;
				r.y2 = ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) - 1;
				return r;
			}
		}
		R_TransformClipToDevice( clip, ndc );
		
		float windowX = 0.5f * ( 1.0f + ndc[0] ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 );
		float windowY = 0.5f * ( 1.0f + ndc[1] ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 );
		
		if( windowX > tr.viewDef->scissor.x2 )
		{
			windowX = tr.viewDef->scissor.x2;
		}
		else if( windowX < tr.viewDef->scissor.x1 )
		{
			windowX = tr.viewDef->scissor.x1;
		}
		
		if( windowY > tr.viewDef->scissor.y2 )
		{
			windowY = tr.viewDef->scissor.y2;
		}
		else if( windowY < tr.viewDef->scissor.y1 )
		{
			windowY = tr.viewDef->scissor.y1;
		}
		r.AddPoint( windowX, windowY );
	}
	
	// add the fudge boundary
	r.Expand();
	
	c_unclippedLight++;
	
	return r;
}
示例#5
0
/*
=======================================================================================================================================
RB_AddFlare

This is called at surface tesselation time
=======================================================================================================================================
*/
void RB_AddFlare(void *surface, int fogNum, vec3_t point, vec3_t color, float scale, vec3_t normal, int id, int flags) {  //----(SA)	added scale. added id.  added visible
	int i;
	flare_t         *f;
	vec3_t local;
	float d = 1;
	vec4_t eye, clip, normalized, window;

	backEnd.pc.c_flareAdds++;

	if(normal && (normal[0] || normal[1] || normal[2]))
	{
		VectorSubtract(backEnd.viewParms.or.origin, point, local);
		VectorNormalizeFast(local);
		d = DotProduct(local, normal);

		// If the viewer is behind the flare don't add it.
		if(d < 0)
			return;
	}

	// if the point is off the screen, don't bother adding it
	// calculate screen coordinates and depth
	R_TransformModelToClip(point, backEnd.or.modelMatrix,
							backEnd.viewParms.projectionMatrix, eye, clip);

	//ri.Printf(PRINT_ALL, "src:  %f  %f  %f  \n", point[0], point[1], point[2]);
	//ri.Printf(PRINT_ALL, "eye:  %f  %f  %f  %f\n", eye[0], eye[1], eye[2], eye[3]);

	// check to see if the point is completely off screen
	for (i = 0 ; i < 3 ; i++) {
		if (clip[i] >= clip[3] || clip[i] <= -clip[3]) {
			return;
		}
	}

	R_TransformClipToWindow(clip, &backEnd.viewParms, normalized, window);

	//ri.Printf(PRINT_ALL, "window:  %f  %f  %f  \n", window[0], window[1], window[2]);

	if (window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
		 || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight) {
		return; // shouldn't happen, since we check the clip[] above, except for FP rounding
	}

	// see if a flare with a matching surface, scene, and view exists
	for (f = r_activeFlares ; f ; f = f->next) {
//		if (f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum && f->inPortal == backEnd.viewParms.isPortal) {

		// (SA) added back in more checks for different scenes
		if (f->id == id && f->frameSceneNum == backEnd.viewParms.frameSceneNum && f->inPortal == backEnd.viewParms.isPortal) {
			break;
		}
	}

	// allocate a new one
	if (!f) {
		if (!r_inactiveFlares) {
			// the list is completely full
			return;
		}
		f = r_inactiveFlares;
		r_inactiveFlares = r_inactiveFlares->next;
		f->next = r_activeFlares;
		r_activeFlares = f;

		f->surface = surface;
		f->frameSceneNum = backEnd.viewParms.frameSceneNum;
		f->inPortal = backEnd.viewParms.isPortal;
		f->addedFrame = -1;
		f->id = id;
	}

	f->flags = flags;

	if (f->addedFrame != backEnd.viewParms.frameCount - 1) {
		f->visible = qfalse;
		f->fadeTime = backEnd.refdef.time - 2000;
	}

	f->addedFrame = backEnd.viewParms.frameCount;
	f->fogNum = fogNum;

	VectorCopy(point, f->origin);
	VectorCopy(color, f->color);

	f->scale = scale;   //----(SA)

	// fade the intensity of the flare down as the
	// light surface turns away from the viewer
	VectorScale(f->color, d, f->color);

	// save info needed to test
	f->windowX = backEnd.viewParms.viewportX + window[0];
	f->windowY = backEnd.viewParms.viewportY + window[1];

	f->eyeZ = eye[2];
}
示例#6
0
/*
======================
R_ClippedLightScissorRectangle
======================
*/
idScreenRect R_ClippedLightScissorRectangle( viewLight_t *vLight )
{
	int							i, j;
	const idRenderLightLocal	*light = vLight->lightDef;
	idScreenRect				r;
	idFixedWinding				w;
	
	r.Clear();
	
	for( i = 0; i < 6; i++ )
	{
		const idWinding *ow = light->frustumWindings[i];
		
		// projected lights may have one of the frustums degenerated
		if( !ow )
		{
			continue;
		}
		
		// the light frustum planes face out from the light,
		// so the planes that have the view origin on the negative
		// side will be the "back" faces of the light, which must have
		// some fragment inside the portalStack to be visible
		if( light->frustum[i].Distance( tr.viewDef->renderView.vieworg ) >= 0 )
		{
			continue;
		}
		w = *ow;
		
		// now check the winding against each of the frustum planes
		for( j = 0; j < 5; j++ )
		{
			if( !w.ClipInPlace( -tr.viewDef->frustum[j] ) )
			{
				break;
			}
		}
		
		// project these points to the screen and add to bounds
		for( j = 0; j < w.GetNumPoints(); j++ )
		{
			idPlane		eye, clip;
			idVec3		ndc;
			
			R_TransformModelToClip( w[j].ToVec3(), tr.viewDef->worldSpace.modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip );
			
			if( clip[3] <= 0.01f )
			{
				clip[3] = 0.01f;
			}
			R_TransformClipToDevice( clip, ndc );
			
			float windowX = 0.5f * ( 1.0f + ndc[0] ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 );
			float windowY = 0.5f * ( 1.0f + ndc[1] ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 );
			
			if( windowX > tr.viewDef->scissor.x2 )
			{
				windowX = tr.viewDef->scissor.x2;
			}
			else if( windowX < tr.viewDef->scissor.x1 )
			{
				windowX = tr.viewDef->scissor.x1;
			}
			
			if( windowY > tr.viewDef->scissor.y2 )
			{
				windowY = tr.viewDef->scissor.y2;
			}
			else if( windowY < tr.viewDef->scissor.y1 )
			{
				windowY = tr.viewDef->scissor.y1;
			}
			r.AddPoint( windowX, windowY );
		}
	}
	
	// add the fudge boundary
	r.Expand();
	
	return r;
}
示例#7
0
/*
===================
R_EntityDefDynamicModel

Issues a deferred entity callback if necessary.
If the model isn't dynamic, it returns the original.
Returns the cached dynamic model if present, otherwise creates
it and any necessary overlays
===================
*/
idRenderModel *R_EntityDefDynamicModel( idRenderEntityLocal *def )
{
	bool callbackUpdate;
	
	// allow deferred entities to construct themselves
	if( def->parms.callback )
	{
		callbackUpdate = R_IssueEntityDefCallback( def );
	}
	else
	{
		callbackUpdate = false;
	}
	idRenderModel *model = def->parms.hModel;
	
	if( !model )
	{
		common->Error( "R_EntityDefDynamicModel: NULL model" );
	}
	
	if( model->IsDynamicModel() == DM_STATIC )
	{
		def->dynamicModel = NULL;
		def->dynamicModelFrameCount = 0;
		return model;
	}
	
	// continously animating models (particle systems, etc) will have their snapshot updated every single view
	if( callbackUpdate || ( model->IsDynamicModel() == DM_CONTINUOUS && def->dynamicModelFrameCount != tr.frameCount ) )
	{
		R_ClearEntityDefDynamicModel( def );
	}
	
	// if we don't have a snapshot of the dynamic model, generate it now
	if( !def->dynamicModel )
	{
		// instantiate the snapshot of the dynamic model, possibly reusing memory from the cached snapshot
		def->cachedDynamicModel = model->InstantiateDynamicModel( &def->parms, tr.viewDef, def->cachedDynamicModel );
		
		if( def->cachedDynamicModel )
		{
			// add any overlays to the snapshot of the dynamic model
			if( def->overlay && !r_skipOverlays.GetBool() )
			{
				def->overlay->AddOverlaySurfacesToModel( def->cachedDynamicModel );
			}
			else
			{
				idRenderModelOverlay::RemoveOverlaySurfacesFromModel( def->cachedDynamicModel );
			}
			
			if( r_checkBounds.GetBool() )
			{
				idBounds b = def->cachedDynamicModel->Bounds();
				
				if( b[0][0] < def->referenceBounds[0][0] - CHECK_BOUNDS_EPSILON ||
						b[0][1] < def->referenceBounds[0][1] - CHECK_BOUNDS_EPSILON ||
						b[0][2] < def->referenceBounds[0][2] - CHECK_BOUNDS_EPSILON ||
						b[1][0] > def->referenceBounds[1][0] + CHECK_BOUNDS_EPSILON ||
						b[1][1] > def->referenceBounds[1][1] + CHECK_BOUNDS_EPSILON ||
						b[1][2] > def->referenceBounds[1][2] + CHECK_BOUNDS_EPSILON )
				{
					common->Printf( "entity %i dynamic model exceeded reference bounds\n", def->index );
				}
			}
		}
		def->dynamicModel = def->cachedDynamicModel;
		def->dynamicModelFrameCount = tr.frameCount;
	}
	
	// set model depth hack value
	if( def->dynamicModel && model->DepthHack() != 0.0f && tr.viewDef )
	{
		idPlane eye, clip;
		idVec3	ndc;
		
		R_TransformModelToClip( def->parms.origin, tr.viewDef->worldSpace.modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip );
		R_TransformClipToDevice( clip, ndc );
		
		def->parms.modelDepthHack = model->DepthHack() * ( 1.0f - ndc.z );
	}
	
	// FIXME: if any of the surfaces have deforms, create a frame-temporary model with references to the
	// undeformed surfaces.  This would allow deforms to be light interacting.
	return def->dynamicModel;
}
/*
=========================
R_PreciseCullSurface

Check the surface for visibility on a per-triangle basis
for cases when it is going to be VERY expensive to draw (subviews)

If not culled, also returns the bounding box of the surface in
Normalized Device Coordinates, so it can be used to crop the scissor rect.

OPTIMIZE: we could also take exact portal passing into consideration
=========================
*/
bool R_PreciseCullSurface( const drawSurf_t* drawSurf, idBounds& ndcBounds )
{
	const srfTriangles_t* tri = drawSurf->frontEndGeo;
	
	unsigned int pointOr = 0;
	unsigned int pointAnd = ( unsigned int )~0;
	
	// get an exact bounds of the triangles for scissor cropping
	ndcBounds.Clear();
	
	const idJointMat* joints = ( tri->staticModelWithJoints != NULL && r_useGPUSkinning.GetBool() ) ? tri->staticModelWithJoints->jointsInverted : NULL;
	
	for( int i = 0; i < tri->numVerts; i++ )
	{
		const idVec3 vXYZ = idDrawVert::GetSkinnedDrawVertPosition( tri->verts[i], joints );
		
		idPlane eye, clip;
		R_TransformModelToClip( vXYZ, drawSurf->space->modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip );
		
		unsigned int pointFlags = 0;
		for( int j = 0; j < 3; j++ )
		{
			if( clip[j] >= clip[3] )
			{
				pointFlags |= ( 1 << ( j * 2 + 0 ) );
			}
			else if( clip[j] <= -clip[3] )  	// FIXME: the D3D near clip plane is at zero instead of -1
			{
				pointFlags |= ( 1 << ( j * 2 + 1 ) );
			}
		}
		
		pointAnd &= pointFlags;
		pointOr |= pointFlags;
	}
	
	// trivially reject
	if( pointAnd != 0 )
	{
		return true;
	}
	
	// backface and frustum cull
	idVec3 localViewOrigin;
	R_GlobalPointToLocal( drawSurf->space->modelMatrix, tr.viewDef->renderView.vieworg, localViewOrigin );
	
	for( int i = 0; i < tri->numIndexes; i += 3 )
	{
		const idVec3 v1 = idDrawVert::GetSkinnedDrawVertPosition( tri->verts[ tri->indexes[ i + 0 ] ], joints );
		const idVec3 v2 = idDrawVert::GetSkinnedDrawVertPosition( tri->verts[ tri->indexes[ i + 1 ] ], joints );
		const idVec3 v3 = idDrawVert::GetSkinnedDrawVertPosition( tri->verts[ tri->indexes[ i + 2 ] ], joints );
		
		// this is a hack, because R_GlobalPointToLocal doesn't work with the non-normalized
		// axis that we get from the gui view transform.  It doesn't hurt anything, because
		// we know that all gui generated surfaces are front facing
		if( tr.guiRecursionLevel == 0 )
		{
			// we don't care that it isn't normalized,
			// all we want is the sign
			const idVec3 d1 = v2 - v1;
			const idVec3 d2 = v3 - v1;
			const idVec3 normal = d2.Cross( d1 );
			
			const idVec3 dir = v1 - localViewOrigin;
			
			const float dot = normal * dir;
			if( dot >= 0.0f )
			{
				return true;
			}
		}
		
		// now find the exact screen bounds of the clipped triangle
		idFixedWinding w;
		w.SetNumPoints( 3 );
		R_LocalPointToGlobal( drawSurf->space->modelMatrix, v1, w[0].ToVec3() );
		R_LocalPointToGlobal( drawSurf->space->modelMatrix, v2, w[1].ToVec3() );
		R_LocalPointToGlobal( drawSurf->space->modelMatrix, v3, w[2].ToVec3() );
		w[0].s = w[0].t = w[1].s = w[1].t = w[2].s = w[2].t = 0.0f;
		
		for( int j = 0; j < 4; j++ )
		{
			if( !w.ClipInPlace( -tr.viewDef->frustums[FRUSTUM_PRIMARY][j], 0.1f ) )
			{
				break;
			}
		}
		for( int j = 0; j < w.GetNumPoints(); j++ )
		{
			idVec3 screen;
			
			R_GlobalToNormalizedDeviceCoordinates( w[j].ToVec3(), screen );
			ndcBounds.AddPoint( screen );
		}
	}
	
	// if we don't enclose any area, return
	if( ndcBounds.IsCleared() )
	{
		return true;
	}
	
	return false;
}
/*
===================
R_EntityDefDynamicModel

This is also called by the game code for idRenderWorldLocal::ModelTrace(), and idRenderWorldLocal::Trace() which is bad for performance...

Issues a deferred entity callback if necessary.
If the model isn't dynamic, it returns the original.
Returns the cached dynamic model if present, otherwise creates it.
===================
*/
idRenderModel* R_EntityDefDynamicModel( idRenderEntityLocal* def )
{
	if( def->dynamicModelFrameCount == tr.frameCount )
	{
		return def->dynamicModel;
	}
	
	// allow deferred entities to construct themselves
	bool callbackUpdate;
	if( def->parms.callback != NULL )
	{
		SCOPED_PROFILE_EVENT( "R_IssueEntityDefCallback" );
		callbackUpdate = R_IssueEntityDefCallback( def );
	}
	else
	{
		callbackUpdate = false;
	}
	
	idRenderModel* model = def->parms.hModel;
	
	if( model == NULL )
	{
		common->Error( "R_EntityDefDynamicModel: NULL model" );
		return NULL;
	}
	
	if( model->IsDynamicModel() == DM_STATIC )
	{
		def->dynamicModel = NULL;
		def->dynamicModelFrameCount = 0;
		return model;
	}
	
	// continously animating models (particle systems, etc) will have their snapshot updated every single view
	if( callbackUpdate || ( model->IsDynamicModel() == DM_CONTINUOUS && def->dynamicModelFrameCount != tr.frameCount ) )
	{
		R_ClearEntityDefDynamicModel( def );
	}
	
	// if we don't have a snapshot of the dynamic model, generate it now
	if( def->dynamicModel == NULL )
	{
	
		SCOPED_PROFILE_EVENT( "InstantiateDynamicModel" );
		
		// instantiate the snapshot of the dynamic model, possibly reusing memory from the cached snapshot
		def->cachedDynamicModel = model->InstantiateDynamicModel( &def->parms, tr.viewDef, def->cachedDynamicModel );
		
		if( def->cachedDynamicModel != NULL && r_checkBounds.GetBool() )
		{
			idBounds b = def->cachedDynamicModel->Bounds();
			if(	b[0][0] < def->localReferenceBounds[0][0] - CHECK_BOUNDS_EPSILON ||
					b[0][1] < def->localReferenceBounds[0][1] - CHECK_BOUNDS_EPSILON ||
					b[0][2] < def->localReferenceBounds[0][2] - CHECK_BOUNDS_EPSILON ||
					b[1][0] > def->localReferenceBounds[1][0] + CHECK_BOUNDS_EPSILON ||
					b[1][1] > def->localReferenceBounds[1][1] + CHECK_BOUNDS_EPSILON ||
					b[1][2] > def->localReferenceBounds[1][2] + CHECK_BOUNDS_EPSILON )
			{
				common->Printf( "entity %i dynamic model exceeded reference bounds\n", def->index );
			}
		}
		
		def->dynamicModel = def->cachedDynamicModel;
		def->dynamicModelFrameCount = tr.frameCount;
	}
	
	// set model depth hack value
	if( def->dynamicModel != NULL && model->DepthHack() != 0.0f && tr.viewDef != NULL )
	{
		idPlane eye, clip;
		idVec3 ndc;
		R_TransformModelToClip( def->parms.origin, tr.viewDef->worldSpace.modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip );
		R_TransformClipToDevice( clip, ndc );
		def->parms.modelDepthHack = model->DepthHack() * ( 1.0f - ndc.z );
	}
	else
	{
		def->parms.modelDepthHack = 0.0f;
	}
	
	return def->dynamicModel;
}
示例#10
0
void RB_AddFlare(srfFlare_t *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal, int radii, int efftype, float scaled, int type) {
	int				i;
	flare_t			*f, *oldest;
	vec3_t			local;
	float			d = 1;
	vec4_t			eye, clip, normalized, window;

	backEnd.pc.c_flareAdds++;

	// fade the intensity of the flare down as the
	// light surface turns away from the viewer
	if(normal && (normal[0] || normal[1] || normal[2]) )
	{
		VectorSubtract( backEnd.viewParms.or.origin, point, local );
		VectorNormalizeFast(local);
		d = DotProduct(local, normal);

		// If the viewer is behind the flare don't add it.
		if(d < 0)
			return;
	}

	flaredsize = backEnd.viewParms.viewportHeight;

	R_TransformModelToClip( point, backEnd.or.modelMatrix, 
		backEnd.viewParms.projectionMatrix, eye, clip );

	


	// check to see if the point is completely off screen
	for ( i = 0 ; i < 3 ; i++ ) {
		if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) {
			return;
		}
	}


	R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window );

	if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
		|| window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) {
		return;	// shouldn't happen, since we check the clip[] above, except for FP rounding
	}

	// see if a flare with a matching surface, scene, and view exists
	oldest = r_flareStructs;
	for ( f = r_activeFlares ; f ; f = f->next ) {
		if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum
			&& f->inPortal == backEnd.viewParms.isPortal ) {
			break;
		}
	}

	// allocate a new one
	if (!f ) {
		if ( !r_inactiveFlares ) {
			// the list is completely full
			return;
		}
		f = r_inactiveFlares;
		r_inactiveFlares = r_inactiveFlares->next;
		f->next = r_activeFlares;
		r_activeFlares = f;

		f->surface = surface;
		f->frameSceneNum = backEnd.viewParms.frameSceneNum;
		f->inPortal = backEnd.viewParms.isPortal;
		f->addedFrame = -1;
	}

	if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) {
		f->visible = qfalse;
		f->fadeTime = backEnd.refdef.time - 2000;
	}

	f->addedFrame = backEnd.viewParms.frameCount;
	f->fogNum = fogNum;
	f->ftype = efftype;
	VectorCopy(point, f->origin);
	VectorCopy( color, f->color );


	if ( (r_flaresDlightFade->integer) && (type == 1) ) {	// leilei - dynamic light flares fading instantly
		f->fadeTime = -666;
	}





	if (!pvrhack)	// leilei - don't do this on powervr
	VectorScale( f->color, d, f->color ); 

	// save info needed to test
	f->windowX = backEnd.viewParms.viewportX + window[0];
	f->windowY = backEnd.viewParms.viewportY + window[1];


	f->radius = radii * scaled * 0.17; 
	f->eyeZ = eye[2];
	f->theshader = tr.flareShader;
	f->type = type;

	if (f->type == 0)
	f->theshader = surface->shadder;
	else
	f->theshader = tr.flareShader;


	if ( (type == 1) && (r_flaresDlightScale->value) ) {	// leilei - dynamic light flare scale
		float ef = r_flaresDlightScale->value;
			if (ef > 1.0f) ef = 1.0f;
			if (ef < 0.01f) ef = 0.01f;
			
		f->radius *= ef;
	}

	if ( (type == 1) && (r_flaresDlightOpacity->value) ) {	// leilei - dynamic light flare scale
		float ef = r_flaresDlightOpacity->value;
			if (ef > 1.0f) ef = 1.0f;
			if (ef < 0.1f) ef = 0.1f;
			
		f->color[0] *= ef;
		f->color[1] *= ef;
		f->color[2] *= ef;
	}


//	if ( (r_flaresDlightShrink->integer) && (type == 1) ) 	// leilei - dynamic light flares shrinking when close
//	{


//	}	


}