]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
v_contrastboost: unclamp
[xonotic/darkplaces.git] / gl_rmain.c
index 3ad23498fb0dfa84d5c67573614109a46b68a0d4..9f485fe7ffad57095f3a08fd8221f6f671f51e04 100644 (file)
@@ -128,6 +128,7 @@ cvar_t r_track_sprites = {CVAR_SAVE, "r_track_sprites", "1", "track SPR_LABEL* s
 cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accodringly, 2: Make it a continuous rotation"};
 cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"};
 cvar_t r_track_sprites_scaleh = {CVAR_SAVE, "r_track_sprites_scaleh", "1", "height scaling of tracked sprites"};
+cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
 
 extern cvar_t v_glslgamma;
 
@@ -477,6 +478,9 @@ static const char *builtinshaderstring =
 "#ifdef USEGAMMARAMPS\n"
 "uniform sampler2D Texture_GammaRamps;\n"
 "#endif\n"
+"#ifdef USESATURATION\n"
+"uniform float Saturation;\n"
+"#endif\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
 "uniform vec4 TintColor;\n"
 "#endif\n"
@@ -511,6 +515,13 @@ static const char *builtinshaderstring =
 "      gl_FragColor /= (1 + 5 * UserVec1.y);\n"
 "#endif\n"
 "\n"
+"#ifdef USESATURATION\n"
+"      //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n"
+"      myhalf y = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n"
+"      //gl_FragColor = vec3(y) + (gl_FragColor.rgb - vec3(y)) * Saturation;\n"
+"      gl_FragColor.rgb = mix(vec3(y), gl_FragColor.rgb, Saturation);\n" // TODO: test this on ATI
+"#endif\n"
+"\n"
 "#ifdef USEGAMMARAMPS\n"
 "      gl_FragColor.r = texture2D(Texture_GammaRamps, vec2(gl_FragColor.r, 0)).r;\n"
 "      gl_FragColor.g = texture2D(Texture_GammaRamps, vec2(gl_FragColor.g, 0)).g;\n"
@@ -975,7 +986,7 @@ static const char *builtinshaderstring =
 "              // 0.25 supports up to 75.5 degrees normal/deluxe angle\n"
 "# ifdef USESPECULAR\n"
 "#  ifdef USEEXACTSPECULARMATH\n"
-"      tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
+"      tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(normalize(diffusenormal), surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
 "#  else\n"
 "      myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n"
 "      tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
@@ -1107,8 +1118,9 @@ typedef enum shaderpermutation_e
        SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<11, // adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
        SHADERPERMUTATION_GAMMARAMPS = 1<<12, // gamma (postprocessing only)
        SHADERPERMUTATION_POSTPROCESSING = 1<<13, // user defined postprocessing
-       SHADERPERMUTATION_LIMIT = 1<<14, // size of permutations array
-       SHADERPERMUTATION_COUNT = 14 // size of shaderpermutationinfo array
+       SHADERPERMUTATION_SATURATION = 1<<14, // user defined postprocessing
+       SHADERPERMUTATION_LIMIT = 1<<15, // size of permutations array
+       SHADERPERMUTATION_COUNT = 15 // size of shaderpermutationinfo array
 }
 shaderpermutation_t;
 
@@ -1129,6 +1141,7 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
        {"#define USEGAMMARAMPS\n", " gammaramps"},
        {"#define USEPOSTPROCESSING\n", " postprocessing"},
+       {"#define USESATURATION\n", " saturation"},
 };
 
 // this enum is multiplied by SHADERPERMUTATION_MODEBASE
@@ -1227,6 +1240,7 @@ typedef struct r_glsl_permutation_s
        int loc_UserVec4;
        int loc_ClientTime;
        int loc_PixelSize;
+       int loc_Saturation;
 }
 r_glsl_permutation_t;
 
@@ -2283,6 +2297,7 @@ void gl_main_start(void)
        r_refdef.fogmasktable_density = 0;
 }
 
+extern rtexture_t *loadingscreentexture;
 void gl_main_shutdown(void)
 {
        if (r_maxqueries)
@@ -2303,6 +2318,7 @@ void gl_main_shutdown(void)
                Mem_Free(r_svbsp.nodes);
        memset(&r_svbsp, 0, sizeof (r_svbsp));
        R_FreeTexturePool(&r_main_texturepool);
+       loadingscreentexture = NULL;
        r_texture_blanknormalmap = NULL;
        r_texture_white = NULL;
        r_texture_grey128 = NULL;
@@ -2430,6 +2446,7 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&gl_lightmaps);
        Cvar_RegisterVariable(&r_test);
        Cvar_RegisterVariable(&r_batchmode);
+       Cvar_RegisterVariable(&r_glsl_saturation);
        if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
                Cvar_SetValue("r_fullbrights", 0);
        R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
@@ -3307,7 +3324,7 @@ void R_Bloom_StartFrame(void)
                Cvar_SetValueQuick(&r_bloom, 0);
        }
 
