/* ================ 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; } }