]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
implemented new bloom code (still not using GLSL, but the new bloom is much nicer...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 11 Jan 2007 04:48:25 +0000 (04:48 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 11 Jan 2007 04:48:25 +0000 (04:48 +0000)
added r_shadow_glossexponent cvar to control width of specular highlights
changed r_shadow_glossexponent default from 8 to 32 (looks more like metal or wet stone)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6683 d7cf8633-e32d-0410-b094-e92efae38249

gl_rmain.c
menu.c
todo

index 80b31da45018523ce378f45cb0d3d0c242c82a1f..76c5fa86069758bdb19f851836e8e34150499dc9 100644 (file)
@@ -76,14 +76,15 @@ cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smooth
 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
 
 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
-cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "1.5", "how bright the glow is"};
+cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
+cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
-cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "2", "how much to darken the image before blurring to make the bloom effect"};
+cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exagerated the glow is"};
+cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
 
 cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"};
 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
-cvar_t r_hdr_bloomintensity = {CVAR_SAVE, "r_hdr_bloomintensity", "0.5", "amount of bloom"};
 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
 
 cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
@@ -95,8 +96,36 @@ cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture
 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"}; // used for testing renderer code changes, otherwise does nothing
 cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"};
 
-rtexture_t *r_bloom_texture_screen;
-rtexture_t *r_bloom_texture_bloom;
+typedef struct r_glsl_bloomshader_s
+{
+       int program;
+       int loc_Texture_Bloom;
+}
+r_glsl_bloomshader_t;
+
+static struct r_bloomstate_s
+{
+       qboolean enabled;
+       qboolean hdr;
+
+       int bloomwidth, bloomheight;
+
+       int screentexturewidth, screentextureheight;
+       rtexture_t *texture_screen;
+
+       int bloomtexturewidth, bloomtextureheight;
+       rtexture_t *texture_bloom;
+
+       r_glsl_bloomshader_t *shader;
+
+       // arrays for rendering the screen passes
+       float vertex3f[12];
+       float screentexcoord2f[8];
+       float bloomtexcoord2f[8];
+       float offsettexcoord2f[8];
+}
+r_bloomstate;
+
 rtexture_t *r_texture_blanknormalmap;
 rtexture_t *r_texture_white;
 rtexture_t *r_texture_black;
@@ -932,8 +961,6 @@ void R_SwitchSurfaceShader(int permutation)
 void gl_main_start(void)
 {
        r_main_texturepool = R_AllocTexturePool();
-       r_bloom_texture_screen = NULL;
-       r_bloom_texture_bloom = NULL;
        R_BuildBlankTextures();
        R_BuildNoTexture();
        if (gl_texturecubemap)
@@ -942,19 +969,19 @@ void gl_main_start(void)
                R_BuildNormalizationCube();
        }
        R_BuildFogTexture();
+       memset(&r_bloomstate, 0, sizeof(r_bloomstate));
        memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
 }
 
 void gl_main_shutdown(void)
 {
        R_FreeTexturePool(&r_main_texturepool);
-       r_bloom_texture_screen = NULL;
-       r_bloom_texture_bloom = NULL;
        r_texture_blanknormalmap = NULL;
        r_texture_white = NULL;
        r_texture_black = NULL;
        r_texture_whitecube = NULL;
        r_texture_normalizationcube = NULL;
+       memset(&r_bloomstate, 0, sizeof(r_bloomstate));
        R_GLSL_Restart_f();
 }
 
@@ -1020,13 +1047,14 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_lerpmodels);
        Cvar_RegisterVariable(&r_waterscroll);
        Cvar_RegisterVariable(&r_bloom);
-       Cvar_RegisterVariable(&r_bloom_intensity);
+       Cvar_RegisterVariable(&r_bloom_colorscale);
+       Cvar_RegisterVariable(&r_bloom_brighten);
        Cvar_RegisterVariable(&r_bloom_blur);
        Cvar_RegisterVariable(&r_bloom_resolution);
-       Cvar_RegisterVariable(&r_bloom_power);
+       Cvar_RegisterVariable(&r_bloom_colorexponent);
+       Cvar_RegisterVariable(&r_bloom_colorsubtract);
        Cvar_RegisterVariable(&r_hdr);
        Cvar_RegisterVariable(&r_hdr_scenebrightness);
-       Cvar_RegisterVariable(&r_hdr_bloomintensity);
        Cvar_RegisterVariable(&r_hdr_glowintensity);
        Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
        Cvar_RegisterVariable(&developer_texturelogging);
@@ -1384,13 +1412,74 @@ void R_ResetViewRendering(void)
        GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
        GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
        GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
-       GL_ScissorTest(true);
-       GL_DepthMask(true);
-       GL_DepthTest(true);
+       GL_ScissorTest(false);
+       GL_DepthMask(false);
+       GL_DepthTest(false);
        R_Mesh_Matrix(&identitymatrix);
        R_Mesh_ResetTextureState();
 }
 