-       if (!(r_glsl.integer && (r_glsl_postprocess.integer || (v_glslgamma.integer && !vid_gammatables_trivial) || r_bloom.integer || r_hdr.integer)) && !r_bloom.integer)
+       if (!(r_glsl.integer && (r_glsl_postprocess.integer || r_glsl_saturation.value != 1 || (v_glslgamma.integer && !vid_gammatables_trivial) || r_bloom.integer || r_hdr.integer)) && !r_bloom.integer)
                screentexturewidth = screentextureheight = 0;
        if (!r_hdr.integer && !r_bloom.integer)
                bloomtexturewidth = bloomtextureheight = 0;
@@ -3524,6 +3541,8 @@ void R_HDR_RenderBloomTexture(void)
        r_refdef.view.showdebug = false;
        r_refdef.view.colorscale *= r_bloom_colorscale.value / bound(1, r_hdr_range.value, 16);
 
+       R_ResetViewRendering3D();
+
        R_ClearScreen(r_refdef.fogenabled);
        if (r_timereport_active)
                R_TimeReport("HDRclear");
@@ -3577,7 +3596,8 @@ static void R_BlendView(void)
                          (r_bloomstate.texture_bloom ? SHADERPERMUTATION_GLOW : 0)
                        | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0)
                        | ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0)
-                       | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0);
+                       | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
+                       | (r_glsl_saturation.value != 1 ? SHADERPERMUTATION_SATURATION : 0);
 
                if (r_bloomstate.texture_bloom && !r_bloomstate.hdr)
                {
@@ -3633,6 +3653,8 @@ static void R_BlendView(void)
                        sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &a, &b, &c, &d);
                        qglUniform4fARB(r_glsl_permutation->loc_UserVec4, a, b, c, d);
                }
+               if (r_glsl_permutation->loc_Saturation >= 0)
+                       qglUniform1fARB(r_glsl_permutation->loc_Saturation, r_glsl_saturation.value);
                R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
                r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
                return;
@@ -5495,12 +5517,28 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
                        float *out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;
                        for (j = 0;j < surface->num_vertices;j++, vertex += 3, normal += 3, out_tc += 2)
                        {
-                               float l, d, eyedir[3];
-                               VectorSubtract(rsurface.modelorg, vertex, eyedir);
-                               l = 0.5f / VectorLength(eyedir);
-                               d = DotProduct(normal, eyedir)*2;
-                               out_tc[0] = 0.5f + (normal[1]*d - eyedir[1])*l;
-                               out_tc[1] = 0.5f - (normal[2]*d - eyedir[2])*l;
+                               // identical to Q3A's method, but executed in worldspace so
+                               // carried models can be shiny too
+
+                               float viewer[3], d, reflected[3], worldreflected[3];
+
+                               VectorSubtract(rsurface.modelorg, vertex, viewer);
+                               // VectorNormalize(viewer);
+
+                               d = DotProduct(normal, viewer);
+
+                               reflected[0] = normal[0]*2*d - viewer[0];
+                               reflected[1] = normal[1]*2*d - viewer[1];
+                               reflected[2] = normal[2]*2*d - viewer[2];
+                               // note: this is proportinal to viewer, so we can normalize later
+
+                               Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
+                               VectorNormalize(worldreflected);
+
+                               // note: this sphere map only uses world x and z!
+                               // so positive and negative y will LOOK THE SAME.
+                               out_tc[0] = 0.5 + 0.5 * worldreflected[1];
+                               out_tc[1] = 0.5 - 0.5 * worldreflected[2];
                        }
                }
                rsurface.texcoordtexture2f               = rsurface.array_generatedtexcoordtexture2f;
@@ -7151,6 +7189,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
        if (debug)
        {
                R_DrawDebugModel(r_refdef.scene.worldentity);
+               rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
                return;
        }
 
@@ -7175,7 +7214,10 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
                                        R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j);
        // don't do anything if there were no surfaces
        if (!numsurfacelist)
+       {
+               rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
                return;
+       }
        R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly);
        GL_AlphaTest(false);
 
@@ -7186,6 +7228,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
                for (j = 0;j < numsurfacelist;j++)
                        r_refdef.stats.world_triangles += r_surfacelist[j]->num_triangles;
        }
+       rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug)
@@ -7241,6 +7284,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        if (debug)
        {
                R_DrawDebugModel(ent);
+               rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
                return;
        }
 
@@ -7255,7 +7299,10 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
                r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
        // don't do anything if there were no surfaces
        if (!numsurfacelist)
+       {
+               rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
                return;
+       }
        // update lightmaps if needed
        if (update)
                for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
@@ -7267,9 +7314,9 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
        // add to stats if desired
        if (r_speeds.integer && !skysurfaces && !depthonly)
        {
-               r_refdef.stats.entities++;
                r_refdef.stats.entities_surfaces += numsurfacelist;
                for (j = 0;j < numsurfacelist;j++)
                        r_refdef.stats.entities_triangles += r_surfacelist[j]->num_triangles;
        }
+       rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }