+ if (r_bloomstate.texture_screen)
+ {
+ // make sure the buffer is available
+ if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); }
+
+ R_ResetViewRendering2D();
+ R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+ R_Mesh_ColorPointer(NULL, 0, 0);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
+ GL_ActiveTexture(0);CHECKGLERROR
+
+ if(r_motionblur.value > 0 || r_damageblur.value > 0)
+ {
+ // declare alpha variable
+ float a;
+ float speed;
+ static float avgspeed;
+
+ speed = VectorLength(cl.movement_velocity);
+
+ a = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vtime.value), 1);
+ avgspeed = avgspeed * (1 - a) + speed * a;
+
+ speed = (avgspeed - r_motionblur_vmin.value) / max(1, r_motionblur_vmax.value - r_motionblur_vmin.value);
+ speed = bound(0, speed, 1);
+ speed = speed * (1 - r_motionblur_bmin.value) + r_motionblur_bmin.value;
+
+ // calculate values into a standard alpha
+ a = 1 - exp(-
+ (
+ (r_motionblur.value * speed / 80)
+ +
+ (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
+ )
+ /
+ max(0.0001, cl.time - cl.oldtime) // fps independent
+ );
+
+ a *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
+ a = bound(0, a, r_motionblur_maxblur.value);
+
+ // developer debug of current value
+ if (r_motionblur_debug.value) { Con_Printf("blur alpha = %f\n", a); }
+
+ // apply the blur
+ if (a > 0)
+ {
+ R_SetupGenericShader(true);
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_Color(1, 1, 1, a); // to do: add color changing support for damage blur
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
+ R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
+ r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
+ }
+ }
+
+ // copy view into the screen texture
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
+ r_refdef.stats.bloom_copypixels += r_refdef.view.width * r_refdef.view.height;
+ }
+
+ if (r_glsl.integer && gl_support_fragment_shader && (r_bloomstate.texture_screen || r_bloomstate.texture_bloom))
+ {
+ unsigned int permutation =
+ (r_bloomstate.texture_bloom ? SHADERPERMUTATION_GLOW : 0)
+ | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0)
+ | ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0)
+ | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
+ | (r_glsl_saturation.value != 1 ? SHADERPERMUTATION_SATURATION : 0);
+
+ if (r_bloomstate.texture_bloom && !r_bloomstate.hdr)
+ {
+ // render simple bloom effect
+ // copy the screen and shrink it and darken it for the bloom process
+ R_Bloom_CopyBloomTexture(r_bloom_colorscale.value);
+ // make the bloom texture
+ R_Bloom_MakeTexture();
+ }
+
+ R_ResetViewRendering2D();
+ R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+ R_Mesh_ColorPointer(NULL, 0, 0);
+ GL_Color(1, 1, 1, 1);
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ R_SetupShader_SetPermutation(SHADERMODE_POSTPROCESS, permutation);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
+ R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_bloom));
+ R_Mesh_TexCoordPointer(1, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
+ if (r_glsl_permutation->loc_Texture_GammaRamps >= 0)
+ R_Mesh_TexBind(GL20TU_GAMMARAMPS, R_GetTexture(r_texture_gammaramps));
+ if (r_glsl_permutation->loc_TintColor >= 0)
+ qglUniform4fARB(r_glsl_permutation->loc_TintColor, r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
+ if (r_glsl_permutation->loc_ClientTime >= 0)
+ qglUniform1fARB(r_glsl_permutation->loc_ClientTime, cl.time);
+ if (r_glsl_permutation->loc_PixelSize >= 0)
+ qglUniform2fARB(r_glsl_permutation->loc_PixelSize, 1.0/r_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight);
+ if (r_glsl_permutation->loc_UserVec1 >= 0)
+ {
+ float a=0, b=0, c=0, d=0;
+#if _MSC_VER >= 1400
+#define sscanf sscanf_s
+#endif
+ sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &a, &b, &c, &d);
+ qglUniform4fARB(r_glsl_permutation->loc_UserVec1, a, b, c, d);
+ }
+ if (r_glsl_permutation->loc_UserVec2 >= 0)
+ {
+ float a=0, b=0, c=0, d=0;
+ sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &a, &b, &c, &d);
+ qglUniform4fARB(r_glsl_permutation->loc_UserVec2, a, b, c, d);
+ }
+ if (r_glsl_permutation->loc_UserVec3 >= 0)
+ {
+ float a=0, b=0, c=0, d=0;
+ sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &a, &b, &c, &d);
+ qglUniform4fARB(r_glsl_permutation->loc_UserVec3, a, b, c, d);
+ }
+ if (r_glsl_permutation->loc_UserVec4 >= 0)
+ {
+ float a=0, b=0, c=0, d=0;
+ sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &a, &b, &c, &d);
+ qglUniform4fARB(r_glsl_permutation->loc_UserVec4, a, b, c, d);
+ }
+ if (r_glsl_permutation->loc_Saturation >= 0)
+ qglUniform1fARB(r_glsl_permutation->loc_Saturation, r_glsl_saturation.value);
+ R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
+ r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
+ return;
+ }
+
+
+
+ if (r_bloomstate.texture_bloom && r_bloomstate.hdr)