+/*
+       R_Bloom_SetupShader(
+"// bloom shader\n"
+"// written by Forest 'LordHavoc' Hale\n"
+"\n"
+"// common definitions between vertex shader and fragment shader:\n"
+"\n"
+"#ifdef __GLSL_CG_DATA_TYPES\n"
+"#define myhalf half\n"
+"#define myhvec2 hvec2\n"
+"#define myhvec3 hvec3\n"
+"#define myhvec4 hvec4\n"
+"#else\n"
+"#define myhalf float\n"
+"#define myhvec2 vec2\n"
+"#define myhvec3 vec3\n"
+"#define myhvec4 vec4\n"
+"#endif\n"
+"\n"
+"varying vec2 ScreenTexCoord;\n"
+"varying vec2 BloomTexCoord;\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"// vertex shader specific:\n"
+"#ifdef VERTEX_SHADER\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"      ScreenTexCoord = vec2(gl_MultiTexCoord0);\n"
+"      BloomTexCoord = vec2(gl_MultiTexCoord1);\n"
+"      // transform vertex to camera space, using ftransform to match non-VS\n"
+"      // rendering\n"
+"      gl_Position = ftransform();\n"
+"}\n"
+"\n"
+"#endif // VERTEX_SHADER\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"// fragment shader specific:\n"
+"#ifdef FRAGMENT_SHADER\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"      int x, y;
+"      myhvec3 color = myhvec3(texture2D(Texture_Screen, ScreenTexCoord));\n"
+"      for (x = -BLUR_X;x <= BLUR_X;x++)
+"      color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
+"      color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
+"      color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
+"      color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
+
+"      gl_FragColor = vec4(color);\n"
+"}\n"
+"\n"
+"#endif // FRAGMENT_SHADER\n"
+*/
+
 void R_SetupView(const matrix4x4_t *matrix)
 {
        if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
@@ -1403,76 +1492,120 @@ void R_SetupView(const matrix4x4_t *matrix)
 
 void R_RenderScene(void);
 
-void R_Bloom_MakeTexture(qboolean darken)
+void R_Bloom_StartFrame(void)
 {
-       int screenwidth, screenheight;
-       int screentexturewidth, screentextureheight;
-       int bloomtexturewidth, bloomtextureheight;
-       int bloomwidth, bloomheight, x, range;
-       float xoffset, yoffset, r;
-       float vertex3f[12];
-       float texcoord2f[3][8];
+       int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
 
        // set bloomwidth and bloomheight to the bloom resolution that will be
        // used (often less than the screen resolution for faster rendering)
-       bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
-       bloomheight = bound(1, bloomwidth * r_view.height / r_view.width, r_view.height);
+       r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
+       r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_view.height / r_view.width;
+       r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_view.height);
 
-       // set the (poorly named) screenwidth and screenheight variables to
-       // a power of 2 at least as large as the screen, these will define the
-       // size of the texture to allocate
-       for (screenwidth = 1;screenwidth < vid.width;screenwidth *= 2);
-       for (screenheight = 1;screenheight < vid.height;screenheight *= 2);
+       // calculate desired texture sizes
+       if (gl_support_arb_texture_non_power_of_two)
+       {
+               screentexturewidth = r_view.width;
+               screentextureheight = r_view.height;
+               bloomtexturewidth = r_bloomstate.bloomwidth;
+               bloomtextureheight = r_bloomstate.bloomheight;
+       }
+       else
+       {
+               for (screentexturewidth  = 1;screentexturewidth  < vid.width               ;screentexturewidth  *= 2);
+               for (screentextureheight = 1;screentextureheight < vid.height              ;screentextureheight *= 2);
+               for (bloomtexturewidth   = 1;bloomtexturewidth   < r_bloomstate.bloomwidth ;bloomtexturewidth   *= 2);
+               for (bloomtextureheight  = 1;bloomtextureheight  < r_bloomstate.bloomheight;bloomtextureheight  *= 2);
+       }
 
-       r_refdef.stats.bloom++;
+       if (r_hdr.integer)
+       {
+               screentexturewidth = screentextureheight = 0;
+       }
+       else if (r_bloom.integer)
+       {
+       }
+       else
+       {
+               screentexturewidth = screentextureheight = 0;
+               bloomtexturewidth = bloomtextureheight = 0;
+       }
 
-       // allocate textures as needed
-       // TODO: reallocate these when size settings change
-       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);
+       if ((!bloomtexturewidth && !bloomtextureheight) || r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512 || screentexturewidth > gl_max_texture_size || screentextureheight > gl_max_texture_size || bloomtexturewidth > gl_max_texture_size || bloomtextureheight > gl_max_texture_size)
+       {
+               // can't use bloom if the parameters are too weird
+               // can't use bloom if the card does not support the texture size
+               if (r_bloomstate.texture_screen)
+                       R_FreeTexture(r_bloomstate.texture_screen);
+               if (r_bloomstate.texture_bloom)
+                       R_FreeTexture(r_bloomstate.texture_bloom);
+               memset(&r_bloomstate, 0, sizeof(r_bloomstate));
+               return;
+       }
 
