diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 5f523e9eb..a9aec57c6 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -55,6 +55,7 @@ #include "r_utility.h" #include "a_hexenglobal.h" #include "p_local.h" +#include "colormatcher.h" #include "gl/gl_functions.h" #include "gl/system/gl_interface.h" #include "gl/system/gl_framebuffer.h" @@ -89,7 +90,7 @@ CVAR(Float, gl_exposure, 0.0f, 0) CUSTOM_CVAR(Int, gl_tonemap, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { - if (self < 0 || self > 4) + if (self < 0 || self > 5) self = 0; } @@ -222,13 +223,61 @@ void FGLRenderer::TonemapScene() mBuffers->BindCurrentTexture(0); mTonemapShader->Bind(); mTonemapShader->SceneTexture.Set(0); - mTonemapShader->Exposure.Set(mCameraExposure); + + if (mTonemapShader->IsPaletteMode()) + { + mTonemapShader->PaletteLUT.Set(1); + BindTonemapPalette(1); + } + else + { + mTonemapShader->Exposure.Set(mCameraExposure); + } + RenderScreenQuad(); mBuffers->NextTexture(); FGLDebug::PopGroup(); } +void FGLRenderer::BindTonemapPalette(int texunit) +{ + if (mTonemapPalette) + { + mTonemapPalette->Bind(texunit, 0, false); + } + else + { + TArray lut; + lut.Resize(512 * 512 * 4); + for (int r = 0; r < 64; r++) + { + for (int g = 0; g < 64; g++) + { + for (int b = 0; b < 64; b++) + { + PalEntry color = GPalette.BaseColors[ColorMatcher.Pick((r << 2) | (r >> 1), (g << 2) | (g >> 1), (b << 2) | (b >> 1))]; + int index = ((r * 64 + g) * 64 + b) * 4; + lut[index] = color.r; + lut[index + 1] = color.g; + lut[index + 2] = color.b; + lut[index + 3] = 255; + } + } + } + + mTonemapPalette = new FHardwareTexture(512, 512, true); + mTonemapPalette->CreateTexture(&lut[0], 512, 512, texunit, false, 0, "mTonemapPalette"); + + glActiveTexture(GL_TEXTURE0 + texunit); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glActiveTexture(GL_TEXTURE0); + } +} + //----------------------------------------------------------------------------- // // Apply lens distortion and place the result in the HUD/2D texture diff --git a/src/gl/renderer/gl_postprocessstate.cpp b/src/gl/renderer/gl_postprocessstate.cpp index 058e41190..05cca7f31 100644 --- a/src/gl/renderer/gl_postprocessstate.cpp +++ b/src/gl/renderer/gl_postprocessstate.cpp @@ -62,8 +62,12 @@ FGLPostProcessState::FGLPostProcessState() glBindTexture(GL_TEXTURE_2D, 0); if (gl.flags & RFL_SAMPLER_OBJECTS) { - glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding); + glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding[0]); glBindSampler(0, 0); + glActiveTexture(GL_TEXTURE0 + 1); + glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding[1]); + glBindSampler(1, 0); + glActiveTexture(GL_TEXTURE0); } glGetBooleanv(GL_BLEND, &blendEnabled); @@ -120,7 +124,10 @@ FGLPostProcessState::~FGLPostProcessState() glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); if (gl.flags & RFL_SAMPLER_OBJECTS) - glBindSampler(0, samplerBinding); + { + glBindSampler(0, samplerBinding[0]); + glBindSampler(1, samplerBinding[1]); + } glBindTexture(GL_TEXTURE_2D, textureBinding); glActiveTexture(activeTex); } diff --git a/src/gl/renderer/gl_postprocessstate.h b/src/gl/renderer/gl_postprocessstate.h index 5cba73674..4f2ca81a1 100644 --- a/src/gl/renderer/gl_postprocessstate.h +++ b/src/gl/renderer/gl_postprocessstate.h @@ -20,7 +20,7 @@ private: GLint activeTex; GLint textureBinding; - GLint samplerBinding; + GLint samplerBinding[2]; GLboolean blendEnabled; GLboolean scissorEnabled; GLboolean depthEnabled; diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 9d2276b52..fba3a09ea 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -123,6 +123,7 @@ void FGLRenderer::Initialize(int width, int height) mBloomCombineShader = new FBloomCombineShader(); mBlurShader = new FBlurShader(); mTonemapShader = new FTonemapShader(); + mTonemapPalette = nullptr; mLensShader = new FLensShader(); mPresentShader = new FPresentShader(); m2DDrawer = new F2DDrawer; @@ -181,6 +182,7 @@ FGLRenderer::~FGLRenderer() if (mBloomCombineShader) delete mBloomCombineShader; if (mBlurShader) delete mBlurShader; if (mTonemapShader) delete mTonemapShader; + if (mTonemapPalette) delete mTonemapPalette; if (mLensShader) delete mLensShader; } diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 36654fad4..da2a11ed0 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -26,6 +26,7 @@ class FTonemapShader; class FLensShader; class FPresentShader; class F2DDrawer; +class FHardwareTexture; inline float DEG2RAD(float deg) { @@ -92,6 +93,7 @@ public: FBloomCombineShader *mBloomCombineShader; FBlurShader *mBlurShader; FTonemapShader *mTonemapShader; + FHardwareTexture *mTonemapPalette; FLensShader *mLensShader; FPresentShader *mPresentShader; @@ -164,6 +166,7 @@ public: void EndDrawScene(sector_t * viewsector); void BloomScene(); void TonemapScene(); + void BindTonemapPalette(int texunit); void LensDistortScene(); void CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma); void Flush() { CopyToBackbuffer(nullptr, true); } diff --git a/src/gl/shaders/gl_tonemapshader.cpp b/src/gl/shaders/gl_tonemapshader.cpp index 8e1f3a844..56708a694 100644 --- a/src/gl/shaders/gl_tonemapshader.cpp +++ b/src/gl/shaders/gl_tonemapshader.cpp @@ -61,10 +61,16 @@ void FTonemapShader::Bind() shader.SetAttribLocation(0, "PositionInProjection"); SceneTexture.Init(shader, "InputTexture"); Exposure.Init(shader, "ExposureAdjustment"); + PaletteLUT.Init(shader, "PaletteLUT"); } shader.Bind(); } +bool FTonemapShader::IsPaletteMode() +{ + return gl_tonemap == Palette; +} + const char *FTonemapShader::GetDefines(int mode) { switch (mode) @@ -74,5 +80,6 @@ const char *FTonemapShader::GetDefines(int mode) case Reinhard: return "#define REINHARD\n"; case HejlDawson: return "#define HEJLDAWSON\n"; case Uncharted2: return "#define UNCHARTED2\n"; + case Palette: return "#define PALETTE\n"; } } diff --git a/src/gl/shaders/gl_tonemapshader.h b/src/gl/shaders/gl_tonemapshader.h index 846fdf659..9d427713f 100644 --- a/src/gl/shaders/gl_tonemapshader.h +++ b/src/gl/shaders/gl_tonemapshader.h @@ -10,6 +10,9 @@ public: FBufferedUniform1i SceneTexture; FBufferedUniform1f Exposure; + FBufferedUniform1i PaletteLUT; + + static bool IsPaletteMode(); private: enum TonemapMode @@ -19,6 +22,7 @@ private: HejlDawson, Reinhard, Linear, + Palette, NumTonemapModes }; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 42190e5fa..1e20ebeb2 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2699,4 +2699,5 @@ OPTVAL_RIGHTEYE = "Right Eye"; OPTVAL_QUADBUFFERED = "Quad-buffered"; OPTVAL_UNCHARTED2 = "Uncharted 2"; OPTVAL_HEJLDAWSON = "Hejl Dawson"; -OPTVAL_REINHARD = "Reinhard"; \ No newline at end of file +OPTVAL_REINHARD = "Reinhard"; +OPTVAL_PALETTE = "Palette"; \ No newline at end of file diff --git a/wadsrc/static/menudef.z b/wadsrc/static/menudef.z index bd458f376..2386b1076 100644 --- a/wadsrc/static/menudef.z +++ b/wadsrc/static/menudef.z @@ -39,6 +39,7 @@ OptionValue "TonemapModes" 2, "$OPTVAL_HEJLDAWSON" 3, "$OPTVAL_REINHARD" 4, "$OPTVAL_LINEAR" + 5, "$OPTVAL_PALETTE" } OptionValue "TextureFormats" diff --git a/wadsrc/static/shaders/glsl/tonemap.fp b/wadsrc/static/shaders/glsl/tonemap.fp index 110cb6030..caf95f885 100644 --- a/wadsrc/static/shaders/glsl/tonemap.fp +++ b/wadsrc/static/shaders/glsl/tonemap.fp @@ -42,7 +42,7 @@ vec3 Tonemap(vec3 color) return (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06); // no sRGB needed } -#else +#elif defined(UNCHARTED2) vec3 Uncharted2Tonemap(vec3 x) { @@ -63,12 +63,33 @@ vec3 Tonemap(vec3 color) return sRGB(curr * whiteScale); } +#elif defined(PALETTE) + +uniform sampler2D PaletteLUT; + +vec3 Tonemap(vec3 color) +{ + ivec3 c = ivec3(clamp(color.rgb, vec3(0.0), vec3(1.0)) * 255.0 + 0.5); + int index = ((c.r >> 2) * 64 + (c.g >> 2)) * 64 + (c.b >> 2); + int tx = index % 512; + int ty = index / 512; + #if __VERSION__ < 130 + return texture2D(PaletteLUT, vec2(float(tx) / 512.0, float(ty) / 512.0))).rgb; + #else + return texelFetch(PaletteLUT, ivec2(tx, ty), 0).rgb; + #endif +} + +#else +#error "Tonemap mode define is missing" #endif void main() { vec3 color = texture(InputTexture, TexCoord).rgb; +#ifndef PALETTE color = color * ExposureAdjustment; color = Linear(color); // needed because gzdoom's scene texture is not linear at the moment +#endif FragColor = vec4(Tonemap(color), 1.0); }