+ varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
+ varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
+ varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
+ varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
+ if (r_bloom.integer && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512)
+ {
+ int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
+ float xoffset, yoffset, r;
+ c_bloom++;
+ for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
+ for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
+ bloomwidth = min(r_view_width, r_bloom_resolution.integer);
+ bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
+ varray_texcoord2f[0][0] = 0;
+ varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
+ varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
+ varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
+ varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
+ varray_texcoord2f[0][5] = 0;
+ varray_texcoord2f[0][6] = 0;
+ varray_texcoord2f[0][7] = 0;
+ varray_texcoord2f[1][0] = 0;
+ varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
+ varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
+ varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[1][5] = 0;
+ varray_texcoord2f[1][6] = 0;
+ varray_texcoord2f[1][7] = 0;
+ if (!r_bloom_texture_screen)
+ r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+ if (!r_bloom_texture_bloom)
+ r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = varray_vertex3f;
+ m.pointer_texcoord[0] = varray_texcoord2f[0];
+ m.tex[0] = R_GetTexture(r_bloom_texture_screen);
+ R_Mesh_State(&m);
+ // copy view to a texture
+ GL_ActiveTexture(0);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
+ c_bloomcopies++;
+ c_bloomcopypixels += r_view_width * r_view_height;
+ // now scale it down to the bloom size and raise to a power of itself
+ qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ // TODO: optimize with multitexture or GLSL
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_Color(1, 1, 1, 1);
+ R_Mesh_Draw(4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += bloomwidth * bloomheight;
+ GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
+ for (x = 1;x < r_bloom_power.integer;x++)
+ {
+ R_Mesh_Draw(4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += bloomwidth * bloomheight;
+ }
+ // copy the bloom view to a texture
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = varray_vertex3f;
+ m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
+ m.pointer_texcoord[0] = varray_texcoord2f[2];
+ R_Mesh_State(&m);
+ GL_ActiveTexture(0);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ c_bloomcopies++;
+ c_bloomcopypixels += bloomwidth * bloomheight;
+ // blend on at multiple offsets vertically
+ // TODO: do offset blends using GLSL
+ range = r_bloom_blur.integer * bloomwidth / 320;
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ for (x = -range;x <= range;x++)
+ {
+ xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
+ yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
+ varray_texcoord2f[2][0] = xoffset+0;
+ varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
+ varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
+ varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[2][5] = yoffset+0;
+ varray_texcoord2f[2][6] = xoffset+0;
+ varray_texcoord2f[2][7] = yoffset+0;
+ r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
+ if (r < 0.01f)
+ continue;
+ GL_Color(r, r, r, 1);
+ R_Mesh_Draw(4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += bloomwidth * bloomheight;
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ }
+ // copy the blurred bloom view to a texture
+ GL_ActiveTexture(0);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ c_bloomcopies++;
+ c_bloomcopypixels += bloomwidth * bloomheight;
+ // blend on at multiple offsets horizontally
+ // TODO: do offset blends using GLSL
+ range = r_bloom_blur.integer * bloomwidth / 320;
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ for (x = -range;x <= range;x++)
+ {
+ xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
+ yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
+ varray_texcoord2f[2][0] = xoffset+0;
+ varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
+ varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
+ varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[2][5] = yoffset+0;
+ varray_texcoord2f[2][6] = xoffset+0;
+ varray_texcoord2f[2][7] = yoffset+0;
+ r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
+ if (r < 0.01f)
+ continue;
+ GL_Color(r, r, r, 1);
+ R_Mesh_Draw(4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += bloomwidth * bloomheight;
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ }
+ // copy the blurred bloom view to a texture
+ GL_ActiveTexture(0);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ c_bloomcopies++;
+ c_bloomcopypixels += bloomwidth * bloomheight;
+ // go back to full view area
+ qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
+ // put the original view back in place
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = varray_vertex3f;
+ m.tex[0] = R_GetTexture(r_bloom_texture_screen);
+ m.pointer_texcoord[0] = varray_texcoord2f[0];
+#if 0
+ dobloomblend = false;
+#else
+ // do both in one pass if possible
+ if (r_textureunits.integer >= 2 && gl_combine.integer)
+ {
+ dobloomblend = false;
+ m.texcombinergb[1] = GL_ADD;
+ m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
+ m.pointer_texcoord[1] = varray_texcoord2f[1];
+ }
+ else
+ dobloomblend = true;
+#endif
+ R_Mesh_State(&m);
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_Color(1,1,1,1);
+ R_Mesh_Draw(4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += r_view_width * r_view_height;
+ // now blend on the bloom texture if multipass
+ if (dobloomblend)
+ {
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = varray_vertex3f;
+ m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
+ m.pointer_texcoord[0] = varray_texcoord2f[1];
+ R_Mesh_State(&m);
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ GL_Color(1,1,1,1);
+ R_Mesh_Draw(4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += r_view_width * r_view_height;
+ }
+ }
+ if (r_refdef.viewblend[3] >= 0.01f)
+ {
+ // apply a color tint to the whole view
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = varray_vertex3f;
+ R_Mesh_State(&m);
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
+ R_Mesh_Draw(4, 2, polygonelements);
+ }