-       screentexturewidth = R_TextureWidth(r_bloom_texture_screen);
-       screentextureheight = R_TextureHeight(r_bloom_texture_screen);
-       bloomtexturewidth = R_TextureWidth(r_bloom_texture_bloom);
-       bloomtextureheight = R_TextureHeight(r_bloom_texture_bloom);
+       r_bloomstate.enabled = true;
+       r_bloomstate.hdr = r_hdr.integer != 0;
+
+       // allocate textures as needed
+       if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
+       {
+               if (r_bloomstate.texture_screen)
+                       R_FreeTexture(r_bloomstate.texture_screen);
+               r_bloomstate.texture_screen = NULL;
+               r_bloomstate.screentexturewidth = screentexturewidth;
+               r_bloomstate.screentextureheight = screentextureheight;
+               if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
+                       r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+       }
+       if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
+       {
+               if (r_bloomstate.texture_bloom)
+                       R_FreeTexture(r_bloomstate.texture_bloom);
+               r_bloomstate.texture_bloom = NULL;
+               r_bloomstate.bloomtexturewidth = bloomtexturewidth;
+               r_bloomstate.bloomtextureheight = bloomtextureheight;
+               if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
+                       r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+       }
 
        // vertex coordinates for a quad that covers the screen exactly
-       vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
-       vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
-       vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
-       vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
+       r_bloomstate.vertex3f[0] = 0;r_bloomstate.vertex3f[1] = 0;r_bloomstate.vertex3f[2] = 0;
+       r_bloomstate.vertex3f[3] = 1;r_bloomstate.vertex3f[4] = 0;r_bloomstate.vertex3f[5] = 0;
+       r_bloomstate.vertex3f[6] = 1;r_bloomstate.vertex3f[7] = 1;r_bloomstate.vertex3f[8] = 0;
+       r_bloomstate.vertex3f[9] = 0;r_bloomstate.vertex3f[10] = 1;r_bloomstate.vertex3f[11] = 0;
 
        // set up a texcoord array for the full resolution screen image
        // (we have to keep this around to copy back during final render)
-       texcoord2f[0][0] = 0;
-       texcoord2f[0][1] = (float)r_view.height / (float)screentextureheight;
-       texcoord2f[0][2] = (float)r_view.width / (float)screentexturewidth;
-       texcoord2f[0][3] = (float)r_view.height / (float)screentextureheight;
-       texcoord2f[0][4] = (float)r_view.width / (float)screentexturewidth;
-       texcoord2f[0][5] = 0;
-       texcoord2f[0][6] = 0;
-       texcoord2f[0][7] = 0;
+       r_bloomstate.screentexcoord2f[0] = 0;
+       r_bloomstate.screentexcoord2f[1] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
+       r_bloomstate.screentexcoord2f[2] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
+       r_bloomstate.screentexcoord2f[3] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
+       r_bloomstate.screentexcoord2f[4] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
+       r_bloomstate.screentexcoord2f[5] = 0;
+       r_bloomstate.screentexcoord2f[6] = 0;
+       r_bloomstate.screentexcoord2f[7] = 0;
 
        // set up a texcoord array for the reduced resolution bloom image
        // (which will be additive blended over the screen image)
-       texcoord2f[1][0] = 0;
-       texcoord2f[1][1] = (float)bloomheight / (float)bloomtextureheight;
-       texcoord2f[1][2] = (float)bloomwidth / (float)bloomtexturewidth;
-       texcoord2f[1][3] = (float)bloomheight / (float)bloomtextureheight;
-       texcoord2f[1][4] = (float)bloomwidth / (float)bloomtexturewidth;
-       texcoord2f[1][5] = 0;
-       texcoord2f[1][6] = 0;
-       texcoord2f[1][7] = 0;
+       r_bloomstate.bloomtexcoord2f[0] = 0;
+       r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
+       r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
+       r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
+       r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
+       r_bloomstate.bloomtexcoord2f[5] = 0;
+       r_bloomstate.bloomtexcoord2f[6] = 0;
+       r_bloomstate.bloomtexcoord2f[7] = 0;
+}
+
+void R_Bloom_CopyScreenTexture(float colorscale)
+{
+       r_refdef.stats.bloom++;
 
        R_ResetViewRendering();
-       GL_DepthTest(false);
-       R_Mesh_VertexPointer(vertex3f);
+       R_Mesh_VertexPointer(r_bloomstate.vertex3f);
        R_Mesh_ColorPointer(NULL);
-
-       R_Mesh_TexCoordPointer(0, 2, texcoord2f[0]);
-       R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_screen));
+       R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f);
+       R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
 
        // copy view into the screen texture
        GL_ActiveTexture(0);
@@ -1482,105 +1615,134 @@ void R_Bloom_MakeTexture(qboolean darken)
 
        // now scale it down to the bloom texture size
        CHECKGLERROR
-       qglViewport(r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
+       qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
        GL_BlendFunc(GL_ONE, GL_ZERO);
-       GL_Color(1, 1, 1, 1);
+       GL_Color(colorscale, colorscale, colorscale, 1);
        // TODO: optimize with multitexture or GLSL
        R_Mesh_Draw(0, 4, 2, polygonelements);
-       r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
+       r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
 
-       if (darken)
-       {
-               // raise to a power of itself to darken it (this leaves the really
-               // bright stuff bright, and everything else becomes very dark)
-               // render multiple times with a multiply blendfunc to raise to a power
-               GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
-               for (x = 1;x < r_bloom_power.integer;x++)
-               {
-                       R_Mesh_Draw(0, 4, 2, polygonelements);
-                       r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
-               }
-       }
+       // we now have a bloom image in the framebuffer
+       // copy it into the bloom image texture for later processing
+       R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+       GL_ActiveTexture(0);
+       CHECKGLERROR
+       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
+       r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+}
 
