]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
added HDR bloom feature, not very different from bloom but looks better, runs a bit...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 11 Jun 2006 23:24:18 +0000 (23:24 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 11 Jun 2006 23:24:18 +0000 (23:24 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6469 d7cf8633-e32d-0410-b094-e92efae38249

cl_particles.c
client.h
gl_backend.c
gl_rmain.c
gl_rsurf.c
menu.c
r_explosion.c
r_lightning.c
r_shadow.c
r_sky.c
render.h

index d8766f64404a1a4f938c56c86e79d33a2d8533f8..85ad184ecc349d207c33c7fd55b6eb428eee4be5 100644 (file)
@@ -2045,9 +2045,9 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
 
                blendmode = p->type->blendmode;
 
-               cr = p->color[0] * (1.0f / 255.0f);
-               cg = p->color[1] * (1.0f / 255.0f);
-               cb = p->color[2] * (1.0f / 255.0f);
+               cr = p->color[0] * (1.0f / 255.0f) * r_view.colorscale;
+               cg = p->color[1] * (1.0f / 255.0f) * r_view.colorscale;
+               cb = p->color[2] * (1.0f / 255.0f) * r_view.colorscale;
                ca = p->alpha * (1.0f / 255.0f);
                if (blendmode == PBLEND_MOD)
                {
@@ -2077,9 +2077,9 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
                        cb = cb * ifog;
                        if (blendmode == PBLEND_ALPHA)
                        {
-                               cr += r_refdef.fogcolor[0] * fog;
-                               cg += r_refdef.fogcolor[1] * fog;
-                               cb += r_refdef.fogcolor[2] * fog;
+                               cr += r_refdef.fogcolor[0] * fog * r_view.colorscale;
+                               cg += r_refdef.fogcolor[1] * fog * r_view.colorscale;
+                               cb += r_refdef.fogcolor[2] * fog * r_view.colorscale;
                        }
                }
                c4f[0] = c4f[4] = c4f[8] = c4f[12] = cr;
index 7a9fdc7c2a12eaedca02a48f130c89da1b486b60..a35160d7f97d01bca16dc0976a6f61dde776ebdd 100644 (file)
--- a/client.h
+++ b/client.h
@@ -1265,6 +1265,9 @@ typedef struct r_view_s
 
        // which color components to allow (for anaglyph glasses)
        int colormask[4];
+
+       // global RGB color multiplier for rendering, this is required by HDR
+       float colorscale;
 }
 r_view_t;
 
index 26b608479c7136516a3100d04ccbd5187d5dc39b..348dd65567082291e4f82062f34d1f69d81dc30c 100644 (file)
@@ -727,7 +727,7 @@ void GL_TransformToScreen(const vec4_t in, vec4_t out)
        Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
        iw = 1.0f / out[3];
        out[0] = r_view.x + (out[0] * iw + 1.0f) * r_view.width * 0.5f;
-       out[1] = r_view.y + (out[1] * iw + 1.0f) * r_view.height * 0.5f;
+       out[1] = r_view.y + r_view.height - (out[1] * iw + 1.0f) * r_view.height * 0.5f;
        out[2] = r_view.z + (out[2] * iw + 1.0f) * r_view.depth * 0.5f;
 }
 
index 0cd996a46ed577e4f14b557cdaddf3d4c0d8aa3b..a566a73fd916edbb110ed75f0b362d6bdc59ec52 100644 (file)
@@ -79,6 +79,11 @@ 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_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"};
 
 cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
@@ -431,6 +436,9 @@ static const char *builtinshaderstring =
 "uniform vec3 Color_Shirt;\n"
 "uniform vec3 FogColor;\n"
 "\n"
+"uniform float GlowScale;\n"
+"uniform float SceneBrightness;\n"
+"\n"
 "uniform float OffsetMapping_Scale;\n"
 "uniform float OffsetMapping_Bias;\n"
 "uniform float FogRangeRecip;\n"
