Example #1
0
/*
================
EmitSurfaces

For full screen GUIs, we can add in per-surface stereoscopic depth effects
================
*/
void idGuiModel::EmitSurfaces( float modelMatrix[16], float modelViewMatrix[16],
							   bool depthHack, bool allowFullScreenStereoDepth, bool linkAsEntity )
{

	viewEntity_t* guiSpace = ( viewEntity_t* )R_ClearedFrameAlloc( sizeof( *guiSpace ), FRAME_ALLOC_VIEW_ENTITY );
	memcpy( guiSpace->modelMatrix, modelMatrix, sizeof( guiSpace->modelMatrix ) );
	memcpy( guiSpace->modelViewMatrix, modelViewMatrix, sizeof( guiSpace->modelViewMatrix ) );
	guiSpace->weaponDepthHack = depthHack;
	guiSpace->isGuiSurface = true;
	
	// If this is an in-game gui, we need to be able to find the matrix again for head mounted
	// display bypass matrix fixup.
	if( linkAsEntity )
	{
		guiSpace->next = tr.viewDef->viewEntitys;
		tr.viewDef->viewEntitys = guiSpace;
	}
	
	//---------------------------
	// make a tech5 renderMatrix
	//---------------------------
	idRenderMatrix viewMat;
	idRenderMatrix::Transpose( *( idRenderMatrix* )modelViewMatrix, viewMat );
	idRenderMatrix::Multiply( tr.viewDef->projectionRenderMatrix, viewMat, guiSpace->mvp );
	if( depthHack )
	{
		idRenderMatrix::ApplyDepthHack( guiSpace->mvp );
	}
	
	// to allow 3D-TV effects in the menu system, we define surface flags to set
	// depth fractions between 0=screen and 1=infinity, which directly modulate the
	// screenSeparation parameter for an X offset.
	// The value is stored in the drawSurf sort value, which adjusts the matrix in the
	// backend.
	float defaultStereoDepth = stereoRender_defaultGuiDepth.GetFloat();	// default to at-screen
	
	// add the surfaces to this view
	for( int i = 0; i < surfaces.Num(); i++ )
	{
		const guiModelSurface_t& guiSurf = surfaces[i];
		if( guiSurf.numIndexes == 0 )
		{
			continue;
		}
		
		const idMaterial* shader = guiSurf.material;
		drawSurf_t* drawSurf = ( drawSurf_t* )R_FrameAlloc( sizeof( *drawSurf ), FRAME_ALLOC_DRAW_SURFACE );
		
		drawSurf->numIndexes = guiSurf.numIndexes;
		drawSurf->ambientCache = vertexBlock;
		// build a vertCacheHandle_t that points inside the allocated block
		drawSurf->indexCache = indexBlock + ( ( int64 )( guiSurf.firstIndex * sizeof( triIndex_t ) ) << VERTCACHE_OFFSET_SHIFT );
		drawSurf->shadowCache = 0;
		drawSurf->jointCache = 0;
		drawSurf->frontEndGeo = NULL;
		drawSurf->space = guiSpace;
		drawSurf->material = shader;
		drawSurf->extraGLState = guiSurf.glState;
		drawSurf->scissorRect = tr.viewDef->scissor;
		drawSurf->sort = shader->GetSort();
		drawSurf->renderZFail = 0;
		// process the shader expressions for conditionals / color / texcoords
		const float*	constRegs = shader->ConstantRegisters();
		if( constRegs )
		{
			// shader only uses constant values
			drawSurf->shaderRegisters = constRegs;
		}
		else
		{
			float* regs = ( float* )R_FrameAlloc( shader->GetNumRegisters() * sizeof( float ), FRAME_ALLOC_SHADER_REGISTER );
			drawSurf->shaderRegisters = regs;
			shader->EvaluateRegisters( regs, shaderParms, tr.viewDef->renderView.shaderParms, tr.viewDef->renderView.time[1] * 0.001f, NULL );
		}
		R_LinkDrawSurfToView( drawSurf, tr.viewDef );
		if( allowFullScreenStereoDepth )
		{
			// override sort with the stereoDepth
			//drawSurf->sort = stereoDepth;
			
			switch( guiSurf.stereoType )
			{
				case STEREO_DEPTH_TYPE_NEAR:
					drawSurf->sort = STEREO_DEPTH_NEAR;
					break;
				case STEREO_DEPTH_TYPE_MID:
					drawSurf->sort = STEREO_DEPTH_MID;
					break;
				case STEREO_DEPTH_TYPE_FAR:
					drawSurf->sort = STEREO_DEPTH_FAR;
					break;
				case STEREO_DEPTH_TYPE_NONE:
				default:
					drawSurf->sort = defaultStereoDepth;
					break;
			}
		}
	}
}
/*
===================
R_AddModels

The end result of running this is the addition of drawSurf_t to the
tr.viewDef->drawSurfs[] array and light link chains, along with
frameData and vertexCache allocations to support the drawSurfs.
===================
*/
void R_AddModels()
{
	SCOPED_PROFILE_EVENT( "R_AddModels" );
	
	tr.viewDef->viewEntitys = R_SortViewEntities( tr.viewDef->viewEntitys );
	
	//-------------------------------------------------
	// Go through each view entity that is either visible to the view, or to
	// any light that intersects the view (for shadows).
	//-------------------------------------------------
	
	if( r_useParallelAddModels.GetBool() )
	{
		for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
		{
			tr.frontEndJobList->AddJob( ( jobRun_t )R_AddSingleModel, vEntity );
		}
		tr.frontEndJobList->Submit();
		tr.frontEndJobList->Wait();
	}
	else
	{
		for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
		{
			R_AddSingleModel( vEntity );
		}
	}
	
	//-------------------------------------------------
	// Kick off jobs to setup static and dynamic shadow volumes.
	//-------------------------------------------------
	
	if( r_useParallelAddShadows.GetInteger() == 1 )
	{
		for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
		{
			for( staticShadowVolumeParms_t* shadowParms = vEntity->staticShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
			{
				tr.frontEndJobList->AddJob( ( jobRun_t )StaticShadowVolumeJob, shadowParms );
			}
			for( dynamicShadowVolumeParms_t* shadowParms = vEntity->dynamicShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
			{
				tr.frontEndJobList->AddJob( ( jobRun_t )DynamicShadowVolumeJob, shadowParms );
			}
			vEntity->staticShadowVolumes = NULL;
			vEntity->dynamicShadowVolumes = NULL;
		}
		tr.frontEndJobList->Submit();
		// wait here otherwise the shadow volume index buffer may be unmapped before all shadow volumes have been constructed
		tr.frontEndJobList->Wait();
	}
	else
	{
		int start = Sys_Microseconds();
		
		for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
		{
			for( staticShadowVolumeParms_t* shadowParms = vEntity->staticShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
			{
				StaticShadowVolumeJob( shadowParms );
			}
			for( dynamicShadowVolumeParms_t* shadowParms = vEntity->dynamicShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
			{
				DynamicShadowVolumeJob( shadowParms );
			}
			vEntity->staticShadowVolumes = NULL;
			vEntity->dynamicShadowVolumes = NULL;
		}
		
		int end = Sys_Microseconds();
		backEnd.pc.shadowMicroSec += end - start;
	}
	
	//-------------------------------------------------
	// Move the draw surfs to the view.
	//-------------------------------------------------
	
	tr.viewDef->numDrawSurfs = 0;	// clear the ambient surface list
	tr.viewDef->maxDrawSurfs = 0;	// will be set to INITIAL_DRAWSURFS on R_LinkDrawSurfToView
	
	for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
	{
		for( drawSurf_t* ds = vEntity->drawSurfs; ds != NULL; )
		{
			drawSurf_t* next = ds->nextOnLight;
			if( ds->linkChain == NULL )
			{
				R_LinkDrawSurfToView( ds, tr.viewDef );
			}
			else
			{
				ds->nextOnLight = *ds->linkChain;
				*ds->linkChain = ds;
			}
			ds = next;
		}
		vEntity->drawSurfs = NULL;
	}
}