/* ================ R_AddInGameGuis ================ */ void R_AddInGameGuis( const drawSurf_t* const drawSurfs[], const int numDrawSurfs ) { SCOPED_PROFILE_EVENT( "R_AddInGameGuis" ); // check for gui surfaces for( int i = 0; i < numDrawSurfs; i++ ) { const drawSurf_t* drawSurf = drawSurfs[i]; idUserInterface* gui = drawSurf->material->GlobalGui(); int guiNum = drawSurf->material->GetEntityGui() - 1; if( guiNum >= 0 && guiNum < MAX_RENDERENTITY_GUI ) { if( drawSurf->space->entityDef != NULL ) { gui = drawSurf->space->entityDef->parms.gui[ guiNum ]; } } if( gui == NULL ) { continue; } idBounds ndcBounds; if( !R_PreciseCullSurface( drawSurf, ndcBounds ) ) { // did we ever use this to forward an entity color to a gui that didn't set color? // memcpy( tr.guiShaderParms, shaderParms, sizeof( tr.guiShaderParms ) ); R_RenderGuiSurf( gui, drawSurf ); } } }
/* ================= R_AddDrawSurf ================= */ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity, const idMaterial *shader, const idScreenRect &scissor ) { drawSurf_t *drawSurf; const float *shaderParms; static float refRegs[MAX_EXPRESSION_REGISTERS]; // don't put on stack, or VC++ will do a page touch float generatedShaderParms[MAX_ENTITY_SHADER_PARMS]; drawSurf = ( drawSurf_t * ) R_FrameAlloc( sizeof( *drawSurf ) ); drawSurf->geo = tri; drawSurf->space = space; drawSurf->material = shader; drawSurf->scissorRect = scissor; drawSurf->sort = shader->GetSort() + tr.sortOffset; drawSurf->dsFlags = 0; // bumping this offset each time causes surfaces with equal sort orders to still // deterministically draw in the order they are added tr.sortOffset += 0.000001f; // if it doesn't fit, resize the list if( tr.viewDef->numDrawSurfs == tr.viewDef->maxDrawSurfs ) { drawSurf_t **old = tr.viewDef->drawSurfs; int count; if( tr.viewDef->maxDrawSurfs == 0 ) { tr.viewDef->maxDrawSurfs = INITIAL_DRAWSURFS; count = 0; } else { count = tr.viewDef->maxDrawSurfs * sizeof( tr.viewDef->drawSurfs[0] ); tr.viewDef->maxDrawSurfs *= 2; } tr.viewDef->drawSurfs = ( drawSurf_t ** ) R_FrameAlloc( tr.viewDef->maxDrawSurfs * sizeof( tr.viewDef->drawSurfs[0] ) ); memcpy( tr.viewDef->drawSurfs, old, count ); } tr.viewDef->drawSurfs[tr.viewDef->numDrawSurfs] = drawSurf; tr.viewDef->numDrawSurfs++; // 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 ) ); drawSurf->shaderRegisters = regs; // a reference shader will take the calculated stage color value from another shader // and use that for the parm0-parm3 of the current shader, which allows a stage of // a light model and light flares to pick up different flashing tables from // different light shaders if( renderEntity->referenceShader ) { // evaluate the reference shader to find our shader parms const shaderStage_t *pStage; renderEntity->referenceShader->EvaluateRegisters( refRegs, renderEntity->shaderParms, tr.viewDef, renderEntity->referenceSound ); pStage = renderEntity->referenceShader->GetStage( 0 ); memcpy( generatedShaderParms, renderEntity->shaderParms, sizeof( generatedShaderParms ) ); generatedShaderParms[0] = refRegs[pStage->color.registers[0]]; generatedShaderParms[1] = refRegs[pStage->color.registers[1]]; generatedShaderParms[2] = refRegs[pStage->color.registers[2]]; shaderParms = generatedShaderParms; } else { // evaluate with the entityDef's shader parms shaderParms = renderEntity->shaderParms; } float oldFloatTime; int oldTime; if( space->entityDef && space->entityDef->parms.timeGroup ) { oldFloatTime = tr.viewDef->floatTime; oldTime = tr.viewDef->renderView.time; tr.viewDef->floatTime = game->GetTimeGroupTime( space->entityDef->parms.timeGroup ) * 0.001; tr.viewDef->renderView.time = game->GetTimeGroupTime( space->entityDef->parms.timeGroup ); } shader->EvaluateRegisters( regs, shaderParms, tr.viewDef, renderEntity->referenceSound ); if( space->entityDef && space->entityDef->parms.timeGroup ) { tr.viewDef->floatTime = oldFloatTime; tr.viewDef->renderView.time = oldTime; } } // check for deformations R_DeformDrawSurf( drawSurf ); // skybox surfaces need a dynamic texgen switch( shader->Texgen() ) { case TG_SKYBOX_CUBE: R_SkyboxTexGen( drawSurf, tr.viewDef->renderView.vieworg ); break; case TG_WOBBLESKY_CUBE: R_WobbleskyTexGen( drawSurf, tr.viewDef->renderView.vieworg ); break; default: break; } // check for gui surfaces idUserInterface *gui = NULL; if( !space->entityDef ) { gui = shader->GlobalGui(); } else { int guiNum = shader->GetEntityGui() - 1; if( guiNum >= 0 && guiNum < MAX_RENDERENTITY_GUI ) { gui = renderEntity->gui[guiNum]; } if( gui == NULL ) { gui = shader->GlobalGui(); } } if( gui ) { // force guis on the fast time float oldFloatTime; int oldTime; oldFloatTime = tr.viewDef->floatTime; oldTime = tr.viewDef->renderView.time; tr.viewDef->floatTime = game->GetTimeGroupTime( 1 ) * 0.001; tr.viewDef->renderView.time = game->GetTimeGroupTime( 1 ); idBounds ndcBounds; if( !R_PreciseCullSurface( drawSurf, ndcBounds ) ) { R_RenderGuiSurf( gui, drawSurf ); } tr.viewDef->floatTime = oldFloatTime; tr.viewDef->renderView.time = oldTime; } // we can't add subviews at this point, because that would // increment tr.viewCount, messing up the rest of the surface // adds for this view }