@@ -591,7 +599,7 @@ static const char *builtinshaderstring =
 "      color *= gl_Color;\n"
 "\n"
 "#ifdef USEGLOW\n"
-"      color.rgb += vec3(texture2D(Texture_Glow, TexCoord));\n"
+"      color.rgb += vec3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n"
 "#endif\n"
 "\n"
 "#ifdef USEFOG\n"
@@ -600,6 +608,8 @@ static const char *builtinshaderstring =
 "      color.rgb = color.rgb * fog + FogColor * (1.0 - fog);\n"
 "#endif\n"
 "\n"
+"      color.rgb *= SceneBrightness;\n"
+"\n"
 "      gl_FragColor = color;\n"
 "}\n"
 "\n"
@@ -727,6 +737,8 @@ void R_GLSL_CompilePermutation(int permutation)
                p->loc_DiffuseScale        = qglGetUniformLocationARB(p->program, "DiffuseScale");
                p->loc_SpecularPower       = qglGetUniformLocationARB(p->program, "SpecularPower");
                p->loc_SpecularScale       = qglGetUniformLocationARB(p->program, "SpecularScale");
+               p->loc_GlowScale           = qglGetUniformLocationARB(p->program, "GlowScale");
+               p->loc_SceneBrightness     = qglGetUniformLocationARB(p->program, "SceneBrightness");
                p->loc_OffsetMapping_Scale = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
                p->loc_AmbientColor        = qglGetUniformLocationARB(p->program, "AmbientColor");
                p->loc_DiffuseColor        = qglGetUniformLocationARB(p->program, "DiffuseColor");
@@ -873,6 +885,8 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting)
        //if (r_glsl_permutation->loc_Texture_Lightmap >= 0) R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
        //if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
        if (r_glsl_permutation->loc_Texture_Glow >= 0) R_Mesh_TexBind(9, R_GetTexture(rsurface_texture->skin.glow));
+       if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
+       if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale);
        if (r_glsl_permutation->loc_FogColor >= 0)
        {
                // additive passes are only darkened by fog, not tinted
@@ -1007,6 +1021,10 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_bloom_blur);
        Cvar_RegisterVariable(&r_bloom_resolution);
        Cvar_RegisterVariable(&r_bloom_power);
+       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);
        Cvar_RegisterVariable(&gl_lightmaps);
@@ -1332,98 +1350,122 @@ static void R_View_SetFrustum(void)
 
 void R_View_Update(void)
 {
+       R_View_SetFrustum();
+       R_View_WorldVisibility();
+       R_View_UpdateEntityVisible();
+}
+
+void R_ResetViewRendering(void)
+{
+       if (gl_support_fragment_shader)
+       {
+               qglUseProgramObjectARB(0);CHECKGLERROR
+       }
+
        // GL is weird because it's bottom to top, r_view.y is top to bottom
        qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
+       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);
-       R_View_SetFrustum();
-       R_View_WorldVisibility();
-       R_View_UpdateEntityVisible();
+       GL_ScissorTest(true);
+       GL_DepthMask(true);
+       GL_DepthTest(true);
+       R_Mesh_Matrix(&identitymatrix);
+       R_Mesh_ResetTextureState();
 }
 
-static void R_BlendView(void)
+void R_RenderScene(void);
+
+void R_Bloom_MakeTexture(qboolean darken)
 {
        int screenwidth, screenheight;
-       qboolean dobloom;
-       qboolean doblend;
+       int screentexturewidth, screentextureheight;
+       int bloomtexturewidth, bloomtextureheight;
+       int bloomwidth, bloomheight, x, range;
+       float xoffset, yoffset, r;
        float vertex3f[12];
        float texcoord2f[3][8];
 
+       // 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);
+
        // 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_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;
+       r_refdef.stats.bloom++;
 
-       if (!dobloom && !doblend)
-               return;
+       // 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);
+
+       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);
 
-       GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
-       GL_DepthMask(true);
-       GL_DepthTest(false);
-       R_Mesh_Matrix(&identitymatrix);
        // 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 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;