-       // we now have a darkened bloom image in the framebuffer
-       // copy it into the bloom image texture for more processing
-       R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_bloom));
-       R_Mesh_TexCoordPointer(0, 2, texcoord2f[2]);
+void R_Bloom_CopyHDRTexture(void)
+{
+       R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
        GL_ActiveTexture(0);
        CHECKGLERROR
-       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
-       r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
+       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
+       r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
+}
 
-       // blend on at multiple vertical offsets to achieve a vertical blur
-       // 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;
-               // compute a texcoord array with the specified x and y offset
-               texcoord2f[2][0] = xoffset+0;
-               texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
-               texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
-               texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
-               texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
-               texcoord2f[2][5] = yoffset+0;
-               texcoord2f[2][6] = xoffset+0;
-               texcoord2f[2][7] = yoffset+0;
-               // this r value looks like a 'dot' particle, fading sharply to
-               // black at the edges
-               // (probably not realistic but looks good enough)
-               r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
-               if (r < 0.01f)
-                       continue;
+void R_Bloom_MakeTexture(void)
+{
+       int x, range, dir;
+       float xoffset, yoffset, r;
+
+       r_refdef.stats.bloom++;
+
+       R_ResetViewRendering();
+       R_Mesh_VertexPointer(r_bloomstate.vertex3f);
+       R_Mesh_ColorPointer(NULL);
+
+       // we have a bloom image in the framebuffer
+       CHECKGLERROR
+       qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
+
+       for (x = 1;x < r_bloom_colorexponent.value;)
+       {
+               x *= 2;
+               r = bound(0, r_bloom_colorexponent.value / x, 1);
+               GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
                GL_Color(r, r, r, 1);
+               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
                R_Mesh_Draw(0, 4, 2, polygonelements);
-               r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
-               GL_BlendFunc(GL_ONE, GL_ONE);
+               r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+
+               // copy the vertically blurred bloom view to a texture
+               GL_ActiveTexture(0);
+               CHECKGLERROR
+               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
+               r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
        }
 
-       // copy the vertically blurred bloom view to a texture
-       GL_ActiveTexture(0);
-       CHECKGLERROR
-       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
-       r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
+       range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
+       R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+       R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f);
 
-       // blend the vertically blurred image at multiple offsets horizontally
-       // to finish the blur effect
-       // 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;
-               // compute a texcoord array with the specified x and y offset
-               texcoord2f[2][0] = xoffset+0;
-               texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
-               texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
-               texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
-               texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
-               texcoord2f[2][5] = yoffset+0;
-               texcoord2f[2][6] = xoffset+0;
-               texcoord2f[2][7] = yoffset+0;
-               // this r value looks like a 'dot' particle, fading sharply to
-               // black at the edges
-               // (probably not realistic but looks good enough)
-               r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
-               if (r < 0.01f)
-                       continue;
-               GL_Color(r, r, r, 1);
+       for (dir = 0;dir < 2;dir++)
+       {
+               // blend on at multiple vertical offsets to achieve a vertical blur
+               // TODO: do offset blends using GLSL
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               for (x = -range;x <= range;x++)
+               {
+                       if (!dir){xoffset = 0;yoffset = x;}
+                       else {xoffset = x;yoffset = 0;}
+                       xoffset /= (float)r_bloomstate.bloomtexturewidth;
+                       yoffset /= (float)r_bloomstate.bloomtextureheight;
+                       // compute a texcoord array with the specified x and y offset
+                       r_bloomstate.offsettexcoord2f[0] = xoffset+0;
+                       r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
+                       r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
+                       r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
+                       r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
+                       r_bloomstate.offsettexcoord2f[5] = yoffset+0;
+                       r_bloomstate.offsettexcoord2f[6] = xoffset+0;
+                       r_bloomstate.offsettexcoord2f[7] = yoffset+0;
+                       // this r value looks like a 'dot' particle, fading sharply to
+                       // black at the edges
+                       // (probably not realistic but looks good enough)
+                       //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
+                       //r = (dir ? 1.0f : r_bloom_brighten.value)/(range*2+1);
+                       r = (dir ? 1.0f : r_bloom_brighten.value)/(range*2+1)*(1 - x*x/(float)(range*range));
+                       GL_Color(r, r, r, 1);
+                       R_Mesh_Draw(0, 4, 2, polygonelements);
+                       r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+                       GL_BlendFunc(GL_ONE, GL_ONE);
+               }
+
+               // copy the vertically blurred bloom view to a texture
+               GL_ActiveTexture(0);
+               CHECKGLERROR
+               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
+               r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+       }
+
+       // apply subtract last
+       // (just like it would be in a GLSL shader)
+       if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
+       {
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
+               GL_Color(1, 1, 1, 1);
                R_Mesh_Draw(0, 4, 2, polygonelements);
-               r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
+               r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+
                GL_BlendFunc(GL_ONE, GL_ONE);
-       }
+               qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
+               R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
+               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
+               GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
+               R_Mesh_Draw(0, 4, 2, polygonelements);
+               r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+               qglBlendEquationEXT(GL_FUNC_ADD_EXT);
 
