From b85b510e7d6bdc6cccef88196ce69e63e96094c2 Mon Sep 17 00:00:00 2001 From: ewasylishen Date: Mon, 26 Jan 2015 20:18:45 +0000 Subject: [PATCH] New gamma correction implementation using glsl. Enabled by default on OpenGL2. Disable with -noglslgamma. Avoids general bugginess of hardware gamma, doesn't affect the whole screen in windowed mode like HW gamma. Should fix http://sourceforge.net/p/quakespasm/bugs/5/ git-svn-id: svn+ssh://svn.code.sf.net/p/quakespasm/code/trunk@1157 af15c1b1-3010-417e-b628-4374ebc0bcbd --- quakespasm/Quake/gl_rmain.c | 134 +++++++++++++++++++++++++++++++++++ quakespasm/Quake/gl_screen.c | 2 + quakespasm/Quake/gl_vidsdl.c | 35 +++++++-- quakespasm/Quake/glquake.h | 5 ++ 4 files changed, 172 insertions(+), 4 deletions(-) diff --git a/quakespasm/Quake/gl_rmain.c b/quakespasm/Quake/gl_rmain.c index cc3fbad1..e161548f 100644 --- a/quakespasm/Quake/gl_rmain.c +++ b/quakespasm/Quake/gl_rmain.c @@ -103,6 +103,140 @@ cvar_t gl_zfix = {"gl_zfix", "0", CVAR_NONE}; // QuakeSpasm z-fighting fix qboolean r_drawflat_cheatsafe, r_fullbright_cheatsafe, r_lightmap_cheatsafe, r_drawworld_cheatsafe; //johnfitz +//============================================================================== +// +// GLSL GAMMA CORRECTION +// +//============================================================================== + +static GLuint r_gamma_texture; +static GLuint r_gamma_program; + +// uniforms used in gamma shader +static GLuint gammaLoc; +static GLuint textureLoc; + +/* +============= +GLSLGamma_DeleteTexture +============= +*/ +void GLSLGamma_DeleteTexture (void) +{ + glDeleteTextures (1, &r_gamma_texture); + r_gamma_texture = 0; + r_gamma_program = 0; // deleted in R_DeleteShaders +} + +/* +============= +GLSLGamma_CreateShaders +============= +*/ +static void GLSLGamma_CreateShaders (void) +{ + const GLchar *vertSource = \ + "#version 110\n" + "\n" + "void main(void) {\n" + " gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0);\n" + " gl_TexCoord[0] = gl_MultiTexCoord0;\n" + "}\n"; + + const GLchar *fragSource = \ + "#version 110\n" + "\n" + "uniform sampler2D GammaTexture;\n" + "uniform float GammaValue;\n" + "\n" + "void main(void) {\n" + " vec4 frag = texture2D(GammaTexture, gl_TexCoord[0].xy);\n" + " gl_FragColor = vec4(pow(frag.rgb, vec3(GammaValue)), 1.0);\n" + "}\n"; + + if (!gl_glsl_gamma_able) + return; + + r_gamma_program = GL_CreateProgram (vertSource, fragSource, 0, NULL); + +// get uniform locations + gammaLoc = GL_GetUniformLocation (&r_gamma_program, "GammaValue"); + textureLoc = GL_GetUniformLocation (&r_gamma_program, "GammaTexture"); +} + +/* +============= +GLSLGamma_GammaCorrect +============= +*/ +void GLSLGamma_GammaCorrect (void) +{ + if (!gl_glsl_gamma_able) + return; + + if (vid_gamma.value == 1) + return; + +// create render-to-texture texture if needed + if (!r_gamma_texture) + { + glGenTextures (1, &r_gamma_texture); + glBindTexture (GL_TEXTURE_2D, r_gamma_texture); + + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, glwidth, glheight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + +// create shader if needed + if (!r_gamma_program) + { + GLSLGamma_CreateShaders (); + if (!r_gamma_program) + { + Sys_Error("GLSLGamma_CreateShaders failed"); + } + } + +// copy the framebuffer to the texture + GL_DisableMultitexture(); + glBindTexture (GL_TEXTURE_2D, r_gamma_texture); + glCopyTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, glx, gly, glwidth, glheight); + + glClear (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + +// draw the texture back to the framebuffer with a fragment shader + GL_UseProgramFunc (r_gamma_program); + GL_Uniform1fFunc (gammaLoc, vid_gamma.value); + GL_Uniform1iFunc (textureLoc, 0); // use texture unit 0 + + glDisable (GL_ALPHA_TEST); + glDisable (GL_DEPTH_TEST); + + glViewport (glx, gly, glwidth, glheight); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + glOrtho (0, 1, 1, 0, -99999, 99999); + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + + glBegin (GL_QUADS); + glTexCoord2f (0, 0); + glVertex2f (-1, -1); + glTexCoord2f (1, 0); + glVertex2f (1, -1); + glTexCoord2f (1, 1); + glVertex2f (1, 1); + glTexCoord2f (0, 1); + glVertex2f (-1, 1); + glEnd (); + + GL_UseProgramFunc (0); + +// clear cached binding + GL_Bind (notexture); +} + /* ================= R_CullBox -- johnfitz -- replaced with new function from lordhavoc diff --git a/quakespasm/Quake/gl_screen.c b/quakespasm/Quake/gl_screen.c index 8698ad7b..631c9144 100644 --- a/quakespasm/Quake/gl_screen.c +++ b/quakespasm/Quake/gl_screen.c @@ -1077,6 +1077,8 @@ void SCR_UpdateScreen (void) V_UpdateBlend (); //johnfitz -- V_UpdatePalette cleaned up and renamed + GLSLGamma_GammaCorrect (); + GL_EndRendering (); } diff --git a/quakespasm/Quake/gl_vidsdl.c b/quakespasm/Quake/gl_vidsdl.c index c0c7ff4e..f3df0639 100644 --- a/quakespasm/Quake/gl_vidsdl.c +++ b/quakespasm/Quake/gl_vidsdl.c @@ -102,6 +102,7 @@ qboolean gl_texture_NPOT = false; //ericw qboolean gl_vbo_able = false; //ericw qboolean gl_glsl_able = false; //ericw GLint gl_max_texture_units = 0; //ericw +qboolean gl_glsl_gamma_able = false; //ericw PFNGLMULTITEXCOORD2FARBPROC GL_MTexCoord2fFunc = NULL; //johnfitz PFNGLACTIVETEXTUREARBPROC GL_SelectTextureFunc = NULL; //johnfitz @@ -177,6 +178,9 @@ VID_Gamma_SetGamma -- apply gamma correction */ static void VID_Gamma_SetGamma (void) { + if (gl_glsl_gamma_able) + return; + if (draw_context && gammaworks) { float value; @@ -213,6 +217,9 @@ VID_Gamma_Restore -- restore system gamma */ static void VID_Gamma_Restore (void) { + if (gl_glsl_gamma_able) + return; + if (draw_context && gammaworks) { #if defined(USE_SDL2) @@ -252,6 +259,9 @@ VID_Gamma_f -- callback when the cvar changes */ static void VID_Gamma_f (cvar_t *var) { + if (gl_glsl_gamma_able) + return; + #if USE_GAMMA_RAMPS int i; @@ -273,6 +283,12 @@ VID_Gamma_Init -- call on init */ static void VID_Gamma_Init (void) { + Cvar_RegisterVariable (&vid_gamma); + Cvar_SetCallback (&vid_gamma, VID_Gamma_f); + + if (gl_glsl_gamma_able) + return; + #if defined(USE_SDL2) # if USE_GAMMA_RAMPS gammaworks = (SDL_GetWindowGammaRamp(draw_context, vid_sysgamma_red, vid_sysgamma_green, vid_sysgamma_blue) == 0); @@ -293,9 +309,6 @@ static void VID_Gamma_Init (void) if (!gammaworks) Con_SafePrintf("gamma adjustment not available\n"); - - Cvar_RegisterVariable (&vid_gamma); - Cvar_SetCallback (&vid_gamma, VID_Gamma_f); } /* @@ -683,6 +696,8 @@ static void VID_Restart (void) // memory leak. TexMgr_DeleteTextureObjects (); + GLSLGamma_DeleteTexture (); + R_DeleteShaders (); // // set new mode @@ -1096,6 +1111,19 @@ static void GL_CheckExtensions (void) { Con_Warning ("OpenGL version < 2, GLSL not available\n"); } + + // GLSL gamma + // + if (COM_CheckParm("-noglslgamma")) + Con_Warning ("GLSL gamma disabled at command line\n"); + else if (gl_glsl_able && gl_texture_NPOT) + { + gl_glsl_gamma_able = true; + } + else + { + Con_Warning ("GLSL gamma not available, using hardware gamma\n"); + } } /* @@ -1168,7 +1196,6 @@ static void GL_Init (void) } //johnfitz - R_DeleteShaders (); GLAlias_CreateShaders (); GL_ClearBufferBindings (); } diff --git a/quakespasm/Quake/glquake.h b/quakespasm/Quake/glquake.h index e9394d10..b35d79c9 100644 --- a/quakespasm/Quake/glquake.h +++ b/quakespasm/Quake/glquake.h @@ -222,6 +222,7 @@ extern QS_PFNGLUNIFORM1FPROC GL_Uniform1fFunc; extern QS_PFNGLUNIFORM3FPROC GL_Uniform3fFunc; extern QS_PFNGLUNIFORM4FPROC GL_Uniform4fFunc; extern qboolean gl_glsl_able; +extern qboolean gl_glsl_gamma_able; // ericw -- //ericw -- NPOT texture support @@ -376,5 +377,9 @@ void R_DrawWorld_Water (void); void GL_BindBuffer (GLenum target, GLuint buffer); void GL_ClearBufferBindings (); + +void GLSLGamma_DeleteTexture (void); +void GLSLGamma_GammaCorrect (void); + #endif /* __GLQUAKE_H */