+
+       // 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_ResetViewRendering();
+       GL_DepthTest(false);
        R_Mesh_VertexPointer(vertex3f);
        R_Mesh_ColorPointer(NULL);
-       R_Mesh_ResetTextureState();
-       if (dobloom)
+
+       R_Mesh_TexCoordPointer(0, 2, texcoord2f[0]);
+       R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_screen));
+
+       // copy view into the screen texture
+       GL_ActiveTexture(0);
+       CHECKGLERROR
+       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;
+
+       // now scale it down to the bloom texture size
+       CHECKGLERROR
+       qglViewport(r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
+       GL_BlendFunc(GL_ONE, GL_ZERO);
+       GL_Color(1, 1, 1, 1);
+       // TODO: optimize with multitexture or GLSL
+       R_Mesh_Draw(0, 4, 2, polygonelements);
+       r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
+
+       if (darken)
        {
-               int bloomwidth, bloomheight, x, range;
-               float xoffset, yoffset, r;
-               r_refdef.stats.bloom++;
-               // allocate textures as needed
-               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);
-               // 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;
-               R_Mesh_TexCoordPointer(0, 2, texcoord2f[0]);
-               R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_screen));
-               // copy view into the full resolution screen image texture
-               GL_ActiveTexture(0);
-               CHECKGLERROR
-               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;
-               // now scale it down to the bloom size and raise to a power of itself
-               // to darken it (this leaves the really bright stuff bright, and
-               // everything else becomes very dark)
-               // TODO: optimize with multitexture or GLSL
-               CHECKGLERROR
-               qglViewport(r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
-               GL_BlendFunc(GL_ONE, GL_ZERO);
-               GL_Color(1, 1, 1, 1);
-               R_Mesh_Draw(0, 4, 2, polygonelements);
-               r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
+               // 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++)
@@ -1431,86 +1473,204 @@ static void R_BlendView(void)
                        R_Mesh_Draw(0, 4, 2, polygonelements);
                        r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
                }
-               // we now have a darkened bloom image in the framebuffer, copy it into
-               // the bloom image texture for more processing
+       }
+
+       // 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]);
+       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;
+
+       // 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;
+               GL_Color(r, r, r, 1);
+               R_Mesh_Draw(0, 4, 2, polygonelements);
+               r_refdef.stats.bloom_drawpixels += bloomwidth * 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 + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
+       r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
+
+       // 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);
+               R_Mesh_Draw(0, 4, 2, polygonelements);
+               r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
+               GL_BlendFunc(GL_ONE, GL_ONE);
+       }
+
+       // 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;
+}
+
+void R_HDR_RenderBloomTexture(void)
+{
+       int oldwidth, oldheight;
+
+       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;
+
+       // 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_RenderScene();
+
+       R_ResetViewRendering();
+
+       R_Bloom_MakeTexture(false);
+
+       R_ClearScreen();
+       if (r_timereport_active)
+               R_TimeReport("clear");
+
+       // 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)
+       {
+               // 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_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[2]);
-               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;
-               // 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;
-                       GL_Color(r, r, r, 1);
-                       R_Mesh_Draw(0, 4, 2, polygonelements);
-                       r_refdef.stats.bloom_drawpixels += bloomwidth * 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 + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
-               r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
-               // 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);
-                       R_Mesh_Draw(0, 4, 2, polygonelements);
-                       r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
-                       GL_BlendFunc(GL_ONE, GL_ONE);
-               }
-               // 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;
-               // go back to full view area
-               qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
+               R_Mesh_TexCoordPointer(0, 2, texcoord2f[1]);
+               R_Mesh_Draw(0, 4, 2, polygonelements);
+               r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
+       }
+       if (dobloom)
+       {
+               // render simple bloom effect
+               // make the bloom texture
+               R_Bloom_MakeTexture(true);
                // put the original screen image back in place and blend the bloom
                // texture on it
-               GL_Color(1,1,1,1);
+               R_ResetViewRendering();
+               GL_DepthTest(false);
+               R_Mesh_VertexPointer(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));
@@ -1536,7 +1696,10 @@ static void R_BlendView(void)
        if (doblend)
        {
                // apply a color tint to the whole view
-               R_Mesh_ResetTextureState();
+               R_ResetViewRendering();
+               GL_DepthTest(false);
+               R_Mesh_VertexPointer(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]);
                R_Mesh_Draw(0, 4, 2, polygonelements);
