示例#1
0
文件: r_cmds.c 项目: MGXRace/racesow
/*
* R_EnvShot_f
*/
void R_EnvShot_f( void )
{
	int i;
	int size, maxSize;
	const char *writedir, *gamedir;
	int checkname_size;
	char *checkname;
	refdef_t fd;
	struct	cubemapSufAndFlip
	{
		char *suf; vec3_t angles; int flags;
	} cubemapShots[6] = {
		{ "px", { 0, 0, 0 }, IT_FLIPX|IT_FLIPY|IT_FLIPDIAGONAL },
		{ "nx", { 0, 180, 0 }, IT_FLIPDIAGONAL },
		{ "py", { 0, 90, 0 }, IT_FLIPY },
		{ "ny", { 0, 270, 0 }, IT_FLIPX },
		{ "pz", { -90, 180, 0 }, IT_FLIPDIAGONAL },
		{ "nz", { 90, 180, 0 }, IT_FLIPDIAGONAL }
	};

	if( !R_ScreenEnabled() || !rsh.worldModel )
		return;

	if( ri.Cmd_Argc() != 3 )
	{
		Com_Printf( "usage: envshot <name> <size>\n" );
		return;
	}

	maxSize = min( min( glConfig.width, glConfig.height ), glConfig.maxTextureSize );
	if( maxSize > atoi( ri.Cmd_Argv( 2 ) ) )
		maxSize = atoi( ri.Cmd_Argv( 2 ) );

	for( size = 1; size < maxSize; size <<= 1 ) ;
	if( size > maxSize )
		size >>= 1;

	writedir = ri.FS_WriteDirectory();
	gamedir = ri.FS_GameDirectory();
	checkname_size = strlen( writedir ) + 1 + strlen( gamedir ) + strlen( "/env/" ) + 
		strlen( ri.Cmd_Argv( 1 ) ) + 1 + strlen( cubemapShots[0].suf ) + 4 + 1;
	checkname = alloca( checkname_size );

	fd = rsc.refdef;
	fd.time = 0;
	//fd.x = fd.y = 0;
	fd.width = fd.height = size;
	fd.fov_x = fd.fov_y = 90;

	rn.farClip = R_DefaultFarClip();

	// do not render non-bmodel entities
	rn.renderFlags |= RF_CUBEMAPVIEW;
	rn.clipFlags = 15;
	rn.shadowGroup = NULL;
	rn.fbColorAttachment = rn.fbDepthAttachment = NULL;

	Vector4Set( rn.viewport, fd.x, glConfig.height - size - fd.y, size, size );
	Vector4Set( rn.scissor, fd.x, glConfig.height - size - fd.y, size, size );

	for( i = 0; i < 6; i++ )
	{
		AnglesToAxis( cubemapShots[i].angles, fd.viewaxis );

		R_RenderView( &fd );

		Q_snprintfz( checkname, checkname_size, "%s/%s/env/%s_%s", writedir, gamedir, ri.Cmd_Argv( 1 ), cubemapShots[i].suf );
		COM_DefaultExtension( checkname, ".tga", checkname_size );

		R_ScreenShot( checkname, 0, 0, size, size, 100, 
			( cubemapShots[i].flags & IT_FLIPX ) ? true : false, 
			( cubemapShots[i].flags & IT_FLIPY ) ? true : false, 
			( cubemapShots[i].flags & IT_FLIPDIAGONAL ) ? true : false,
			false );
	}

	// render non-bmodel entities again
	rn.renderFlags &= ~RF_CUBEMAPVIEW;
}
示例#2
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 );
}
示例#3
0
/*
* R_DrawSkyPortal
*/
void R_DrawSkyPortal( const entity_t *e, skyportal_t *skyportal, vec3_t mins, vec3_t maxs )
{
	int x, y, w, h;

	if( !R_ScissorForEntity( e, mins, maxs, &x, &y, &w, &h ) ) {
		return;
	}
	if( !R_PushRefInst() ) {
		return;
	}

	rn.renderFlags = ( rn.renderFlags|RF_SKYPORTALVIEW|RF_SOFT_PARTICLES );
	VectorCopy( skyportal->vieworg, rn.pvsOrigin );

	rn.farClip = R_DefaultFarClip();

	rn.clipFlags = 15;
	rn.shadowGroup = NULL;
	rn.meshlist = &r_skyportallist;
	//Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h );

	if( skyportal->noEnts ) {
		rn.renderFlags |= RF_NOENTS;
	}

	if( skyportal->scale )
	{
		vec3_t centre, diff;

		VectorAdd( rsh.worldModel->mins, rsh.worldModel->maxs, centre );
		VectorScale( centre, 0.5f, centre );
		VectorSubtract( centre, rn.viewOrigin, diff );
		VectorMA( skyportal->vieworg, -skyportal->scale, diff, rn.refdef.vieworg );
	}
	else
	{
		VectorCopy( skyportal->vieworg, rn.refdef.vieworg );
	}

	// FIXME
	if( !VectorCompare( skyportal->viewanglesOffset, vec3_origin ) )
	{
		vec3_t angles;
		mat3_t axis;

		Matrix3_Copy( rn.refdef.viewaxis, axis );
		VectorInverse( &axis[AXIS_RIGHT] );
		Matrix3_ToAngles( axis, angles );

		VectorAdd( angles, skyportal->viewanglesOffset, angles );
		AnglesToAxis( angles, axis );
		Matrix3_Copy( axis, rn.refdef.viewaxis );
	}

	rn.refdef.rdflags &= ~( RDF_UNDERWATER|RDF_CROSSINGWATER|RDF_SKYPORTALINVIEW );
	if( skyportal->fov )
	{
		rn.refdef.fov_x = skyportal->fov;
		rn.refdef.fov_y = CalcFov( rn.refdef.fov_x, rn.refdef.width, rn.refdef.height );
		if( glConfig.wideScreen && !( rn.refdef.rdflags & RDF_NOFOVADJUSTMENT ) )
			AdjustFov( &rn.refdef.fov_x, &rn.refdef.fov_y, glConfig.width, glConfig.height, qfalse );
	}

	R_RenderView( &rn.refdef );

	// restore modelview and projection matrices, scissoring, etc for the main view
	R_PopRefInst( ~GL_COLOR_BUFFER_BIT );
}
示例#4
0
/*
* R_RenderScene
*/
void R_RenderScene( const refdef_t *fd )
{
	int fbFlags = 0;
	int ppFrontBuffer = 0;
	image_t *ppSource;

	if( r_norefresh->integer )
		return;

	R_Set2DMode( false );

	RB_SetTime( fd->time );

	if( !( fd->rdflags & RDF_NOWORLDMODEL ) )
		rsc.refdef = *fd;

	rn.refdef = *fd;
	if( !rn.refdef.minLight ) {
		rn.refdef.minLight = 0.1f;
	}

	fd = &rn.refdef;

	rn.renderFlags = RF_NONE;

	rn.farClip = R_DefaultFarClip();
	rn.clipFlags = 15;
	if( rsh.worldModel && !( fd->rdflags & RDF_NOWORLDMODEL ) && rsh.worldBrushModel->globalfog )
		rn.clipFlags |= 16;
	rn.meshlist = &r_worldlist;
	rn.portalmasklist = &r_portalmasklist;
	rn.shadowBits = 0;
	rn.dlightBits = 0;
	rn.shadowGroup = NULL;

	fbFlags = 0;
	rn.fbColorAttachment = rn.fbDepthAttachment = NULL;
	
	if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
		if( r_soft_particles->integer && ( rsh.screenTexture != NULL ) ) {
			rn.fbColorAttachment = rsh.screenTexture;
			rn.fbDepthAttachment = rsh.screenDepthTexture;
			rn.renderFlags |= RF_SOFT_PARTICLES;
			fbFlags |= 1;
		}

		if( rsh.screenPPCopies[0] && rsh.screenPPCopies[1] ) {
			int oldFlags = fbFlags;
			shader_t *cc = rn.refdef.colorCorrection;

			if( r_fxaa->integer ) {
				fbFlags |= 2;
			}

			if( cc && cc->numpasses > 0 && cc->passes[0].images[0] && cc->passes[0].images[0] != rsh.noTexture ) {
				fbFlags |= 4;
			}

			if( fbFlags != oldFlags ) {
				if( !rn.fbColorAttachment ) {
					rn.fbColorAttachment = rsh.screenPPCopies[0];
					ppFrontBuffer = 1;
				}
			}
		}
	}

	ppSource = rn.fbColorAttachment;

	// clip new scissor region to the one currently set
	Vector4Set( rn.scissor, fd->scissor_x, fd->scissor_y, fd->scissor_width, fd->scissor_height );
	Vector4Set( rn.viewport, fd->x, fd->y, fd->width, fd->height );
	VectorCopy( fd->vieworg, rn.pvsOrigin );
	VectorCopy( fd->vieworg, rn.lodOrigin );

	R_BindFrameBufferObject( 0 );

	R_BuildShadowGroups();

	R_RenderView( fd );

	R_RenderDebugSurface( fd );

	R_RenderDebugBounds();

	R_BindFrameBufferObject( 0 );

	R_Set2DMode( true );

	if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
		ri.Mutex_Lock( rf.speedsMsgLock );
		R_WriteSpeedsMessage( rf.speedsMsg, sizeof( rf.speedsMsg ) );
		ri.Mutex_Unlock( rf.speedsMsgLock );
	}

	// blit and blend framebuffers in proper order

	if( fbFlags == 1 ) {
		// only blit soft particles directly when we don't have any other post processing
		// otherwise use the soft particles FBO as the base texture on the next layer
		// to avoid wasting time on resolves and the fragment shader to blit to a temp texture
		R_BlitTextureToScrFbo( fd,
			ppSource, 0,
			GLSL_PROGRAM_TYPE_NONE,
			colorWhite, 0,
			0, NULL );
	}
	fbFlags &= ~1;

	// apply FXAA
	if( fbFlags & 2 ) {
		image_t *dest;

		fbFlags &= ~2;
		dest = fbFlags ? rsh.screenPPCopies[ppFrontBuffer] : NULL;

		R_BlitTextureToScrFbo( fd,
			ppSource, dest ? dest->fbo : 0,
			GLSL_PROGRAM_TYPE_FXAA,
			colorWhite, 0,
			0, NULL );

		ppFrontBuffer ^= 1;
		ppSource = dest;
	}

	// apply color correction
	if( fbFlags & 4 ) {
		image_t *dest;

		fbFlags &= ~4;
		dest = fbFlags ? rsh.screenPPCopies[ppFrontBuffer] : NULL;

		R_BlitTextureToScrFbo( fd,
			ppSource, dest ? dest->fbo : 0,
			GLSL_PROGRAM_TYPE_COLORCORRECTION,
			colorWhite, 0,
			1, &( rn.refdef.colorCorrection->passes[0].images[0] ) );
	}
}
示例#5
0
文件: r_cmds.c 项目: adem4ik/qfusion
	for( size = 1; size < maxSize; size <<= 1 ) ;
	if( size > maxSize ) {
		size >>= 1;
	}

	checkname_size = strlen( path ) + strlen( name ) + 1 + strlen( cubemapShots[0].suf ) + 4 + 1;
	checkname = alloca( checkname_size );

	fd = rsc.refdef;
	fd.time = 0;
	//fd.x = fd.y = 0;
	fd.width = fd.height = size;
	fd.fov_x = fd.fov_y = 90;

	rn.farClip = R_DefaultFarClip();

	// do not render non-bmodel entities
	rn.renderFlags |= RF_CUBEMAPVIEW;
	rn.clipFlags = 15;
	rn.shadowGroup = NULL;
	rn.renderTarget = 0;

	Vector4Set( rn.viewport, fd.x, glConfig.height - size - fd.y, size, size );
	Vector4Set( rn.scissor, fd.x, glConfig.height - size - fd.y, size, size );

	for( i = 0; i < 6; i++ ) {
		AnglesToAxis( cubemapShots[i].angles, fd.viewaxis );

		R_RenderView( &fd );
示例#6
0
/*
* R_DrawSkyportal
*/
static void R_DrawSkyportal( const entity_t *e, skyportal_t *skyportal ) {
	if( !R_PushRefInst() ) {
		return;
	}

	rn.renderFlags = ( rn.renderFlags | RF_PORTALVIEW );
	//rn.renderFlags &= ~RF_SOFT_PARTICLES;
	VectorCopy( skyportal->vieworg, rn.pvsOrigin );

	rn.nearClip = Z_NEAR;
	rn.farClip = R_DefaultFarClip();
	rn.polygonFactor = POLYOFFSET_FACTOR;
	rn.polygonUnits = POLYOFFSET_UNITS;

	rn.clipFlags = 15;
	rn.meshlist = &r_skyportallist;
	rn.portalmasklist = NULL;
	rn.rtLight = NULL;
	//Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h );

	if( skyportal->noEnts ) {
		rn.renderFlags |= RF_ENVVIEW;
	}

	if( skyportal->scale ) {
		vec3_t centre, diff;

		VectorAdd( rsh.worldModel->mins, rsh.worldModel->maxs, centre );
		VectorScale( centre, 0.5f, centre );
		VectorSubtract( centre, rn.viewOrigin, diff );
		VectorMA( skyportal->vieworg, -skyportal->scale, diff, rn.refdef.vieworg );
	} else {
		VectorCopy( skyportal->vieworg, rn.refdef.vieworg );
	}

	// FIXME
	if( !VectorCompare( skyportal->viewanglesOffset, vec3_origin ) ) {
		vec3_t angles;
		mat3_t axis;

		Matrix3_Copy( rn.refdef.viewaxis, axis );
		VectorInverse( &axis[AXIS_RIGHT] );
		Matrix3_ToAngles( axis, angles );

		VectorAdd( angles, skyportal->viewanglesOffset, angles );
		AnglesToAxis( angles, axis );
		Matrix3_Copy( axis, rn.refdef.viewaxis );
	}

	rn.refdef.rdflags &= ~( RDF_UNDERWATER | RDF_CROSSINGWATER | RDF_SKYPORTALINVIEW );
	if( skyportal->fov ) {
		rn.refdef.fov_y = WidescreenFov( skyportal->fov );
		rn.refdef.fov_x = CalcHorizontalFov( rn.refdef.fov_y, rn.refdef.width, rn.refdef.height );
	}

	R_SetupViewMatrices( &rn.refdef );

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

	R_SetupPVS( &rn.refdef );

	R_RenderView( &rn.refdef );

	// restore modelview and projection matrices, scissoring, etc for the main view
	R_PopRefInst();
}
示例#7
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();
}
示例#8
0
/*
* R_RenderScene
*/
void R_RenderScene( const refdef_t *fd )
{
	int fbFlags = 0;

	if( r_norefresh->integer )
		return;

	R_Set2DMode( qfalse );

	RB_SetTime( fd->time );

	if( !( fd->rdflags & RDF_NOWORLDMODEL ) )
		rsc.refdef = *fd;

	rn.refdef = *fd;
	if( !rn.refdef.minLight ) {
		rn.refdef.minLight = 0.1f;
	}
	if( !rsh.screenWeaponTexture || rn.refdef.weaponAlpha == 1 ) {
		rn.refdef.rdflags &= ~RDF_WEAPONALPHA;
	}

	fd = &rn.refdef;

	rn.renderFlags = RF_NONE;

	rn.farClip = R_DefaultFarClip();
	rn.clipFlags = 15;
	if( rsh.worldModel && !( fd->rdflags & RDF_NOWORLDMODEL ) && rsh.worldBrushModel->globalfog )
		rn.clipFlags |= 16;
	rn.meshlist = &r_worldlist;
	rn.shadowBits = 0;
	rn.dlightBits = 0;
	rn.shadowGroup = NULL;

	fbFlags = 0;
	rn.fbColorAttachment = rn.fbDepthAttachment = NULL;
	
	if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
		// soft particles require GL_EXT_framebuffer_blit as we need to copy the depth buffer
		// attachment into a texture we're going to read from in GLSL shader
		if( r_soft_particles->integer && glConfig.ext.framebuffer_blit && ( rsh.screenTexture != NULL ) ) {
			rn.fbColorAttachment = rsh.screenTexture;
			rn.fbDepthAttachment = rsh.screenDepthTexture;
			rn.renderFlags |= RF_SOFT_PARTICLES;
			fbFlags |= 1;
		}
		if( ( fd->rdflags & RDF_WEAPONALPHA ) && ( rsh.screenWeaponTexture != NULL ) ) {
			fbFlags |= 2;
		}
		if( r_fxaa->integer && ( rsh.screenFxaaCopy != NULL ) ) {
			if( !rn.fbColorAttachment ) {
				rn.fbColorAttachment = rsh.screenFxaaCopy;
			}
			fbFlags |= 4;
		}
	}

	// adjust field of view for widescreen
	if( glConfig.wideScreen && !( fd->rdflags & RDF_NOFOVADJUSTMENT ) )
		AdjustFov( &rn.refdef.fov_x, &rn.refdef.fov_y, glConfig.width, glConfig.height, qfalse );

	// clip new scissor region to the one currently set
	Vector4Set( rn.scissor, fd->scissor_x, fd->scissor_y, fd->scissor_width, fd->scissor_height );
	Vector4Set( rn.viewport, fd->x, fd->y, fd->width, fd->height );
	VectorCopy( fd->vieworg, rn.pvsOrigin );
	VectorCopy( fd->vieworg, rn.lodOrigin );

	if( gl_finish->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) )
		qglFinish();

	if( fbFlags & 2 ) {
		// clear the framebuffer we're going to render the weapon model to
		// set the alpha to 0, visible parts of the model will overwrite that,
		// creating proper alpha mask
		R_BindFrameBufferObject( rsh.screenWeaponTexture->fbo );
		RB_Clear( GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT, 0, 0, 0, 0 );
	}

	R_BindFrameBufferObject( 0 );

	R_BuildShadowGroups();

	R_RenderView( fd );

	R_RenderDebugSurface( fd );

	R_RenderDebugBounds();

	R_BindFrameBufferObject( 0 );

	R_Set2DMode( qtrue );

	// blit and blend framebuffers in proper order

	if( fbFlags & 1 ) {
		// copy to FXAA or default framebuffer
		R_BlitTextureToScrFbo( fd, rn.fbColorAttachment, 
			fbFlags & 4 ? rsh.screenFxaaCopy->fbo : 0, 
			GLSL_PROGRAM_TYPE_NONE, 
			colorWhite, 0 );
	}

	if( fbFlags & 2 ) {
		vec4_t color = { 1, 1, 1, 1 };
		color[3] = fd->weaponAlpha;

		// blend to FXAA or default framebuffer
		R_BlitTextureToScrFbo( fd, rsh.screenWeaponTexture, 
			fbFlags & 4 ? rsh.screenFxaaCopy->fbo : 0, 
			GLSL_PROGRAM_TYPE_NONE, 
			color, GLSTATE_SRCBLEND_SRC_ALPHA|GLSTATE_DSTBLEND_ONE_MINUS_SRC_ALPHA );
	}

	// blit FXAA to default framebuffer
	if( fbFlags & 4 ) {
		// blend to FXAA or default framebuffer
		R_BlitTextureToScrFbo( fd, rsh.screenFxaaCopy, 0, 
			GLSL_PROGRAM_TYPE_FXAA, 
			colorWhite, 0 );
	}
}