-       // copy the blurred bloom view to a texture
-       GL_ActiveTexture(0);
-       CHECKGLERROR
-       qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
-       r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
+               // copy the darkened bloom view to a texture
+               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+               GL_ActiveTexture(0);
+               CHECKGLERROR
+               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
+               r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+       }
 }
 
 void R_HDR_RenderBloomTexture(void)
@@ -1589,21 +1751,24 @@ void R_HDR_RenderBloomTexture(void)
 
        oldwidth = r_view.width;
        oldheight = r_view.height;
-       r_view.width = bound(1, r_bloom_resolution.integer, min(r_view.width, gl_max_texture_size));
-       r_view.height = r_view.width * oldheight / oldwidth;
+       r_view.width = r_bloomstate.bloomwidth;
+       r_view.height = r_bloomstate.bloomheight;
 
        // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer?  it might improve SLI performance.
-       // FIXME: change global lightmapintensity and light intensity according to r_hdr_bloomintensity cvar
-       // FIXME: change global lightmapintensity and light intensity according to r_hdr_scenebrightness cvar
        // TODO: add exposure compensation features
 
-       r_view.colorscale = r_hdr_bloomintensity.value * r_hdr_scenebrightness.value;
+       r_view.colorscale = r_bloom_colorscale.value * r_hdr_scenebrightness.value;
        R_RenderScene();
 
        R_ResetViewRendering();
 
-       R_Bloom_MakeTexture(false);
+       R_Bloom_CopyHDRTexture();
+       R_Bloom_MakeTexture();
 
+       R_ResetViewRendering();
+       GL_ScissorTest(true);
+       GL_DepthMask(true);
+       GL_DepthTest(true);
        R_ClearScreen();
        if (r_timereport_active)
                R_TimeReport("clear");
@@ -1611,102 +1776,47 @@ void R_HDR_RenderBloomTexture(void)
        // restore the view settings
        r_view.width = oldwidth;
        r_view.height = oldheight;
-
-       // go back to full view area
-       R_ResetViewRendering();
 }
 
 static void R_BlendView(void)
 {
-       int screenwidth, screenheight;
-       int bloomwidth, bloomheight;
-       qboolean dobloom;
-       qboolean dohdr;
-       qboolean doblend;
-       float vertex3f[12];
-       float texcoord2f[3][8];
-
-       // set the (poorly named) screenwidth and screenheight variables to
-       // a power of 2 at least as large as the screen, these will define the
-       // size of the texture to allocate
-       for (screenwidth = 1;screenwidth < vid.width;screenwidth *= 2);
-       for (screenheight = 1;screenheight < vid.height;screenheight *= 2);
-
-       doblend = r_refdef.viewblend[3] >= 0.01f;
-       dobloom = !r_hdr.integer && r_bloom.integer && screenwidth <= gl_max_texture_size && screenheight <= gl_max_texture_size && 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;
-       dohdr = r_hdr.integer && screenwidth <= gl_max_texture_size && screenheight <= gl_max_texture_size && 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;
-
-       if (!dobloom && !dohdr && !doblend)
-               return;
-
-       // vertex coordinates for a quad that covers the screen exactly
-       vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
-       vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
-       vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
-       vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
-
-       // set bloomwidth and bloomheight to the bloom resolution that will be
-       // used (often less than the screen resolution for faster rendering)
-       bloomwidth = min(r_view.width, r_bloom_resolution.integer);
-       bloomheight = min(r_view.height, bloomwidth * r_view.height / r_view.width);
-       // set up a texcoord array for the full resolution screen image
-       // (we have to keep this around to copy back during final render)
-       texcoord2f[0][0] = 0;
-       texcoord2f[0][1] = (float)r_view.height / (float)screenheight;
-       texcoord2f[0][2] = (float)r_view.width / (float)screenwidth;
-       texcoord2f[0][3] = (float)r_view.height / (float)screenheight;
-       texcoord2f[0][4] = (float)r_view.width / (float)screenwidth;
-       texcoord2f[0][5] = 0;
-       texcoord2f[0][6] = 0;
-       texcoord2f[0][7] = 0;
-       // set up a texcoord array for the reduced resolution bloom image
-       // (which will be additive blended over the screen image)
-       texcoord2f[1][0] = 0;
-       texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
-       texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
-       texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
-       texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
-       texcoord2f[1][5] = 0;
-       texcoord2f[1][6] = 0;
-       texcoord2f[1][7] = 0;
-
-       if (dohdr)
+       if (r_bloomstate.enabled && r_bloomstate.hdr)
        {
                // render high dynamic range bloom effect
                // the bloom texture was made earlier this render, so we just need to
                // blend it onto the screen...
                R_ResetViewRendering();
-               GL_DepthTest(false);
-               R_Mesh_VertexPointer(vertex3f);
+               R_Mesh_VertexPointer(r_bloomstate.vertex3f);
                R_Mesh_ColorPointer(NULL);
                GL_Color(1, 1, 1, 1);
                GL_BlendFunc(GL_ONE, GL_ONE);
-               R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_bloom));
-               R_Mesh_TexCoordPointer(0, 2, texcoord2f[1]);
+               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
                R_Mesh_Draw(0, 4, 2, polygonelements);
                r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
        }