@@ -1639,8 +1802,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");
 
@@ -1648,10 +1809,18 @@ void R_RenderView(void)
        if (r_timereport_active)
                R_TimeReport("visibility");
 
+       // GL is weird because it's bottom to top, r_view.y is top to bottom
+       R_ResetViewRendering();
+
        R_ClearScreen();
        if (r_timereport_active)
                R_TimeReport("clear");
 
+       // this produces a bloom texture to be used in R_BlendView() later
+       if (r_hdr.integer)
+               R_HDR_RenderBloomTexture();
+
+       r_view.colorscale = r_hdr_scenebrightness.value;
        R_RenderScene();
 
        R_BlendView();
@@ -1679,6 +1848,8 @@ void CSQC_R_ClearScreen (void)
        if (r_timereport_active)
                R_TimeReport("visibility");
 
+       R_ResetViewRendering();
+
        R_ClearScreen();
        if (r_timereport_active)
                R_TimeReport("clear");
@@ -1688,6 +1859,17 @@ void CSQC_R_ClearScreen (void)
 //[515]: csqc
 void CSQC_R_RenderScene (void)
 {
+       R_ResetViewRendering();
+
+       R_ClearScreen();
+       if (r_timereport_active)
+               R_TimeReport("clear");
+
+       // this produces a bloom texture to be used in R_BlendView() later
+       if (r_hdr.integer)
+               R_HDR_RenderBloomTexture();
+
+       r_view.colorscale = r_hdr_scenebrightness.value;
        R_RenderScene();
 
        R_BlendView();
@@ -1717,6 +1899,8 @@ void R_RenderScene(void)
        qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
        qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
 
+       R_ResetViewRendering();
+
        R_MeshQueue_BeginScene();
 
        if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
@@ -2031,14 +2215,15 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_
        R_Mesh_ResetTextureState();
        R_Mesh_TexBind(0, R_GetTexture(texture));
        R_Mesh_TexCoordPointer(0, 2, spritetexcoord2f);
-       GL_Color(cr * ifog, cg * ifog, cb * ifog, ca);
+       // FIXME: fixed function path can't properly handle r_view.colorscale > 1
+       GL_Color(cr * ifog * r_view.colorscale, cg * ifog * r_view.colorscale, cb * ifog * r_view.colorscale, ca);
        R_Mesh_Draw(0, 4, 2, polygonelements);
 
        if (blendfunc2 == GL_ONE_MINUS_SRC_ALPHA)
        {
                R_Mesh_TexBind(0, R_GetTexture(fogtexture));
                GL_BlendFunc(blendfunc1, GL_ONE);
-               GL_Color(r_refdef.fogcolor[0] * fog, r_refdef.fogcolor[1] * fog, r_refdef.fogcolor[2] * fog, ca);
+               GL_Color(r_refdef.fogcolor[0] * fog * r_view.colorscale, r_refdef.fogcolor[1] * fog * r_view.colorscale, r_refdef.fogcolor[2] * fog * r_view.colorscale, ca);
                R_Mesh_Draw(0, 4, 2, polygonelements);
        }
 }
@@ -2115,7 +2300,7 @@ static void R_DrawCollisionBrush(const colbrushf_t *brush)
        int i;
        R_Mesh_VertexPointer(brush->points->v);
        i = (int)(((size_t)brush) / sizeof(colbrushf_t));
