/** * @brief Enable the render to the framebuffer * @param enable If @c true we are enabling the rendering to fbo_render, if @c false we are rendering * to fbo that represents the screen * @sa R_DrawBuffers * @return @c true if the fbo was bound, @c false if not supported or deactivated */ bool R_EnableRenderbuffer (bool enable) { if (!r_state.frameBufferObjectsInitialized || !r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer) return false; if (enable != r_state.renderbuffer_enabled) { r_state.renderbuffer_enabled = enable; if (enable) R_UseFramebuffer(fbo_render); else R_UseFramebuffer(fbo_screen); } R_DrawBuffers(1); return true; }
/** * @brief Delete all registered framebuffer and render buffer objects, clear memory */ void R_ShutdownFBObjects (void) { int i; if (!r_state.frameBufferObjectsInitialized) return; for (i = 0; i < frameBufferObjectCount; i++) R_DeleteFBObject(&frameBufferObjects[i]); R_UseFramebuffer(&screenBuffer); frameBufferObjectCount = 0; OBJZERO(frameBufferObjects); r_state.frameBufferObjectsInitialized = false; Mem_Free(colorAttachments); }
/** * @brief blur from the source image pyramid into the dest image pyramid */ static void R_BlurStack (int levels, r_framebuffer_t **sources, r_framebuffer_t **dests) { int i; for (i = 0; i < levels; i++) { const int l = levels - i - 1; R_UseProgram(i == 0 ? default_program : r_state.combine2_program); R_UseFramebuffer(dests[l]); R_BindTextureForTexUnit(sources[l]->textures[0], &texunit_0); if (i != 0) R_BindTextureForTexUnit(dests[l + 1]->textures[0], &texunit_1); R_UseViewport(sources[l]); R_DrawQuad(); R_Blur(dests[l], sources[l], 0, 1); R_Blur(sources[l], dests[l], 0, 0); } }
/** * @brief handle post-processing bloom */ void R_DrawBloom (void) { int i; bool renderBufferState; if (!r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer) return; /* save state, then set up for blit-style rendering to quads */ renderBufferState = R_RenderbufferEnabled(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); #ifndef GL_VERSION_ES_CM_1_0 glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT); #endif glOrtho(0, viddef.context.width, viddef.context.height, 0, 9999.0f, SKYBOX_DEPTH); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); /* downsample into image pyramid */ R_ResolveMSAA(fbo_render); R_BindTexture(fbo_render->textures[1]); qglGenerateMipmapEXT(GL_TEXTURE_2D); R_Blur(fbo_render, fbo_bloom0, 1, 0); R_Blur(fbo_bloom0, fbo_bloom1, 0, 1); R_UseFramebuffer(r_state.buffers0[0]); R_BindTexture(fbo_bloom1->textures[0]); qglGenerateMipmapEXT(GL_TEXTURE_2D); R_UseViewport(r_state.buffers0[0]); R_DrawQuad(); for (i = 1; i < DOWNSAMPLE_PASSES; i++) { R_Blur(r_state.buffers0[i - 1], r_state.buffers1[i - 1], 0, 0); R_Blur(r_state.buffers1[i - 1], r_state.buffers2[i - 1], 0, 1); R_UseFramebuffer(r_state.buffers0[i]); R_BindTexture(r_state.buffers2[i - 1]->textures[0]); R_UseViewport(r_state.buffers0[i]); R_DrawQuad(); } /* blur and combine downsampled images */ R_BlurStack(DOWNSAMPLE_PASSES, r_state.buffers0, r_state.buffers1); /* re-combine the blurred version with the original "glow" image */ R_UseProgram(r_state.combine2_program); R_UseFramebuffer(fbo_bloom0); R_BindTextureForTexUnit(fbo_render->textures[1], &texunit_0); R_BindTextureForTexUnit(r_state.buffers1[0]->textures[0], &texunit_1); R_UseViewport(fbo_screen); R_DrawQuad(); /* draw final result to the screenbuffer */ R_UseFramebuffer(fbo_screen); R_UseProgram(r_state.combine2_program); R_BindTextureForTexUnit(fbo_render->textures[0], &texunit_0); R_BindTextureForTexUnit(fbo_bloom0->textures[0], &texunit_1); R_DrawQuad(); /* cleanup before returning */ R_UseProgram(default_program); R_CheckError(); #ifndef GL_VERSION_ES_CM_1_0 glPopAttrib(); #endif glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); R_CheckError(); /* reset renderbuffer state to what it was before */ R_EnableRenderbuffer(renderBufferState); }