-       if (dobloom)
+       else if (r_bloomstate.enabled)
        {
                // render simple bloom effect
+               // copy the screen and shrink it and darken it for the bloom process
+               R_Bloom_CopyScreenTexture(r_bloom_colorscale.value);
                // make the bloom texture
-               R_Bloom_MakeTexture(true);
+               R_Bloom_MakeTexture();
                // put the original screen image back in place and blend the bloom
                // texture on it
                R_ResetViewRendering();
-               GL_DepthTest(false);
-               R_Mesh_VertexPointer(vertex3f);
+               R_Mesh_VertexPointer(r_bloomstate.vertex3f);
                R_Mesh_ColorPointer(NULL);
                GL_Color(1, 1, 1, 1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
                // do both in one pass if possible
-               R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_screen));
-               R_Mesh_TexCoordPointer(0, 2, texcoord2f[0]);
+               R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
                if (r_textureunits.integer >= 2 && gl_combine.integer)
                {
                        R_Mesh_TexCombine(1, GL_ADD, GL_ADD, 1, 1);
-                       R_Mesh_TexBind(1, R_GetTexture(r_bloom_texture_bloom));
-                       R_Mesh_TexCoordPointer(1, 2, texcoord2f[1]);
+                       R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
+                       R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f);
                }
                else
                {
@@ -1714,18 +1824,17 @@ static void R_BlendView(void)
                        r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
                        // now blend on the bloom texture
                        GL_BlendFunc(GL_ONE, GL_ONE);
-                       R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_bloom));
-                       R_Mesh_TexCoordPointer(0, 2, texcoord2f[1]);
+                       R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
+                       R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f);
                }
                R_Mesh_Draw(0, 4, 2, polygonelements);
                r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
        }
-       if (doblend)
+       if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
        {
                // apply a color tint to the whole view
                R_ResetViewRendering();
-               GL_DepthTest(false);
-               R_Mesh_VertexPointer(vertex3f);
+               R_Mesh_VertexPointer(r_bloomstate.vertex3f);
                R_Mesh_ColorPointer(NULL);
                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]);
@@ -1816,8 +1925,6 @@ void R_RenderView(void)
                return; //Host_Error ("R_RenderView: NULL worldmodel");
 
        CHECKGLERROR
-       GL_ScissorTest(true);
-       GL_DepthMask(true);
        if (r_timereport_active)
                R_TimeReport("setup");
 
@@ -1826,11 +1933,15 @@ void R_RenderView(void)
                R_TimeReport("visibility");
 
        R_ResetViewRendering();
-
+       GL_ScissorTest(true);
+       GL_DepthMask(true);
+       GL_DepthTest(true);
        R_ClearScreen();
        if (r_timereport_active)
                R_TimeReport("clear");
 
+       R_Bloom_StartFrame();
+
        // this produces a bloom texture to be used in R_BlendView() later
        if (r_hdr.integer)
                R_HDR_RenderBloomTexture();
@@ -2398,7 +2509,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
        t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
        t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
        t->glosstexture = r_texture_white;
-       t->specularpower = 8;
+       t->specularpower = r_shadow_glossexponent.value;
        t->specularscale = 0;
        if (r_shadow_gloss.integer > 0)
        {
diff --git a/menu.c b/menu.c
index 7e0b1b22ee2a27ad6225450452ef0df565065c65..3a0f0d7cd803eb3e2419a13769a0bdef2e3154c1 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -1976,7 +1976,7 @@ static void M_Options_Effects_Key (int k, char ascii)
 }
 
 
-#define        OPTIONS_GRAPHICS_ITEMS  18
+#define        OPTIONS_GRAPHICS_ITEMS  16
 
 static int options_graphics_cursor;
 
@@ -1995,12 +1995,12 @@ extern cvar_t r_shadow_realtime_world_dlightshadows;
 extern cvar_t r_shadow_realtime_world_lightmaps;
 extern cvar_t r_shadow_realtime_world_shadows;
 extern cvar_t r_bloom;
-extern cvar_t r_bloom_intensity;
-extern cvar_t r_bloom_power;
+extern cvar_t r_bloom_colorscale;
+extern cvar_t r_bloom_colorsubtract;
+extern cvar_t r_bloom_colorexponent;
 extern cvar_t r_bloom_blur;
 extern cvar_t r_bloom_resolution;
 extern cvar_t r_hdr;
-extern cvar_t r_hdr_bloomintensity;
 extern cvar_t r_hdr_scenebrightness;
 extern cvar_t r_hdr_glowintensity;
 extern cvar_t gl_picmip;