-       GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
+       GL_Color((i & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_view.colorscale, 0.2f);
        GL_LockArrays(0, brush->numpoints);
        R_Mesh_Draw(0, brush->numpoints, brush->numtriangles, brush->elements);
        GL_LockArrays(0, 0);
@@ -2128,7 +2313,7 @@ static void R_DrawCollisionSurface(const entity_render_t *ent, const msurface_t
                return;
        R_Mesh_VertexPointer(surface->data_collisionvertex3f);
        i = (int)(((size_t)surface) / sizeof(msurface_t));
-       GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
+       GL_Color((i & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_view.colorscale, 0.2f);
        GL_LockArrays(0, surface->num_collisionvertices);
        R_Mesh_Draw(0, surface->num_collisionvertices, surface->num_collisiontriangles, surface->data_collisionelement3i);
        GL_LockArrays(0, 0);
@@ -2144,9 +2329,9 @@ static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1,
        layer->blendfunc2 = blendfunc2;
        layer->texture = texture;
        layer->texmatrix = *matrix;
-       layer->color[0] = r;
-       layer->color[1] = g;
-       layer->color[2] = b;
+       layer->color[0] = r * r_view.colorscale;
+       layer->color[1] = g * r_view.colorscale;
+       layer->color[2] = b * r_view.colorscale;
        layer->color[3] = a;
 }
 
@@ -2290,7 +2475,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
                                        }
                                }
                                if (t->skin.glow != NULL)
-                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.glow, &t->currenttexmatrix, 1, 1, 1, t->currentalpha);
+                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.glow, &t->currenttexmatrix, r_hdr_glowintensity.value, r_hdr_glowintensity.value, r_hdr_glowintensity.value, t->currentalpha);
                                if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
                                {
                                        // if this is opaque use alpha blend which will darken the earlier
@@ -2603,7 +2788,7 @@ static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **te
        {
                const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
                int k = (int)(((size_t)surface) / sizeof(msurface_t));
-               GL_Color((k & 15) * (1.0f / 16.0f), ((k >> 4) & 15) * (1.0f / 16.0f), ((k >> 8) & 15) * (1.0f / 16.0f), 0.2f);
+               GL_Color((k & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_view.colorscale, 0.2f);
                GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
                R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
        }
@@ -2812,7 +2997,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **te
        // level, so don't use it then either.
        if (rsurface_model->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_viewcache.world_novis)
        {
-               GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
+               GL_Color(r_refdef.fogcolor[0] * r_view.colorscale, r_refdef.fogcolor[1] * r_view.colorscale, r_refdef.fogcolor[2] * r_view.colorscale, 1);
                R_Mesh_ColorPointer(NULL);
                R_Mesh_ResetTextureState();
                if (skyrendermasked)
@@ -3391,11 +3576,11 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
                                if (r_showtris.integer)
                                {
                                        if (!rsurface_texture->currentlayers->depthmask)
-                                               GL_Color(r_showtris.value, 0, 0, 1);
+                                               GL_Color(r_showtris.value * r_view.colorscale, 0, 0, 1);
                                        else if (ent == r_refdef.worldentity)
-                                               GL_Color(r_showtris.value, r_showtris.value, r_showtris.value, 1);
+                                               GL_Color(r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, 1);
                                        else
-                                               GL_Color(0, r_showtris.value, 0, 1);
+                                               GL_Color(0, r_showtris.value * r_view.colorscale, 0, 1);
                                        elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
                                        CHECKGLERROR
                                        qglBegin(GL_LINES);
@@ -3410,7 +3595,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
                                }
                                if (r_shownormals.integer)
                                {
-                                       GL_Color(r_shownormals.value, 0, 0, 1);
+                                       GL_Color(r_shownormals.value * r_view.colorscale, 0, 0, 1);
                                        qglBegin(GL_LINES);
                                        for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
                                        {
@@ -3421,7 +3606,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
                                        }
                                        qglEnd();
                                        CHECKGLERROR
-                                       GL_Color(0, 0, r_shownormals.value, 1);
+                                       GL_Color(0, 0, r_shownormals.value * r_view.colorscale, 1);
                                        qglBegin(GL_LINES);
                                        for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
                                        {
@@ -3432,7 +3617,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
                                        }
                                        qglEnd();
                                        CHECKGLERROR
-                                       GL_Color(0, r_shownormals.value, 0, 1);
+                                       GL_Color(0, r_shownormals.value * r_view.colorscale, 0, 1);
                                        qglBegin(GL_LINES);
                                        for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
                                        {
index 99c8b4c52e2cdaccaf13dee4ea5211f0cdb81512..117e1364669b1fa6fe5df41280adbaf34eddf93b 100644 (file)
@@ -348,9 +348,9 @@ static void R_DrawPortal_Callback(const entity_render_t *ent, const rtlight_t *r
        R_Mesh_ResetTextureState();
 
        i = surfacelist[0];
-       GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f),
-                        ((i & 0x0038) >> 3) * (1.0f / 7.0f),
-                        ((i & 0x01C0) >> 6) * (1.0f / 7.0f),
+       GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_view.colorscale,
+                        ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_view.colorscale,
+                        ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_view.colorscale,
                         0.125f);
        for (i = 0, v = vertex3f;i < numpoints;i++, v += 3)
                VectorCopy(portal->points[i].position, v);
diff --git a/menu.c b/menu.c
index 951fdeb0f38265f10987072d58dcd3230091cc3e..b3562b2b756fa1515df03072cf1181abe3a7e0df 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -1962,7 +1962,7 @@ static void M_Options_Effects_Key (int k, char ascii)
 }
 
 
-#define        OPTIONS_GRAPHICS_ITEMS  14
+#define        OPTIONS_GRAPHICS_ITEMS  18
 
 static int options_graphics_cursor;
 
@@ -1985,6 +1985,10 @@ extern cvar_t r_bloom_intensity;
 extern cvar_t r_bloom_power;
 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;
 
 static void M_Menu_Options_Graphics_AdjustSliders (int dir)
@@ -2002,10 +2006,14 @@ static void M_Menu_Options_Graphics_AdjustSliders (int dir)
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_realtime_world_lightmaps,           bound(0, r_shadow_realtime_world_lightmaps.value + dir * 0.1, 1));
        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_bloom_intensity,                       bound(1, r_bloom_intensity.value + dir * 1, 16));
+       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_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));
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&gl_picmip,                               bound(0, gl_picmip.value - dir, 3));
        else if (options_graphics_cursor == optnum++) Cbuf_AddText ("r_restart\n");
 }
