/* ================= R_Postprocess_BackupScreen Backup the full original screen to a texture for downscaling and later restoration ================= */ static void R_Postprocess_BackupScreen( void ) { GL_Bind( postproc.screen.texture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); GL_Bind( postproc.depth.texture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); }
GLuint CaptureScreenAsTexID(void) { GLuint id; gld_EnableTexture2D(GL_TEXTURE0_ARB, true); qglGenTextures(1, &id); qglBindTexture(GL_TEXTURE_2D, id); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); #ifdef ANDROID qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, #else qglTexImage2D(GL_TEXTURE_2D, 0, 3, #endif gld_GetTexDimension(SCREENWIDTH), gld_GetTexDimension(SCREENHEIGHT), 0, GL_RGB, GL_UNSIGNED_BYTE, 0); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, SCREENWIDTH, SCREENHEIGHT); return id; }
static void RB_BloomDownSample( void ) { GLenum target; int width, height; GLint loc; GL_SelectTexture(0); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); target = GL_TEXTURE_RECTANGLE_ARB; width = glConfig.vidWidth; height = glConfig.vidHeight; qglBindTexture(target, tr.backBufferTexture); qglCopyTexSubImage2D(target, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight); GL_SelectTexture(1); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); qglBindTexture(target, tr.bloomTexture); qglUseProgramObjectARB(tr.downSample1Sp); loc = qglGetUniformLocationARB(tr.downSample1Sp, "backBufferTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get backBufferTex", __FUNCTION__); } qglUniform1iARB(loc, 0); //qglDisable(GL_BLEND); qglBegin(GL_QUADS); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, 0, 0); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, 0, 0); qglVertex2i(0, tr.bloomHeight); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, width, 0); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, width, 0); qglVertex2i(tr.bloomWidth, tr.bloomHeight); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, width, height); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, width, height); qglVertex2i(tr.bloomWidth, 0); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, 0, height); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, 0, height); qglVertex2i(0, 0); qglEnd(); qglUseProgramObjectARB(0); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglDisable(GL_TEXTURE_2D); GL_SelectTexture(0); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglEnable(GL_TEXTURE_2D); }
/* ================= R_Bloom_DownsampleView ================= */ void R_Bloom_DownsampleView( void ) { GL_Disable( GL_BLEND ); qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); //stepped downsample if( r_screendownsamplingtexture_size ) { int midsample_width = r_screendownsamplingtexture_size * sampleText_tcw; int midsample_height = r_screendownsamplingtexture_size * sampleText_tch; //copy the screen and draw resized GL_Bind(r_bloomscreentexture->texnum); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, curView_x, vid.height - (curView_y + curView_height), curView_width, curView_height); R_Bloom_Quad( 0, vid.height-midsample_height, midsample_width, midsample_height, screenText_tcw, screenText_tch ); //now copy into Downsampling (mid-sized) texture GL_Bind(r_bloomdownsamplingtexture->texnum); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, midsample_width, midsample_height); //now draw again in bloom size qglColor4f( 0.5f, 0.5f, 0.5f, 1.0f ); R_Bloom_Quad( 0, vid.height-sample_height, sample_width, sample_height, sampleText_tcw, sampleText_tch ); //now blend the big screen texture into the bloom generation space (hoping it adds some blur) GL_Enable( GL_BLEND ); GL_BlendFunc(GL_ONE, GL_ONE); qglColor4f( 0.5f, 0.5f, 0.5f, 1.0f ); GL_Bind(r_bloomscreentexture->texnum); R_Bloom_Quad( 0, vid.height-sample_height, sample_width, sample_height, screenText_tcw, screenText_tch ); qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); GL_Disable( GL_BLEND ); } else { //downsample simple GL_Bind(r_bloomscreentexture->texnum); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, curView_x, vid.height - (curView_y + curView_height), curView_width, curView_height); R_Bloom_Quad( 0, vid.height-sample_height, sample_width, sample_height, screenText_tcw, screenText_tch ); } }
/* * R_Bloom_DownsampleView */ static void R_Bloom_DownsampleView( void ) { qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); if( r_screendownsamplingtexture_size ) { // stepped downsample int midsample_width = ( r_screendownsamplingtexture_size * sampleText_tcw ); int midsample_height = ( r_screendownsamplingtexture_size * sampleText_tch ); // copy the screen and draw resized GL_Bind( 0, r_bloomscreentexture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, curView_x, glState.height - ( curView_y + curView_height ), curView_width, curView_height ); R_Bloom_Quad( 0, 0, midsample_width, midsample_height, screenTex_tcw, screenTex_tch ); // now copy into downsampling (mid-sized) texture GL_Bind( 0, r_bloomdownsamplingtexture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, midsample_width, midsample_height ); // now draw again in bloom size qglColor4f( 0.5f, 0.5f, 0.5f, 1.0f ); R_Bloom_Quad( 0, 0, sample_width, sample_height, sampleText_tcw, sampleText_tch ); // now blend the big screen texture into the bloom generation space (hoping it adds some blur) GL_SetState( GLSTATE_NO_DEPTH_TEST|GLSTATE_SRCBLEND_ONE|GLSTATE_DSTBLEND_ONE ); GL_Bind( 0, r_bloomscreentexture ); R_Bloom_Quad( 0, 0, sample_width, sample_height, screenTex_tcw, screenTex_tch ); qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); } else { // downsample simple GL_Bind( 0, r_bloomscreentexture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, curView_x, glState.height - ( curView_y + curView_height ), curView_width, curView_height ); R_Bloom_Quad( 0, 0, sample_width, sample_height, screenTex_tcw, screenTex_tch ); } }
static void RB_BloomBrightness( void ) { GLenum target; int width, height; GLint loc; GL_SelectTexture(0); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); target = GL_TEXTURE_RECTANGLE_ARB; width = tr.bloomWidth; height = tr.bloomHeight; qglBindTexture(target, tr.bloomTexture); qglCopyTexSubImage2D(target, 0, 0, 0, 0, glConfig.vidHeight - height, width, height); qglUseProgramObjectARB(tr.brightPassSp); loc = qglGetUniformLocationARB(tr.brightPassSp, "backBufferTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get backBufferTex", __FUNCTION__); } qglUniform1iARB(loc, 0); loc = qglGetUniformLocationARB(tr.brightPassSp, "p_brightthreshold"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_brightthreshold", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomBrightThreshold->value); qglBegin(GL_QUADS); qglTexCoord2i(0, 0); qglVertex2i(0, height); qglTexCoord2i(width, 0); qglVertex2i(width, height); qglTexCoord2i(width, height); qglVertex2i(width, 0); qglTexCoord2i(0, height); qglVertex2i(0, 0); qglEnd(); qglUseProgramObjectARB(0); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglEnable(GL_TEXTURE_2D); }
void R_BloomBlend ( refdef_t *fd ) { if( !(fd->rdflags & RDF_BLOOM) || !r_bloom->value || r_showtris->value ) return; if( !BLOOM_SIZE ) R_Bloom_InitTextures(); if( screen_texture_width < BLOOM_SIZE || screen_texture_height < BLOOM_SIZE ) return; //set up full screen workspace qglViewport ( 0, 0, vid.width, vid.height ); GL_TexEnv (GL_REPLACE); // Knightmare added GL_Disable (GL_DEPTH_TEST); qglMatrixMode (GL_PROJECTION); qglLoadIdentity (); qglOrtho(0, vid.width, vid.height, 0, -10, 100); qglMatrixMode (GL_MODELVIEW); qglLoadIdentity (); GL_Disable (GL_CULL_FACE); GL_Disable (GL_BLEND); qglEnable (GL_TEXTURE_2D); qglColor4f (1, 1, 1, 1); //set up current sizes curView_x = fd->x; curView_y = fd->y; curView_width = fd->width; curView_height = fd->height; screenText_tcw = ((float)fd->width / (float)screen_texture_width); screenText_tch = ((float)fd->height / (float)screen_texture_height); if( fd->height > fd->width ) { sampleText_tcw = ((float)fd->width / (float)fd->height); sampleText_tch = 1.0f; } else { sampleText_tcw = 1.0f; sampleText_tch = ((float)fd->height / (float)fd->width); } sample_width = BLOOM_SIZE * sampleText_tcw; sample_height = BLOOM_SIZE * sampleText_tch; //copy the screen space we'll use to work into the backup texture GL_Bind(r_bloombackuptexture->texnum); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, r_screenbackuptexture_size * sampleText_tcw, r_screenbackuptexture_size * sampleText_tch); //create the bloom image R_Bloom_DownsampleView(); R_Bloom_GeneratexDiamonds( fd ); //R_Bloom_GeneratexCross(); //restore the screen-backup to the screen GL_Disable(GL_BLEND); GL_Bind(r_bloombackuptexture->texnum); qglColor4f( 1, 1, 1, 1 ); R_Bloom_Quad( 0, vid.height - (r_screenbackuptexture_size * sampleText_tch), r_screenbackuptexture_size * sampleText_tcw, r_screenbackuptexture_size * sampleText_tch, sampleText_tcw, sampleText_tch ); R_Bloom_DrawEffect( fd ); // Knightmare added R_SetupGL (); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglEnable (GL_TEXTURE_2D); qglColor4f(1,1,1,1); }
/* * R_BloomBlend */ void R_BloomBlend( const refdef_t *fd ) { if( !( fd->rdflags & RDF_BLOOM ) || !r_bloom->integer ) return; if( !BLOOM_SIZE ) R_Bloom_InitTextures(); if( screen_texture_width < BLOOM_SIZE || screen_texture_height < BLOOM_SIZE ) return; // set up full screen workspace GL_Scissor( 0, 0, glState.width, glState.height ); GL_Viewport( 0, 0, glState.width, glState.height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( 0, glState.width, glState.height, 0, -10, 100 ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); GL_Cull( 0 ); GL_SetState( GLSTATE_NO_DEPTH_TEST ); qglColor4f( 1, 1, 1, 1 ); // set up current sizes curView_x = fd->x; curView_y = fd->y; curView_width = fd->width; curView_height = fd->height; screenTex_tcw = ( (float)curView_width / (float)screen_texture_width ); screenTex_tch = ( (float)curView_height / (float)screen_texture_height ); if( curView_height > curView_width ) { sampleText_tcw = ( (float)curView_width / (float)curView_height ); sampleText_tch = 1.0f; } else { sampleText_tcw = 1.0f; sampleText_tch = ( (float)curView_height / (float)curView_width ); } sample_width = ( BLOOM_SIZE * sampleText_tcw ); sample_height = ( BLOOM_SIZE * sampleText_tch ); // copy the screen space we'll use to work into the backup texture GL_Bind( 0, r_bloombackuptexture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, r_screenbackuptexture_width, r_screenbackuptexture_height ); // create the bloom image R_Bloom_DownsampleView(); R_Bloom_GeneratexDiamonds(); // restore the screen-backup to the screen GL_SetState( GLSTATE_NO_DEPTH_TEST ); GL_Bind( 0, r_bloombackuptexture ); qglColor4f( 1, 1, 1, 1 ); R_Bloom_Quad( 0, 0, r_screenbackuptexture_width, r_screenbackuptexture_height, 1.0f, 1.0f ); GL_Scissor( ri.scissor[0], ri.scissor[1], ri.scissor[2], ri.scissor[3] ); R_Bloom_DrawEffect(); GL_Viewport( ri.viewport[0], ri.viewport[1], ri.viewport[2], ri.viewport[3] ); }
static inline void RB_BlurGlowTexture() { qglDisable (GL_CLIP_PLANE0); GL_Cull( CT_TWO_SIDED ); // Go into orthographic 2d mode. qglMatrixMode(GL_PROJECTION); qglPushMatrix(); qglLoadIdentity(); qglOrtho(0, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight, 0, -1, 1); qglMatrixMode(GL_MODELVIEW); qglPushMatrix(); qglLoadIdentity(); GL_State(GLS_DEPTHTEST_DISABLE); ///////////////////////////////////////////////////////// // Setup vertex and pixel programs. ///////////////////////////////////////////////////////// // NOTE: The 0.25 is because we're blending 4 textures (so = 1.0) and we want a relatively normalized pixel // intensity distribution, but this won't happen anyways if intensity is higher than 1.0. float fBlurDistribution = r_DynamicGlowIntensity->value * 0.25f; float fBlurWeight[4] = { fBlurDistribution, fBlurDistribution, fBlurDistribution, 1.0f }; // Enable and set the Vertex Program. qglEnable( GL_VERTEX_PROGRAM_ARB ); qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, tr.glowVShader ); // Apply Pixel Shaders. if ( qglCombinerParameterfvNV ) { BeginPixelShader( GL_REGISTER_COMBINERS_NV, tr.glowPShader ); // Pass the blur weight to the regcom. qglCombinerParameterfvNV( GL_CONSTANT_COLOR0_NV, (float*)&fBlurWeight ); } else if ( qglProgramEnvParameter4fARB ) { BeginPixelShader( GL_FRAGMENT_PROGRAM_ARB, tr.glowPShader ); // Pass the blur weight to the Fragment Program. qglProgramEnvParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 0, fBlurWeight[0], fBlurWeight[1], fBlurWeight[2], fBlurWeight[3] ); } ///////////////////////////////////////////////////////// // Set the blur texture to the 4 texture stages. ///////////////////////////////////////////////////////// // How much to offset each texel by. float fTexelWidthOffset = 0.1f, fTexelHeightOffset = 0.1f; GLuint uiTex = tr.screenGlow; qglActiveTextureARB( GL_TEXTURE3_ARB ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB( GL_TEXTURE2_ARB ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB( GL_TEXTURE1_ARB ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB(GL_TEXTURE0_ARB ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); ///////////////////////////////////////////////////////// // Draw the blur passes (each pass blurs it more, increasing the blur radius ). ///////////////////////////////////////////////////////// //int iTexWidth = backEnd.viewParms.viewportWidth, iTexHeight = backEnd.viewParms.viewportHeight; int iTexWidth = glConfig.vidWidth, iTexHeight = glConfig.vidHeight; for ( int iNumBlurPasses = 0; iNumBlurPasses < r_DynamicGlowPasses->integer; iNumBlurPasses++ ) { // Load the Texel Offsets into the Vertex Program. qglProgramEnvParameter4fARB( GL_VERTEX_PROGRAM_ARB, 0, -fTexelWidthOffset, -fTexelWidthOffset, 0.0f, 0.0f ); qglProgramEnvParameter4fARB( GL_VERTEX_PROGRAM_ARB, 1, -fTexelWidthOffset, fTexelWidthOffset, 0.0f, 0.0f ); qglProgramEnvParameter4fARB( GL_VERTEX_PROGRAM_ARB, 2, fTexelWidthOffset, -fTexelWidthOffset, 0.0f, 0.0f ); qglProgramEnvParameter4fARB( GL_VERTEX_PROGRAM_ARB, 3, fTexelWidthOffset, fTexelWidthOffset, 0.0f, 0.0f ); // After first pass put the tex coords to the viewport size. if ( iNumBlurPasses == 1 ) { if ( !g_bTextureRectangleHack ) { iTexWidth = backEnd.viewParms.viewportWidth; iTexHeight = backEnd.viewParms.viewportHeight; } uiTex = tr.blurImage; qglActiveTextureARB( GL_TEXTURE3_ARB ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB( GL_TEXTURE2_ARB ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB( GL_TEXTURE1_ARB ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB(GL_TEXTURE0_ARB ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); // Copy the current image over. qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, 0, 0, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); } // Draw the fullscreen quad. qglBegin( GL_QUADS ); qglMultiTexCoord2fARB( GL_TEXTURE0_ARB, 0, iTexHeight ); qglVertex2f( 0, 0 ); qglMultiTexCoord2fARB( GL_TEXTURE0_ARB, 0, 0 ); qglVertex2f( 0, backEnd.viewParms.viewportHeight ); qglMultiTexCoord2fARB( GL_TEXTURE0_ARB, iTexWidth, 0 ); qglVertex2f( backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); qglMultiTexCoord2fARB( GL_TEXTURE0_ARB, iTexWidth, iTexHeight ); qglVertex2f( backEnd.viewParms.viewportWidth, 0 ); qglEnd(); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.blurImage ); qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, 0, 0, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); // Increase the texel offsets. // NOTE: This is possibly the most important input to the effect. Even by using an exponential function I've been able to // make it look better (at a much higher cost of course). This is cheap though and still looks pretty great. In the future // I might want to use an actual gaussian equation to correctly calculate the pixel coefficients and attenuates, texel // offsets, gaussian amplitude and radius... fTexelWidthOffset += r_DynamicGlowDelta->value; fTexelHeightOffset += r_DynamicGlowDelta->value; } // Disable multi-texturing. qglActiveTextureARB( GL_TEXTURE3_ARB ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglActiveTextureARB( GL_TEXTURE2_ARB ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglActiveTextureARB( GL_TEXTURE1_ARB ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglActiveTextureARB(GL_TEXTURE0_ARB ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglEnable( GL_TEXTURE_2D ); qglDisable( GL_VERTEX_PROGRAM_ARB ); EndPixelShader(); qglMatrixMode(GL_PROJECTION); qglPopMatrix(); qglMatrixMode(GL_MODELVIEW); qglPopMatrix(); qglDisable( GL_BLEND ); glState.currenttmu = 0; //this matches the last one we activated }
/* * R_Bloom_GeneratexDiamonds */ static void R_Bloom_GeneratexDiamonds( void ) { int i, j, k; float intensity, scale, *diamond; // set up sample size workspace GL_Scissor( 0, glState.height - sample_height, sample_width, sample_height ); GL_Viewport( 0, glState.height - sample_height, sample_width, sample_height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( 0, sample_width, sample_height, 0, -10, 100 ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); // copy small scene into r_bloomeffecttexture GL_Bind( 0, r_bloomeffecttexture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height ); // start modifying the small scene corner qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); // darkening passes if( r_bloom_darken->integer ) { GL_TexEnv( GL_MODULATE ); GL_SetState( GLSTATE_NO_DEPTH_TEST|GLSTATE_SRCBLEND_DST_COLOR|GLSTATE_DSTBLEND_ZERO ); for( i = 0; i < r_bloom_darken->integer; i++ ) R_Bloom_SamplePass( 0, 0 ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height ); } // bluring passes GL_SetState( GLSTATE_NO_DEPTH_TEST|GLSTATE_SRCBLEND_ONE|GLSTATE_DSTBLEND_ONE_MINUS_SRC_COLOR ); if( r_bloom_diamond_size->integer > 7 || r_bloom_diamond_size->integer <= 3 ) { if( r_bloom_diamond_size->integer != 8 ) Cvar_ForceSet( "r_bloom_diamond_size", "8" ); } else if( r_bloom_diamond_size->integer > 5 ) { if( r_bloom_diamond_size->integer != 6 ) Cvar_ForceSet( "r_bloom_diamond_size", "6" ); } else if( r_bloom_diamond_size->integer > 3 ) { if( r_bloom_diamond_size->integer != 4 ) Cvar_ForceSet( "r_bloom_diamond_size", "4" ); } switch( r_bloom_diamond_size->integer ) { case 4: k = 2; diamond = &Diamond4x[0][0]; scale = r_bloom_intensity->value * 0.8f; break; case 6: k = 3; diamond = &Diamond6x[0][0]; scale = r_bloom_intensity->value * 0.5f; break; default: // case 8: k = 4; diamond = &Diamond8x[0][0]; scale = r_bloom_intensity->value * 0.3f; break; } for( i = 0; i < r_bloom_diamond_size->integer; i++ ) { for( j = 0; j < r_bloom_diamond_size->integer; j++, diamond++ ) { intensity = *diamond * scale; if( intensity < 0.01f ) continue; qglColor4f( intensity, intensity, intensity, 1.0 ); R_Bloom_SamplePass( i - k, j - k ); } } qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height ); // restore full screen workspace GL_Scissor( 0, 0, glState.width, glState.height ); GL_Viewport( 0, 0, glState.width, glState.height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( 0, glState.width, glState.height, 0, -10, 100 ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); }
void RB_ColorCorrect( void ) { GLint loc; GLenum target; int width, height; int shift; float mul; if ( !r_enablePostProcess->integer || !r_enableColorCorrect->integer || !glsl ) { return; } GL_SelectTexture(0); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); target = GL_TEXTURE_RECTANGLE_ARB; width = glConfig.vidWidth; height = glConfig.vidHeight; qglBindTexture(target, tr.backBufferTexture); qglCopyTexSubImage2D(target, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); RB_SetGL2D(); GL_State( GLS_DEPTHTEST_DISABLE ); qglUseProgramObjectARB(tr.colorCorrectSp); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_gammaRecip"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_gammaRecip", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)(1.0 / r_gamma->value)); //mul = r_overBrightBitsValue->value; mul = r_overBrightBits->value; if (mul < 0.0) { mul = 0.0; } shift = tr.overbrightBits; loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_overbright"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_overbright", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)((float)(1 << shift) * mul)); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_contrast"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_contrast", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_contrast->value); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "backBufferTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get backBufferTex", __FUNCTION__); } qglUniform1iARB(loc, 0); qglBegin(GL_QUADS); qglTexCoord2i(0, 0); qglVertex2i(0, height); qglTexCoord2i(width, 0); qglVertex2i(width, height); qglTexCoord2i(width, height); qglVertex2i(width, 0); qglTexCoord2i(0, height); qglVertex2i(0, 0); qglEnd(); qglUseProgramObjectARB(0); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglEnable(GL_TEXTURE_2D); }
/* ============= RB_DrawSurfs ============= */ const void *RB_DrawSurfs( const void *data ) { const drawSurfsCommand_t *cmd; // finish any 2D drawing if needed if ( tess.numIndexes ) { RB_EndSurface(); } cmd = (const drawSurfsCommand_t *)data; backEnd.refdef = cmd->refdef; backEnd.viewParms = cmd->viewParms; RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); // Dynamic Glow/Flares: /* The basic idea is to render the glowing parts of the scene to an offscreen buffer, then take that buffer and blur it. After it is sufficiently blurred, re-apply that image back to the normal screen using a additive blending. To blur the scene I use a vertex program to supply four texture coordinate offsets that allow 'peeking' into adjacent pixels. In the register combiner (pixel shader), I combine the adjacent pixels using a weighting factor. - Aurelio */ // Render dynamic glowing/flaring objects. if ( !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && g_bDynamicGlowSupported && r_DynamicGlow->integer ) { // Copy the normal scene to texture. qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.sceneImage ); qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglEnable( GL_TEXTURE_2D ); // Just clear colors, but leave the depth buffer intact so we can 'share' it. qglClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); qglClear( GL_COLOR_BUFFER_BIT ); // Render the glowing objects. g_bRenderGlowingObjects = true; RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); g_bRenderGlowingObjects = false; qglFinish(); // Copy the glow scene to texture. qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.screenGlow ); qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglEnable( GL_TEXTURE_2D ); // Resize the viewport to the blur texture size. const int oldViewWidth = backEnd.viewParms.viewportWidth; const int oldViewHeight = backEnd.viewParms.viewportHeight; backEnd.viewParms.viewportWidth = r_DynamicGlowWidth->integer; backEnd.viewParms.viewportHeight = r_DynamicGlowHeight->integer; SetViewportAndScissor(); // Blur the scene. RB_BlurGlowTexture(); // Copy the finished glow scene back to texture. qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.blurImage ); qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, 0, 0, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglEnable( GL_TEXTURE_2D ); // Set the viewport back to normal. backEnd.viewParms.viewportWidth = oldViewWidth; backEnd.viewParms.viewportHeight = oldViewHeight; SetViewportAndScissor(); qglClear( GL_COLOR_BUFFER_BIT ); // Draw the glow additively over the screen. RB_DrawGlowOverlay(); } return (const void *)(cmd + 1); }
static void RB_BloomCombine( void ) { GLenum target; int width, height; GLint loc; GL_SelectTexture(0); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); target = GL_TEXTURE_RECTANGLE_ARB; width = tr.bloomWidth; height = tr.bloomHeight; qglBindTexture(target, tr.bloomTexture); qglCopyTexSubImage2D(target, 0, 0, 0, 0, glConfig.vidHeight - height, width, height); qglUseProgramObjectARB(tr.combineSp); qglBindTexture(target, tr.backBufferTexture); loc = qglGetUniformLocationARB(tr.combineSp, "backBufferTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get backBufferTex", __FUNCTION__); } qglUniform1iARB(loc, 0); GL_SelectTexture(1); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); qglBindTexture(target, tr.bloomTexture); loc = qglGetUniformLocationARB(tr.combineSp, "bloomTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get bloomTex", __FUNCTION__); } qglUniform1iARB(loc, 1); loc = qglGetUniformLocationARB(tr.combineSp, "p_bloomsaturation"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_bloomsaturation", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomSaturation->value); loc = qglGetUniformLocationARB(tr.combineSp, "p_scenesaturation"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_scenesaturation", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomSceneSaturation->value); loc = qglGetUniformLocationARB(tr.combineSp, "p_bloomintensity"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_bloomintensity", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomIntensity->value); loc = qglGetUniformLocationARB(tr.combineSp, "p_sceneintensity"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_sceneintensity", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomSceneIntensity->value); width = glConfig.vidWidth; height = glConfig.vidHeight; qglBegin(GL_QUADS); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, 0, 0); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, 0, 0); qglVertex2i(0, height); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, width, 0); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, tr.bloomWidth, 0); qglVertex2i(width, height); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, width, height); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, tr.bloomWidth, tr.bloomHeight); qglVertex2i(width, 0); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, 0, height); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, 0, tr.bloomHeight); qglVertex2i(0, 0); qglEnd(); qglUseProgramObjectARB(0); GL_SelectTexture(1); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglDisable(GL_TEXTURE_2D); GL_SelectTexture(0); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglEnable(GL_TEXTURE_2D); }
/* ================= R_Bloom_GeneratexDiamonds ================= */ void R_Bloom_GeneratexDiamonds( refdef_t *fd ) { int i, j; static float intensity; //set up sample size workspace qglViewport( 0, 0, sample_width, sample_height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity (); qglOrtho(0, sample_width, sample_height, 0, -10, 100); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity (); //copy small scene into r_bloomeffecttexture GL_Bind(r_bloomeffecttexture->texnum); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); //start modifying the small scene corner qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); GL_Enable(GL_BLEND); //Com_Printf("%d %d\n", r_bloom_darken->value, fd->bloomdarken); //darkening passes if( r_bloom_darken->value ) { GL_BlendFunc(GL_DST_COLOR, GL_ZERO); GL_TexEnv(GL_MODULATE); for(i=0; i< r_bloom_darken->value ; i++) { R_Bloom_SamplePass( 0, 0 ); } qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); } //bluring passes //GL_BlendFunc(GL_ONE, GL_ONE); GL_BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); if( r_bloom_diamond_size->value > 7 || r_bloom_diamond_size->value <= 3) { if( (int)r_bloom_diamond_size->value != 8 ) Cvar_SetValue( "r_bloom_diamond_size", 8 ); for(i=0; i<r_bloom_diamond_size->value; i++) { for(j=0; j<r_bloom_diamond_size->value; j++) { intensity = /*bc mod*/(fd->bloomintensity + r_bloom_intensity->value) * 0.3 * Diamond8x[i][j]; if( intensity < r_bloom_threshold->value ) continue; qglColor4f( intensity, intensity, intensity, 1.0); R_Bloom_SamplePass( i-4, j-4 ); } } } else if( r_bloom_diamond_size->value > 5 ) { if( r_bloom_diamond_size->value != 6 ) Cvar_SetValue( "r_bloom_diamond_size", 6 ); for(i=0; i<r_bloom_diamond_size->value; i++) { for(j=0; j<r_bloom_diamond_size->value; j++) { intensity = /*bc mod*/(fd->bloomintensity + r_bloom_intensity->value) * 0.5 * Diamond6x[i][j]; if( intensity < r_bloom_threshold->value ) continue; qglColor4f( intensity, intensity, intensity, 1.0); R_Bloom_SamplePass( i-3, j-3 ); } } } else if( r_bloom_diamond_size->value > 3 ) { if( (int)r_bloom_diamond_size->value != 4 ) Cvar_SetValue( "r_bloom_diamond_size", 4 ); for(i=0; i<r_bloom_diamond_size->value; i++) { for(j=0; j<r_bloom_diamond_size->value; j++) { intensity = /*bc mod*/(fd->bloomintensity + r_bloom_intensity->value) * 0.8f * Diamond4x[i][j]; if( intensity < r_bloom_threshold->value ) continue; qglColor4f( intensity, intensity, intensity, 1.0); R_Bloom_SamplePass( i-2, j-2 ); } } } qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); //restore full screen workspace qglViewport( 0, 0, vid.width, vid.height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity (); qglOrtho(0, vid.width, vid.height, 0, -10, 100); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity (); }
/* ================= R_Bloom_Cascaded ================= Tcpp: sorry for my poor English skill. */ static void R_Bloom_Cascaded( void ){ int scale; int oldWorkW, oldWorkH; int newWorkW, newWorkH; float bloomShiftX=r_bloom_cascade_blur->value/(float)bloom.effect.width; float bloomShiftY=r_bloom_cascade_blur->value/(float)bloom.effect.height; float intensity=r_bloom_cascade_intensity->value; float intensity2; qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); //Take the backup texture and downscale it GL_Bind( bloom.screen.texture ); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); R_Bloom_Quad( bloom.work.width, bloom.work.height, 0, 0, bloom.screen.readW, bloom.screen.readH ); //Copy downscaled framebuffer into a texture GL_Bind( bloom.effect.texture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, bloom.work.width, bloom.work.height ); /* Copy the result to the effect texture */ GL_Bind( bloom.effect2.texture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, bloom.work.width, bloom.work.height ); // do blurs.. scale=32; while(bloom.work.width<scale) scale>>=1; while(bloom.work.height<scale) scale>>=1; // prepare the first level. newWorkW=bloom.work.width/scale; newWorkH=bloom.work.height/scale; GL_Bind( bloom.effect2.texture ); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); intensity2=intensity/(float)scale; qglColor4f( intensity2, intensity2, intensity2, 1.0 ); R_Bloom_Quad( newWorkW, newWorkH, 0, 0, bloom.effect2.readW, bloom.effect2.readH ); // go through levels. while(scale>1){ float oldScaleInv=1.f/(float)scale; scale>>=1; oldWorkH=newWorkH; oldWorkW=newWorkW; newWorkW=bloom.work.width/scale; newWorkH=bloom.work.height/scale; // get effect texture. GL_Bind( bloom.effect.texture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWorkW, oldWorkH); // maginfy the previous level. if(r_bloom_cascade_blur->value<.01f){ // don't blur. qglColor4f( 1.f, 1.f, 1.f, 1.0 ); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); R_Bloom_Quad( newWorkW, newWorkH, 0, 0, bloom.effect.readW*oldScaleInv, bloom.effect.readH*oldScaleInv ); }else{ // blur. qglColor4f( .25f, .25f, .25f, 1.0 ); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); R_Bloom_Quad( newWorkW, newWorkH, -bloomShiftX, -bloomShiftY, bloom.effect.readW*oldScaleInv, bloom.effect.readH*oldScaleInv ); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); R_Bloom_Quad( newWorkW, newWorkH, bloomShiftX, -bloomShiftY, bloom.effect.readW*oldScaleInv, bloom.effect.readH*oldScaleInv ); R_Bloom_Quad( newWorkW, newWorkH, -bloomShiftX, bloomShiftY, bloom.effect.readW*oldScaleInv, bloom.effect.readH*oldScaleInv ); R_Bloom_Quad( newWorkW, newWorkH, bloomShiftX, bloomShiftY, bloom.effect.readW*oldScaleInv, bloom.effect.readH*oldScaleInv ); } // add the input. intensity2=intensity/(float)scale; qglColor4f( intensity2, intensity2, intensity2, 1.0 ); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); GL_Bind( bloom.effect2.texture ); R_Bloom_Quad( newWorkW, newWorkH, 0, 0, bloom.effect2.readW, bloom.effect2.readH ); } GL_Bind( bloom.effect.texture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, bloom.work.width, bloom.work.height ); }
/* ================= R_Bloom_GeneratexDiamonds ================= */ static void R_Bloom_WarsowEffect( void ) { int i, j, k; float intensity, scale, *diamond; qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); //Take the backup texture and downscale it GL_Bind( bloom.screen.texture ); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); R_Bloom_Quad( bloom.work.width, bloom.work.height, 0, 0, bloom.screen.readW, bloom.screen.readH ); //Copy downscaled framebuffer into a texture GL_Bind( bloom.effect.texture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, bloom.work.width, bloom.work.height ); // darkening passes with repeated filter if( r_bloom_darken->integer ) { int i; GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); for( i = 0; i < r_bloom_darken->integer; i++ ) { R_Bloom_Quad( bloom.work.width, bloom.work.height, 0, 0, bloom.effect.readW, bloom.effect.readH ); } qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, bloom.work.width, bloom.work.height ); } /* Copy the result to the effect texture */ GL_Bind( bloom.effect.texture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, bloom.work.width, bloom.work.height ); // bluring passes, warsow uses a repeated semi blend on a selectable diamond grid qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ); if( r_bloom_diamond_size->integer > 7 || r_bloom_diamond_size->integer <= 3 ) { if( r_bloom_diamond_size->integer != 8 ) ri.Cvar_Set( "r_bloom_diamond_size", "8" ); } else if( r_bloom_diamond_size->integer > 5 ) { if( r_bloom_diamond_size->integer != 6 ) ri.Cvar_Set( "r_bloom_diamond_size", "6" ); } else if( r_bloom_diamond_size->integer > 3 ) { if( r_bloom_diamond_size->integer != 4 ) ri.Cvar_Set( "r_bloom_diamond_size", "4" ); } switch( r_bloom_diamond_size->integer ) { case 4: k = 2; diamond = &Diamond4x[0][0]; scale = r_bloom_intensity->value * 0.8f; break; case 6: k = 3; diamond = &Diamond6x[0][0]; scale = r_bloom_intensity->value * 0.5f; break; default: // case 8: k = 4; diamond = &Diamond8x[0][0]; scale = r_bloom_intensity->value * 0.3f; break; } for( i = 0; i < r_bloom_diamond_size->integer; i++ ) { for( j = 0; j < r_bloom_diamond_size->integer; j++, diamond++ ) { float x, y; intensity = *diamond * scale; if( intensity < 0.01f ) continue; qglColor4f( intensity, intensity, intensity, 1.0 ); x = (i - k) * ( 2 / 640.0f ) * bloom.effect.readW; y = (j - k) * ( 2 / 480.0f ) * bloom.effect.readH; R_Bloom_Quad( bloom.work.width, bloom.work.height, x, y, bloom.effect.readW, bloom.effect.readH ); } } qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, bloom.work.width, bloom.work.height ); }
/* ================= R_Bloom_BackupScreen Backup the full original screen to a texture for downscaling and later restoration ================= */ static void R_Bloom_BackupScreen( void ) { GL_Bind( bloom.screen.texture ); qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); }
/* * RB_PostProcess * */ const void * RB_PostProcess(const void *data) { const postProcessCommand_t *cmd = data; Vec4 white; Vec2 texScale; qbool autoExposure; texScale[0] = texScale[1] = 1.0f; setv34(white, 1, 1, 1, 1); if(!r_postProcess->integer){ /* if we have an FBO, just copy it out, otherwise, do nothing. */ if(glRefConfig.framebufferObject){ Vec4 srcBox, dstBox, color; setv34(srcBox, 0, 0, tr.renderFbo->width, tr.renderFbo->height); /* setv34(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight); */ setv34(dstBox, 0, 0, tr.screenScratchFbo->width, tr.screenScratchFbo->height); color[0] = color[1] = color[2] = pow(2, r_cameraExposure->value); /* exp2(r_cameraExposure->value); */ color[3] = 1.0f; /* FBO_Blit(tr.renderFbo, srcBox, texScale, NULL, dstBox, &tr.textureColorShader, color, 0); */ FBO_Blit(tr.renderFbo, srcBox, texScale, tr.screenScratchFbo, dstBox, &tr.textureColorShader, color, 0); } backEnd.framePostProcessed = qtrue; return (const void*)(cmd + 1); } #if 0 if(!glRefConfig.framebufferObject){ /* we couldn't render straight to it, so just cap the screen instead */ GL_Bind(tr.renderImage); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight); } #endif if(r_hdr->integer && (r_toneMap->integer == 2 || (r_toneMap->integer == 1 && tr.autoExposure))){ autoExposure = (r_autoExposure->integer == 1 && tr.autoExposure) || (r_autoExposure->integer == 2); RB_ToneMap(autoExposure); }else{ Vec4 srcBox, dstBox, color; setv34(srcBox, 0, 0, tr.renderFbo->width, tr.renderFbo->height); setv34(dstBox, 0, 0, tr.screenScratchFbo->width, tr.screenScratchFbo->height); color[0] = color[1] = color[2] = pow(2, r_cameraExposure->value); /* exp2(r_cameraExposure->value); */ color[3] = 1.0f; FBO_Blit(tr.renderFbo, srcBox, texScale, tr.screenScratchFbo, dstBox, &tr.textureColorShader, color, 0); } #ifdef REACTION RB_GodRays(); if(1) RB_BokehBlur(backEnd.refdef.blurFactor); else RB_GaussianBlur(backEnd.refdef.blurFactor); #endif /* * if (glRefConfig.framebufferObject) * { * // copy final image to screen * Vec4 srcBox, dstBox; * * setv34(srcBox, 0, 0, tr.screenScratchFbo->width, tr.screenScratchFbo->height); * setv34(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight); * * FBO_Blit(tr.screenScratchFbo, srcBox, texScale, NULL, dstBox, &tr.textureColorShader, white, 0); * } */ backEnd.framePostProcessed = qtrue; return (const void*)(cmd + 1); }
/* ================= R_Bloom_GeneratexCross - alternative bluring method ================= */ void R_Bloom_GeneratexCross( void ) { int i; static int BLOOM_BLUR_RADIUS = 8; //static float BLOOM_BLUR_INTENSITY = 2.5f; float BLOOM_BLUR_INTENSITY; static float intensity; static float range; //set up sample size workspace qglViewport( 0, 0, sample_width, sample_height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity (); qglOrtho(0, sample_width, sample_height, 0, -10, 100); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity (); //copy small scene into r_bloomeffecttexture GL_Bind(0, r_bloomeffecttexture); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); //start modifying the small scene corner qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); GL_Enable(GL_BLEND); //darkening passes if( r_bloom_darken->value ) { GL_BlendFunc(GL_DST_COLOR, GL_ZERO); GL_TexEnv(GL_MODULATE); for(i=0; i<r_bloom_darken->value ; i++) { R_Bloom_SamplePass( 0, 0 ); } qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); } //bluring passes if( BLOOM_BLUR_RADIUS ) { GL_BlendFunc(GL_ONE, GL_ONE); range = (float)BLOOM_BLUR_RADIUS; BLOOM_BLUR_INTENSITY = r_bloom_intensity->value; //diagonal-cross draw 4 passes to add initial smooth qglColor4f( 0.5f, 0.5f, 0.5f, 1.0); R_Bloom_SamplePass( 1, 1 ); R_Bloom_SamplePass( -1, 1 ); R_Bloom_SamplePass( -1, -1 ); R_Bloom_SamplePass( 1, -1 ); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); for(i=-(BLOOM_BLUR_RADIUS+1); i<BLOOM_BLUR_RADIUS; i++) { intensity = BLOOM_BLUR_INTENSITY/(range*2+1)*(1 - fabs(i*i)/(float)(range*range)); if( intensity < 0.05f ) continue; qglColor4f( intensity, intensity, intensity, 1.0f); R_Bloom_SamplePass( i, 0 ); //R_Bloom_SamplePass( -i, 0 ); } qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); //for(i=0;i<BLOOM_BLUR_RADIUS;i++) { for(i=-(BLOOM_BLUR_RADIUS+1); i<BLOOM_BLUR_RADIUS; i++) { intensity = BLOOM_BLUR_INTENSITY/(range*2+1)*(1 - fabs(i*i)/(float)(range*range)); if( intensity < 0.05f ) continue; qglColor4f( intensity, intensity, intensity, 1.0f); R_Bloom_SamplePass( 0, i ); //R_Bloom_SamplePass( 0, -i ); } qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height); } //restore full screen workspace qglViewport( 0, 0, glState.width, glState.height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity (); qglOrtho(0, glState.width, glState.height, 0, -10, 100); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity (); }