@@ -2021,10 +2021,10 @@ static void M_Menu_Options_Graphics_AdjustSliders (int dir)
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_realtime_world_shadows,                     !r_shadow_realtime_world_shadows.integer);
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom,                                 !r_bloom.integer);
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr,                                   !r_hdr.integer);
-       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr_bloomintensity,                    bound(0.125, r_hdr_bloomintensity.value + dir * 0.125, 4));
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr_glowintensity,                     bound(0, r_hdr_glowintensity.value + dir * 0.25, 4));
-       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_power,                           bound(1, r_bloom_power.value + dir * 1, 16));
-       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_intensity,                       bound(1, r_bloom_intensity.value + dir * 0.25, 16));
+       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_colorscale,                      bound(0.0625, r_bloom_colorscale.value + dir * 0.0625, 1));
+       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_colorsubtract,                   bound(0, r_bloom_colorsubtract.value + dir * 0.0625, 1-0.0625));
+       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_colorexponent,                   bound(1, r_bloom_colorexponent.value *= (dir > 0 ? 2 : 0.5), 8));
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_blur,                            bound(1, r_bloom_blur.value + dir * 1, 16));
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_resolution,                      bound(64, r_bloom_resolution.value + dir * 64, 2048));
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr_scenebrightness,                   bound(0.25, r_hdr_scenebrightness.value + dir * 0.125, 4));
@@ -2058,10 +2058,11 @@ static void M_Options_Graphics_Draw (void)
        M_Options_PrintCheckbox("        RT World Shadow", true, r_shadow_realtime_world_shadows.integer);
        M_Options_PrintCheckbox("           Bloom Effect", !r_hdr.integer, r_bloom.integer);
        M_Options_PrintCheckbox("       HDR Bloom Effect", r_hdr.integer, r_hdr.integer);
-       M_Options_PrintSlider(  "    HDR Bloom Intensity", r_hdr.integer, r_hdr_bloomintensity.value, 0.125, 4);
        M_Options_PrintSlider(  "     HDR Glow Intensity", r_hdr.integer, r_hdr_glowintensity.value, 0, 4);
-       M_Options_PrintSlider(  "Non-HDR Bloom Darkening", !r_hdr.integer && r_bloom.integer, r_bloom_power.value, 1, 16);
-       M_Options_PrintSlider(  "        Bloom Intensity", r_hdr.integer || r_bloom.integer, r_bloom_intensity.value, 1, 16);
+       M_Options_PrintSlider(  "      Bloom Color Scale", r_hdr.integer || r_bloom.integer, r_bloom_colorscale.value, 0.0625, 1);
+       M_Options_PrintSlider(  "   Bloom Color Subtract", r_hdr.integer || r_bloom.integer, r_bloom_colorsubtract.value, 0, 1-0.0625);
+       M_Options_PrintSlider(  "   Bloom Color Exponent", r_hdr.integer || r_bloom.integer, r_bloom_colorexponent.value, 1, 8);
+       M_Options_PrintSlider(  "        Bloom Intensity", r_hdr.integer || r_bloom.integer, r_bloom_colorscale.value, 0.125, 4);
        M_Options_PrintSlider(  "             Bloom Blur", r_hdr.integer || r_bloom.integer, r_bloom_blur.value, 1, 16);
        M_Options_PrintSlider(  "       Bloom Resolution", r_hdr.integer || r_bloom.integer, r_bloom_resolution.value, 64, 2048);
        M_Options_PrintSlider(  "       Scene Brightness", true, r_hdr_scenebrightness.value, 0.25, 4);
diff --git a/todo b/todo
index c385964c06e1adcc4219b9277d69c22b6b843bfb..d3a7dbeca49a7b9a19e952a3c3a2ba65f7670064 100644 (file)
--- a/todo
+++ b/todo
@@ -33,8 +33,6 @@
 -d (yummyluv) feature darkplaces protocol: add buttons 9-16 (yummyluv)
 -f (James D) bug darkplaces server: losing runes on episode completion, completing episode 1 then 2 then 3 causes it to forget 1, then 4 causes it to forget 2 and 3, making it impossible to open the boss gate (James D)
 -f (Wazat) bug darkplaces: client's slowmo detection (measuring packet times and comparing to game time changes) may be making the game unpleasant (Wazat)