@@ -2034,11 +2042,15 @@ static void M_Options_Graphics_Draw (void)
        M_Options_PrintCheckbox("RT World DLight Shadows", true, r_shadow_realtime_world_dlightshadows.integer);
        M_Options_PrintSlider(  "     RT World Lightmaps", true, r_shadow_realtime_world_lightmaps.value, 0, 1);
        M_Options_PrintCheckbox("        RT World Shadow", true, r_shadow_realtime_world_shadows.integer);
-       M_Options_PrintCheckbox("           Bloom Effect", true, r_bloom.integer);
-       M_Options_PrintSlider(  "        Bloom Intensity", true, r_bloom_intensity.value, 1, 16);
-       M_Options_PrintSlider(  "            Bloom Power", true, r_bloom_power.value, 1, 16);
-       M_Options_PrintSlider(  "             Bloom Blur", true, r_bloom_blur.value, 1, 16);
-       M_Options_PrintSlider(  "       Bloom Resolution", true, r_bloom_resolution.value, 64, 2048);
+       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 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);
        M_Options_PrintSlider(  "        Texture Quality", true, gl_picmip.value, 3, 0);
        M_Options_PrintCommand( "       Restart Renderer", true);
 }
index 6f2c36eceb41b265d0db37af50e479ebac120432..283bbe81baea01fdc848cc2fcfdf2230134a7446 100644 (file)
@@ -199,7 +199,8 @@ static void R_DrawExplosion_TransparentCallback(const entity_render_t *ent, cons
        {
                const explosion_t *e = explosion + surfacelist[surfacelistindex];
                R_Mesh_VertexPointer(e->vert[0]);
-               GL_Color(e->alpha, e->alpha, e->alpha, 1);
+               // FIXME: fixed function path can't properly handle r_view.colorscale > 1
+               GL_Color(e->alpha * r_view.colorscale, e->alpha * r_view.colorscale, e->alpha * r_view.colorscale, 1);
                GL_LockArrays(0, numverts);
                R_Mesh_Draw(0, numverts, numtriangles, explosiontris[0]);
                GL_LockArrays(0, 0);
index eabf768f2f6cc56e9a3cf235d094868d1a09748f..9fb871e11f2e31b28d5ef893fd3827b8d5062a5d 100644 (file)
@@ -246,17 +246,18 @@ void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, const r
                r_lightningbeams_setuptexture();
 
        R_Mesh_VertexPointer(vertex3f);
+       // FIXME: fixed function path can't properly handle r_view.colorscale > 1
        if (r_refdef.fogenabled)
        {
                // per vertex colors if fog is used
                R_Mesh_ColorPointer(color4f);
-               R_FogLightningBeam_Vertex3f_Color4f(vertex3f, color4f, 12, r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1);
+               R_FogLightningBeam_Vertex3f_Color4f(vertex3f, color4f, 12, r_lightningbeam_color_red.value * r_view.colorscale, r_lightningbeam_color_green.value * r_view.colorscale, r_lightningbeam_color_blue.value * r_view.colorscale, 1);
        }
        else
        {
                // solid color if fog is not used
                R_Mesh_ColorPointer(NULL);
-               GL_Color(r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1);
+               GL_Color(r_lightningbeam_color_red.value * r_view.colorscale, r_lightningbeam_color_green.value * r_view.colorscale, r_lightningbeam_color_blue.value * r_view.colorscale, 1);
        }
        memset(&m, 0, sizeof(m));
        if (r_lightningbeam_qmbtexture.integer)
@@ -271,7 +272,7 @@ void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, const r
                const beam_t *b = cl.beams + surfacelist[surfacelistindex];
                vec3_t beamdir, right, up, offset, start, end;
                float length, t1, t2;
-               
+
                CL_Beam_CalculatePositions(b, start, end);
 
                // calculate beam direction (beamdir) vector and beam length
index 791e073ef0085f89c97717c8032cbc037dd31af6..2c384f3353de43329c58d3208d2bcd8d9955ea4a 100644 (file)
@@ -962,7 +962,7 @@ void R_Shadow_RenderMode_VisibleShadowVolumes(void)
        GL_DepthMask(false);
        GL_DepthTest(!r_showdisabledepthtest.integer);
        qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
-       GL_Color(0.0, 0.0125, 0.1, 1);
+       GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
        GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
        qglDepthFunc(GL_GEQUAL);CHECKGLERROR
        qglCullFace(GL_FRONT);CHECKGLERROR // this culls back
@@ -979,7 +979,7 @@ void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transpar
        GL_DepthMask(false);
        GL_DepthTest(!r_showdisabledepthtest.integer);
        qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
-       GL_Color(0.1, 0.0125, 0, 1);
+       GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
        GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
        if (transparent)
        {
@@ -1075,6 +1075,7 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        // if that mesh is not empty, check what area of the screen it covers
        x1 = y1 = x2 = y2 = 0;
        v[3] = 1.0f;
+       //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
        for (i = 0;i < mesh.numvertices;i++)
        {
                VectorCopy(mesh.vertex3f + i * 3, v);
@@ -1112,7 +1113,7 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
                return true;
 
        // the light area is visible, set up the scissor rectangle
-       GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
+       GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
        //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
        //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
        r_refdef.stats.lights_scissored++;
@@ -1275,7 +1276,7 @@ static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurfa
 static void R_Shadow_RenderSurfacesLighting_VisibleLighting(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
 {
        // used to display how many times a surface is lit for level design purposes
-       GL_Color(0.1, 0.025, 0, 1);
+       GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
        R_Mesh_ColorPointer(NULL);
        R_Mesh_ResetTextureState();
        RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
@@ -1793,25 +1794,25 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3(int numsurfaces, msurface
        RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
        R_Mesh_ColorPointer(NULL);
        if (doambient)
-               R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
+               R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
        if (dodiffuse)
-               R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale);
+               R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
        if (dopants)
        {
                if (doambient)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
                if (dodiffuse)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
        }
        if (doshirt)
        {
                if (doambient)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
                if (dodiffuse)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
        }
        if (dospecular)
-               R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale);
+               R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
 }
 
 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
@@ -1928,12 +1929,12 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex(int numsurfaces, msurfa
        float ambientcolorpants[3], diffusecolorpants[3];
        float ambientcolorshirt[3], diffusecolorshirt[3];
        rmeshstate_t m;
-       VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2, ambientcolorbase);
-       VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2, diffusecolorbase);
-       VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2, ambientcolorpants);
-       VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2, diffusecolorpants);
-       VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2, ambientcolorshirt);
-       VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2, diffusecolorshirt);
+       VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
+       VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
+       VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
+       VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
+       VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
+       VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
        R_Mesh_ColorPointer(rsurface_array_color4f);
        memset(&m, 0, sizeof(m));
diff --git a/r_sky.c b/r_sky.c
index 487ebb5ccec6b128ddcd4a757f08726409a890b4..41b473a67243584108eb0299ae1ae93c1075b92f 100644 (file)
--- a/r_sky.c
+++ b/r_sky.c
@@ -268,7 +268,8 @@ int skyboxelements[6*2*3] =
 static void R_SkyBox(void)
 {
        int i;
-       GL_Color(1, 1, 1, 1);
+       // FIXME: fixed function path can't properly handle r_view.colorscale > 1
+       GL_Color(1 * r_view.colorscale, 1 * r_view.colorscale, 1 * r_view.colorscale, 1);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(false);
        GL_DepthTest(false); // don't modify or read zbuffer
@@ -365,7 +366,8 @@ static void R_SkySphere(void)
        speedscale -= (int)speedscale;
        Matrix4x4_CreateTranslate(&scroll2matrix, speedscale, speedscale, 0);
 
-       GL_Color(1, 1, 1, 1);
+       // FIXME: fixed function path can't properly handle r_view.colorscale > 1
+       GL_Color(1 * r_view.colorscale, 1 * r_view.colorscale, 1 * r_view.colorscale, 1);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(true);
        GL_DepthTest(false); // don't modify or read zbuffer
@@ -375,7 +377,7 @@ static void R_SkySphere(void)
        R_Mesh_TexBind(0, R_GetTexture(r_refdef.worldmodel->brush.solidskytexture));
        R_Mesh_TexCoordPointer(0, 2, skysphere_texcoord2f);
        R_Mesh_TexMatrix(0, &scroll1matrix);
-       if (r_textureunits.integer >= 2)
+       if (r_textureunits.integer >= 2 && r_view.colorscale == 1)
        {
                // one pass using GL_DECAL or GL_INTERPOLATE_ARB for alpha layer
                R_Mesh_TexBind(1, R_GetTexture(r_refdef.worldmodel->brush.alphaskytexture));
index dd0f04116a60d04d9153f66e1357925a41ac5638..66bd58b234637d9b98735c415584ccc19b7bcc94 100644 (file)
--- a/render.h
+++ b/render.h
@@ -153,6 +153,8 @@ extern cvar_t gl_dither;
 
 extern cvar_t r_smoothnormals_areaweighting;
 
+extern cvar_t r_test;
+
 #include "gl_backend.h"
 
 #include "r_light.h"
@@ -267,6 +269,8 @@ typedef struct r_glsl_permutation_s
        int loc_DiffuseScale;
        int loc_SpecularScale;
        int loc_SpecularPower;
+       int loc_GlowScale;
+       int loc_SceneBrightness;
        int loc_OffsetMapping_Scale;
        int loc_AmbientColor;
        int loc_DiffuseColor;