diff --git a/code/renderergl2/glsl/greyscale_fp.glsl b/code/renderergl2/glsl/greyscale_fp.glsl new file mode 100644 index 00000000..bddcb9d9 --- /dev/null +++ b/code/renderergl2/glsl/greyscale_fp.glsl @@ -0,0 +1,15 @@ +uniform sampler2D u_TextureMap; +uniform float u_Greyscale; +varying vec2 var_TexCoords; + +// From Rec. 709-1 4.2 "Derivation of luminance signal" +const vec3 LUMA = vec3(0.2125, 0.7154, 0.0721); + +void main() { + vec4 color = texture2D(u_TextureMap, var_TexCoords); + if (u_Greyscale > 0.0) { + float y = dot(color.rgb, LUMA); + color.rgb = mix(color.rgb, vec3(y), clamp(u_Greyscale, 0.0, 1.0)); + } + gl_FragColor = color; +} \ No newline at end of file diff --git a/code/renderergl2/glsl/greyscale_vp.glsl b/code/renderergl2/glsl/greyscale_vp.glsl new file mode 100644 index 00000000..22066540 --- /dev/null +++ b/code/renderergl2/glsl/greyscale_vp.glsl @@ -0,0 +1,11 @@ +attribute vec4 attr_Position; +attribute vec2 attr_TexCoord0; +varying vec2 var_TexCoords; + +void main() { + vec2 clipXY = (attr_Position.xy * r_FBufScale) * 2.0 - 1.0; + clipXY.y = -clipXY.y; + + gl_Position = vec4(clipXY, 0.0, 1.0); + var_TexCoords = attr_TexCoord0; +} diff --git a/code/renderergl2/tr_backend.c b/code/renderergl2/tr_backend.c index dcb379f2..03217c3b 100644 --- a/code/renderergl2/tr_backend.c +++ b/code/renderergl2/tr_backend.c @@ -394,6 +394,9 @@ void RB_BeginDrawingView (void) { // we will only draw a sun if there was sky rendered in this view backEnd.skyRenderedThisView = qfalse; + // cache the clamped greyscale value + backEnd.greyscale = Com_Clamp(0.0f, 1.0f, r_greyscale->value); + // clip to the plane of the portal if ( backEnd.viewParms.isPortal ) { #if 0 @@ -1357,6 +1360,84 @@ const void *RB_ClearDepth(const void *data) return (const void *)(cmd + 1); } +/* +============= +RB_DrawGreyscale + +============= +*/ +static void RB_DrawGreyscale(const FBO_t *src) +{ + if (!src || !src->colorImage[0]) + return; + + FBO_Bind(NULL); + qglViewport(0, 0, glConfig.vidWidth, glConfig.vidHeight); + qglScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight); + GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO); + + GLSL_BindProgram(&tr.greyscaleShader); + GLSL_SetUniformInt(&tr.greyscaleShader, UNIFORM_TEXTUREMAP, 0); + GLSL_SetUniformFloat(&tr.greyscaleShader, UNIFORM_GREYSCALE, backEnd.greyscale); + GL_BindToTMU(src->colorImage[0], 0); + + vec4_t quadVerts[4] = { + { 0.0f, 0.0f, 0.0f, 1.0f }, + { (float)glConfig.vidWidth, 0.0f, 0.0f, 1.0f }, + { (float)glConfig.vidWidth, (float)glConfig.vidHeight, 0.0f, 1.0f }, + { 0.0f, (float)glConfig.vidHeight, 0.0f, 1.0f }, + }; + + vec2_t texCoords[4] = { {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f}, {0.0f, 0.0f} }; + + RB_InstantQuad2(quadVerts, texCoords); +} + +/* +============= +RB_PresentToScreen + +============= +*/ +static void RB_PresentToScreen(void) +{ + if (!glRefConfig.framebufferObject) + return; + + const FBO_t *src = NULL; + + if (tr.renderFbo && tr.renderFbo->colorImage[0]) + { + // texture-backed render FBO + src = tr.renderFbo; + } + else if (tr.msaaResolveFbo && r_hdr->integer) + { + // Resolving an RGB16F MSAA FBO to the screen messes with the brightness, so resolve to an RGB16F FBO first + FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); + src = tr.msaaResolveFbo; + } + + if (src) + { + if (backEnd.greyscale > 0.0f) + { + RB_DrawGreyscale(src); + } + else + { + FBO_FastBlit(src, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); + } + return; + } + + if (tr.renderFbo) + { + FBO_FastBlit(tr.renderFbo, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); + } +} + + /* ============= @@ -1397,19 +1478,7 @@ const void *RB_SwapBuffers( const void *data ) { ri.Hunk_FreeTempMemory( stencilReadback ); } - if (glRefConfig.framebufferObject) - { - if (tr.msaaResolveFbo && r_hdr->integer) - { - // Resolving an RGB16F MSAA FBO to the screen messes with the brightness, so resolve to an RGB16F FBO first - FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); - FBO_FastBlit(tr.msaaResolveFbo, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - else if (tr.renderFbo) - { - FBO_FastBlit(tr.renderFbo, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - } + RB_PresentToScreen(); if ( !glState.finishCalled ) { qglFinish(); diff --git a/code/renderergl2/tr_fbo.c b/code/renderergl2/tr_fbo.c index 22516c35..4b058636 100644 --- a/code/renderergl2/tr_fbo.c +++ b/code/renderergl2/tr_fbo.c @@ -592,7 +592,7 @@ void FBO_BlitFromTexture(struct image_s *src, vec4_t inSrcTexCorners, vec2_t inS FBO_Bind(oldFbo); } -void FBO_Blit(FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend) +void FBO_Blit(const FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend) { vec4_t srcTexCorners; @@ -617,7 +617,7 @@ void FBO_Blit(FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec FBO_BlitFromTexture(src->colorImage[0], srcTexCorners, srcTexScale, dst, dstBox, shaderProgram, color, blend | GLS_DEPTHTEST_DISABLE); } -void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter) +void FBO_FastBlit(const FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter) { ivec4_t srcBoxFinal, dstBoxFinal; GLuint srcFb, dstFb; diff --git a/code/renderergl2/tr_fbo.h b/code/renderergl2/tr_fbo.h index 29d24d52..a9d6bee2 100644 --- a/code/renderergl2/tr_fbo.h +++ b/code/renderergl2/tr_fbo.h @@ -58,8 +58,8 @@ void FBO_Init(void); void FBO_Shutdown(void); void FBO_BlitFromTexture(struct image_s *src, vec4_t inSrcTexCorners, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend); -void FBO_Blit(FBO_t *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); -void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter); +void FBO_Blit(const FBO_t *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); +void FBO_FastBlit(const FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter); #endif diff --git a/code/renderergl2/tr_glsl.c b/code/renderergl2/tr_glsl.c index 39223bf6..27271f0e 100644 --- a/code/renderergl2/tr_glsl.c +++ b/code/renderergl2/tr_glsl.c @@ -52,6 +52,8 @@ extern const char *fallbackShader_texturecolor_vp; extern const char *fallbackShader_texturecolor_fp; extern const char *fallbackShader_tonemap_vp; extern const char *fallbackShader_tonemap_fp; +extern const char* fallbackShader_greyscale_vp; +extern const char* fallbackShader_greyscale_fp; typedef struct uniformInfo_s { @@ -156,6 +158,7 @@ static uniformInfo_t uniformsInfo[] = { "u_AlphaTest", GLSL_INT }, { "u_BoneMatrix", GLSL_MAT16_BONEMATRIX }, + { "u_Greyscale", GLSL_FLOAT } }; typedef enum @@ -1451,6 +1454,18 @@ void GLSL_InitGPUShaders(void) } + if (!GLSL_InitGPUShader(&tr.greyscaleShader, "greyscale", attribs, qtrue, extradefines, qtrue, + fallbackShader_greyscale_vp, fallbackShader_greyscale_fp)) + { + ri.Error(ERR_FATAL, "Unable to load greyscale shader"); + } + + GLSL_InitUniforms(&tr.greyscaleShader); + GLSL_SetUniformInt(&tr.greyscaleShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); + GLSL_FinishGPUShader(&tr.greyscaleShader); + + numEtcShaders++; + // GLSL 1.10+ or GL_OES_standard_derivatives extension are required for dFdx() and dFdy() GLSL functions if (glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 10) || glRefConfig.standardDerivatives) diff --git a/code/renderergl2/tr_image.c b/code/renderergl2/tr_image.c index be0b178e..242d98a0 100644 --- a/code/renderergl2/tr_image.c +++ b/code/renderergl2/tr_image.c @@ -1805,12 +1805,8 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picForm } else if(lightMap) { - // GL_LUMINANCE is not valid for OpenGL 3.2 Core context and - // everything becomes solid black - if(0 && r_greyscale->integer) - internalFormat = GL_LUMINANCE; - else - internalFormat = GL_RGBA; + + internalFormat = GL_RGBA; } else { @@ -1822,72 +1818,53 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picForm // select proper internal format if ( samples == 3 ) { - if(0 && r_greyscale->integer) + + if ( !forceNoCompression && (glRefConfig.textureCompression & TCR_BPTC) ) { - if(r_texturebits->integer == 16 || r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE8; - else - internalFormat = GL_LUMINANCE; + internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; + } + else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB ) + { + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + } + else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC ) + { + internalFormat = GL_RGB4_S3TC; + } + else if ( r_texturebits->integer == 16 ) + { + internalFormat = GL_RGB5; + } + else if ( r_texturebits->integer == 32 ) + { + internalFormat = GL_RGB8; } else { - if ( !forceNoCompression && (glRefConfig.textureCompression & TCR_BPTC) ) - { - internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; - } - else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB ) - { - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - } - else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC ) - { - internalFormat = GL_RGB4_S3TC; - } - else if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGB5; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGB8; - } - else - { internalFormat = GL_RGB; - } } } else if ( samples == 4 ) { - if(0 && r_greyscale->integer) + if ( !forceNoCompression && (glRefConfig.textureCompression & TCR_BPTC) ) { - if(r_texturebits->integer == 16 || r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE8_ALPHA8; - else - internalFormat = GL_LUMINANCE_ALPHA; + internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; + } + else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB ) + { + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + } + else if ( r_texturebits->integer == 16 ) + { + internalFormat = GL_RGBA4; + } + else if ( r_texturebits->integer == 32 ) + { + internalFormat = GL_RGBA8; } else { - if ( !forceNoCompression && (glRefConfig.textureCompression & TCR_BPTC) ) - { - internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; - } - else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB ) - { - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - } - else if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGBA4; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGBA8; - } - else - { internalFormat = GL_RGBA; - } } } } @@ -2129,7 +2106,6 @@ Upload32 static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, GLenum dataFormat, GLenum dataType, int numMips, image_t *image, qboolean scaled) { int i, c; - byte *scan; imgType_t type = image->type; imgFlags_t flags = image->flags; @@ -2142,30 +2118,9 @@ static void Upload32(byte *data, int x, int y, int width, int height, GLenum pic if (rgba8 && !cubemap) { c = width*height; - scan = data; if (type == IMGTYPE_COLORALPHA) { - if( r_greyscale->integer ) - { - for ( i = 0; i < c; i++ ) - { - byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = luma; - scan[i*4 + 1] = luma; - scan[i*4 + 2] = luma; - } - } - else if( r_greyscale->value ) - { - for ( i = 0; i < c; i++ ) - { - float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value); - scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value); - scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value); - } - } // This corresponds to what the OpenGL1 renderer does. if (!(flags & IMGFLAG_NOLIGHTSCALE) && (scaled || mipmap)) diff --git a/code/renderergl2/tr_local.h b/code/renderergl2/tr_local.h index 1f0c80dc..1ec1f8dd 100644 --- a/code/renderergl2/tr_local.h +++ b/code/renderergl2/tr_local.h @@ -708,6 +708,8 @@ typedef enum UNIFORM_BONEMATRIX, + UNIFORM_GREYSCALE, + UNIFORM_COUNT } uniform_t; @@ -1494,6 +1496,7 @@ typedef struct { FBO_t *last2DFBO; qboolean colorMask[4]; qboolean depthFill; + float greyscale; } backEndState_t; /* @@ -1614,6 +1617,7 @@ typedef struct { shaderProgram_t ssaoShader; shaderProgram_t depthBlurShader[4]; shaderProgram_t testcubeShader; + shaderProgram_t greyscaleShader; // ----------------------------------------- diff --git a/code/renderergl2/tr_shade.c b/code/renderergl2/tr_shade.c index 5b3de913..568d0f00 100644 --- a/code/renderergl2/tr_shade.c +++ b/code/renderergl2/tr_shade.c @@ -722,20 +722,6 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t break; } - // FIXME: find some way to implement this. -#if 0 - // if in greyscale rendering mode turn all color values into greyscale. - if(r_greyscale->integer) - { - int scale; - - for(i = 0; i < tess.numVertexes; i++) - { - scale = (tess.svars.colors[i][0] + tess.svars.colors[i][1] + tess.svars.colors[i][2]) / 3; - tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; - } - } -#endif }