-0 change darkplaces client: put depthtest flag in texturelayer_t
-0 bug hmap2: handle \" properly in hmap2 cmdlib.c COM_Parse (sort)
 0 bug darkplaces client: GAME_NEHAHRA: make sure cutscenes and movies work, got a report of seeing a black screen (NightFright)
 0 bug darkplaces client: hipnotic: health is one character to the right on the sbar, covering up the key icons (M`Shacron)
 0 bug darkplaces client: it has been reported that sometimes level changes on quakeworld servers don't load a map, this may be related to downloading? (Baker)
@@ -66,6 +64,7 @@
 0 bug darkplaces server: if sv_fixedframeratesingleplayer is 0 and cl_maxfps is something like 10, the server still runs every frame, consuming massive amounts of cpu and resulting in very small frametime values
 0 bug darkplaces server: in X-Men: Ravages of Apocalypse the weapon part in x1m3 fails to follow the platform it is on, it is probably spawning inside the ceiling and for some reason not associating with the platform as its groundentity? (qwerasdf)
 0 bug darkplaces server: in X-Men: Ravages of Apocalypse the weapon part in x2m4 falls out of the level, along with a few other items in the same secret (qwerasdf)
+0 bug darkplaces sound: remove playing sounds when their owner entity has been removed by network code, this would mean that Nexuiz could have rocket/electro noise again (Qantoursic)
 0 bug darkplaces wgl client: during video mode setup, sometimes another application's window becomes permanently top most, not darkplaces' fullscreen window, why? (tZork)
 0 bug darkplaces wgl client: hardware gamma is being retried every frame for unknown reasons, this is SEVERELY impacting framerates on win2k/xp (Jago)
 0 bug darkplaces windows general: include libcurl dll from Nexuiz 2.0 in future releases (Baker)
 0 bug hmap2 -qbsp: various errors still occur for Predator's Transfusion maps (Predator)
 0 bug hmap2 -vis: test that bitlongs code works properly on big endian systems such as Mac (LordHavoc)
 0 bug hmap2: figure out why there is a subtle difference between bmodel lighting and wall lighting, something to do with nudges causing different attenuation? (Urre)
+0 bug hmap2: handle \" properly in hmap2 cmdlib.c COM_Parse (sort)
 0 bug hmap: strip .map extension from filename if present
 0 change darkplaces client: change timedemo minfps/maxfps to be the lowest and highest fps in one second segments, similar to the showfps display, this should solve the precision problems resulting in stupidly high/low fps reports (m0rfar)
 0 change darkplaces client: disable all possible 'cheat' things unless -developer is given on commandline, this includes r_show*, r_test, gl_lightmaps, r_fullbright
 0 change darkplaces client: hardcode sbar image sizes so they can be replaced with higher quality images
+0 change darkplaces client: implement inversion of non-uniform scaling in Matrix4x4_Invert_Simple or replace it with a full featured matrix inverter
 0 change darkplaces client: modify cl_particles_quake to make all the engine dlights be white and look as much like quake as possible (Jago)
 0 change darkplaces client: particles shouldn't be using contents checks to decide whether to die, they should use movement traces
 0 change darkplaces client: restrict wateralpha and such cvars according to what is permitted in qw serverinfo?
 0 feature darkplaces protocol: add DP_WEAPONSKIN extension which would add a .float weaponskin field (protoplasmatic, Kazashi)
 0 feature darkplaces protocol: add EF_NOLERP effect for mods to use to prevent interpolation across teleports (Kinn, CuBe0wL)
 0 feature darkplaces protocol: add TE_LASER effect with values Entity owner Vector start Vector end Byte palettecolor Byte startalpha Byte endalpha Byte beam width (in quake units) Byte lifetime (0-255 for 0-1 seconds), skin index (looking up a gfx/particles/beam%03i.tga), it fades from startalpha to endalpha over time (Wazat, Vermeulen)
+0 feature darkplaces protocol: add a .fatness field which enlarges models along their vertex normals, this won't work on bsp models or sprites, label this as FTE_PEXT_FATNESS in the extensions string (Dresk)
+0 feature darkplaces protocol: add a .scalexyz field which would allow non-uniform scaling of models, and may requires upgrading some lighting code but I am not sure (Dresk)
 0 feature darkplaces protocol: add a new TE_ explosion effect with RGB color choice for particle color and another choice for light color (VorteX)
 0 feature darkplaces protocol: add an EF_BULLETTRACER trail effect which can be used to make an invisible entity into a tracer, a bright streak leaving a faint smoke trail (Carni)
 0 feature darkplaces protocol: add lava-steam particle puff effect for bursting lava bubbles (Zombie)
 0 feature darkplaces server: add a DP_QC_WARNING extension which has a "warning" builtin that does a PF_WARNING just to print the requested message, opcode dump, and stack trace (FrikaC)
 0 feature darkplaces server: add a clipmask thingy to allow QC to mask off collisions as it wishes (Uffe)
 0 feature darkplaces server: add a sv_gameplayfix_slidewhenstandingonmonster cvar to allow the FL_ONGROUND when ontop of a SOLID_BBOX/SOLID_SLIDEBOX to be disabled
+0 feature darkplaces server: add a sv_netticrate cvar which allows less frequent network updates (Urre)
 0 feature darkplaces server: add back edict, edicts and edictset commands (just as stubs that call the prvm_edict/edicts/edictset server commands) for convenience and compatibility with quake modding practices
 0 feature darkplaces server: add cl_prydoncursor_centeredcursor cvar and PRYDON_CLIENTCURSOR_CENTEREDCURSOR extension (Wazat)
 0 feature darkplaces server: add sv_antilag cvar which would upgrade the aim() builtin to aim at the creature the player's prydon cursor trace was hitting (Spike)
@@ -635,6 +639,7 @@ d bug darkplaces server: when trying to load a map that is missing the model is
 d bug darkplaces sound: spatialization bug occurs in The Ascension of Vigil, making all player and monster sounds far to the right (RenegadeC)
 d bug darkplaces video: generate 1024 color gamma ramps for glx on Quadro, right now hardware gamma is being disabled on these cards because they use 1024 color ramps, not 256 (div0)
 d bug dpmod: air control doesn't seem to be working (Kedhrin)
+d bug dpmod: fix sv_user.qc noclip movement when looking straight up/down (Electro)
 d bug dpmod: fix the 'shell casing spawning at wrong player' bug somehow
 d bug dpmod: items aren't respawning in coop, they should
 d bug dpmod: nailgun mine launching doesn't trigger a player animation (sng one does)