diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5a034fc1a..adc49495b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1031,6 +1031,7 @@ set (PCH_SOURCES gl/shaders/gl_shader.cpp gl/shaders/gl_texshader.cpp gl/shaders/gl_shaderprogram.cpp + gl/shaders/gl_postprocessshader.cpp gl/shaders/gl_shadowmapshader.cpp gl/shaders/gl_presentshader.cpp gl/shaders/gl_present3dRowshader.cpp diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 7d44b9e25..2659b41f8 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -42,7 +42,6 @@ #include "r_utility.h" #include "p_local.h" #include "colormatcher.h" -#include "w_wad.h" #include "gl/gl_functions.h" #include "gl/system/gl_interface.h" #include "gl/system/gl_framebuffer.h" @@ -63,6 +62,7 @@ #include "gl/shaders/gl_lensshader.h" #include "gl/shaders/gl_fxaashader.h" #include "gl/shaders/gl_presentshader.h" +#include "gl/shaders/gl_postprocessshader.h" #include "gl/renderer/gl_2ddrawer.h" #include "gl/stereo3d/gl_stereo3d.h" @@ -155,15 +155,6 @@ EXTERN_CVAR(Float, vid_contrast) EXTERN_CVAR(Float, vid_saturation) EXTERN_CVAR(Int, gl_satformula) -class PostProcessShaderInstance -{ -public: - FShaderProgram Program; - FBufferedUniformSampler InputTexture; - FBufferedUniformSampler CustomTexture; - FHardwareTexture *HWTexture = nullptr; -}; - void FGLRenderer::RenderScreenQuad() { mVBO->BindVBO(); @@ -175,135 +166,13 @@ void FGLRenderer::PostProcessScene(int fixedcm) { mBuffers->BlitSceneToTexture(); UpdateCameraExposure(); + mCustomPostProcessShaders->Run("beforebloom"); BloomScene(fixedcm); TonemapScene(); ColormapScene(fixedcm); LensDistortScene(); ApplyFXAA(); - RunCustomPostProcessShaders("scene"); -} - -#include "vm.h" - -DEFINE_ACTION_FUNCTION(_Shader, SetUniform1f) -{ - PARAM_PROLOGUE; - PARAM_STRING(shaderName); - PARAM_STRING(uniformName); - PARAM_FLOAT_DEF(value); - - for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) - { - PostProcessShader &shader = PostProcessShaders[i]; - if (shader.Name == shaderName) - shader.Uniform1f[uniformName] = value; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(_Shader, SetUniform1i) -{ - PARAM_PROLOGUE; - PARAM_STRING(shaderName); - PARAM_STRING(uniformName); - PARAM_INT_DEF(value); - - for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) - { - PostProcessShader &shader = PostProcessShaders[i]; - if (shader.Name == shaderName) - shader.Uniform1i[uniformName] = value; - } - return 0; -} - -void FGLRenderer::RunCustomPostProcessShaders(FString target) -{ - if (!gl_custompost) - return; - - for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) - { - PostProcessShader &shader = PostProcessShaders[i]; - - if (shader.Target != target) - continue; - - if (!shader.Instance) - { - const char *lumpName = shader.ShaderLumpName.GetChars(); - int lump = Wads.CheckNumForFullName(lumpName); - if (lump == -1) I_FatalError("Unable to load '%s'", lumpName); - FString code = Wads.ReadLump(lump).GetString().GetChars(); - - shader.Instance = std::make_shared(); - shader.Instance->Program.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); // Hmm, should this use shader.shaderversion? - shader.Instance->Program.Compile(FShaderProgram::Fragment, lumpName, code, "", shader.ShaderVersion); - shader.Instance->Program.SetFragDataLocation(0, "FragColor"); - shader.Instance->Program.Link(shader.ShaderLumpName.GetChars()); - shader.Instance->Program.SetAttribLocation(0, "PositionInProjection"); - shader.Instance->InputTexture.Init(shader.Instance->Program, "InputTexture"); - shader.Instance->CustomTexture.Init(shader.Instance->Program, "CustomTexture"); - - if (shader.Texture) - { - shader.Instance->HWTexture = new FHardwareTexture(shader.Texture->GetWidth(), shader.Texture->GetHeight(), false); - shader.Instance->HWTexture->CreateTexture((unsigned char*)shader.Texture->GetPixelsBgra(), shader.Texture->GetWidth(), shader.Texture->GetHeight(), 0, false, 0, "CustomTexture"); - } - } - - FGLDebug::PushGroup(shader.ShaderLumpName.GetChars()); - - FGLPostProcessState savedState; - savedState.SaveTextureBindings(2); - - mBuffers->BindNextFB(); - mBuffers->BindCurrentTexture(0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - shader.Instance->Program.Bind(); - - TMap::Iterator it1f(shader.Uniform1f); - TMap::Pair *pair1f; - while (it1f.NextPair(pair1f)) - { - int location = glGetUniformLocation(shader.Instance->Program, pair1f->Key.GetChars()); - if (location != -1) - glUniform1f(location, pair1f->Value); - } - - TMap::Iterator it1i(shader.Uniform1i); - TMap::Pair *pair1i; - while (it1i.NextPair(pair1i)) - { - int location = glGetUniformLocation(shader.Instance->Program, pair1i->Key.GetChars()); - if (location != -1) - glUniform1i(location, pair1i->Value); - } - - shader.Instance->InputTexture.Set(0); - - if (shader.Instance->HWTexture) - { - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, shader.Instance->HWTexture->GetTextureHandle(0)); - 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); - - shader.Instance->CustomTexture.Set(1); - } - RenderScreenQuad(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - mBuffers->NextTexture(); - - FGLDebug::PopGroup(); - } + mCustomPostProcessShaders->Run("scene"); } //----------------------------------------------------------------------------- @@ -952,7 +821,7 @@ void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma) m2DDrawer->Draw(); // draw all pending 2D stuff before copying the buffer m2DDrawer->Clear(); - RunCustomPostProcessShaders("screen"); + mCustomPostProcessShaders->Run("screen"); FGLDebug::PushGroup("CopyToBackbuffer"); if (FGLRenderBuffers::IsEnabled()) diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 77d8d6bc3..bac55edb8 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -62,6 +62,7 @@ #include "gl/shaders/gl_presentshader.h" #include "gl/shaders/gl_present3dRowshader.h" #include "gl/shaders/gl_shadowmapshader.h" +#include "gl/shaders/gl_postprocessshader.h" #include "gl/stereo3d/gl_stereo3d.h" #include "gl/textures/gl_texture.h" #include "gl/textures/gl_translate.h" @@ -128,6 +129,7 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mFXAAShader = nullptr; mFXAALumaShader = nullptr; mShadowMapShader = nullptr; + mCustomPostProcessShaders = nullptr; } void gl_LoadModels(); @@ -157,6 +159,7 @@ void FGLRenderer::Initialize(int width, int height) mPresent3dColumnShader = new FPresent3DColumnShader(); mPresent3dRowShader = new FPresent3DRowShader(); mShadowMapShader = new FShadowMapShader(); + mCustomPostProcessShaders = new FCustomPostProcessShaders(); m2DDrawer = new F2DDrawer; // needed for the core profile, because someone decided it was a good idea to remove the default VAO. @@ -232,6 +235,7 @@ FGLRenderer::~FGLRenderer() if (mColormapShader) delete mColormapShader; if (mLensShader) delete mLensShader; if (mShadowMapShader) delete mShadowMapShader; + delete mCustomPostProcessShaders; delete mFXAAShader; delete mFXAALumaShader; } diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index ad8dd5a10..27263f62c 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -42,7 +42,7 @@ class FPresent3DRowShader; class F2DDrawer; class FHardwareTexture; class FShadowMapShader; -class PostProcessShaderInstance; +class FCustomPostProcessShaders; inline float DEG2RAD(float deg) { @@ -86,22 +86,6 @@ enum DM_SKYPORTAL }; -struct PostProcessShader -{ - FString Target; - FString ShaderLumpName; - int ShaderVersion = 0; - FTexture *Texture = nullptr; - - FString Name; - TMap Uniform1i; - TMap Uniform1f; - - std::shared_ptr Instance; -}; - -extern TArray PostProcessShaders; - class FGLRenderer { public: @@ -143,6 +127,7 @@ public: FPresent3DColumnShader *mPresent3dColumnShader; FPresent3DRowShader *mPresent3dRowShader; FShadowMapShader *mShadowMapShader; + FCustomPostProcessShaders *mCustomPostProcessShaders; FShadowMap mShadowMap; @@ -188,7 +173,6 @@ public: void RenderScreenQuad(); void PostProcessScene(int fixedcm); - void RunCustomPostProcessShaders(FString target); void AmbientOccludeScene(); void UpdateCameraExposure(); void BloomScene(int fixedcm); diff --git a/src/gl/shaders/gl_postprocessshader.cpp b/src/gl/shaders/gl_postprocessshader.cpp new file mode 100644 index 000000000..1bd7bc394 --- /dev/null +++ b/src/gl/shaders/gl_postprocessshader.cpp @@ -0,0 +1,145 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2017 Magnus Norddahl +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#include "gl/system/gl_system.h" +#include "m_swap.h" +#include "v_video.h" +#include "gl/gl_functions.h" +#include "vectors.h" +#include "w_wad.h" +#include "gl/system/gl_interface.h" +#include "gl/system/gl_framebuffer.h" +#include "gl/system/gl_debug.h" +#include "gl/system/gl_cvars.h" +#include "gl/renderer/gl_renderer.h" +#include "gl/renderer/gl_postprocessstate.h" +#include "gl/renderer/gl_renderbuffers.h" +#include "gl/shaders/gl_postprocessshader.h" + +CVAR(Bool, gl_custompost, true, 0) + +TArray PostProcessShaders; + +FCustomPostProcessShaders::FCustomPostProcessShaders() +{ + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + mShaders.push_back(std::unique_ptr(new PostProcessShaderInstance(&PostProcessShaders[i]))); + } +} + +FCustomPostProcessShaders::~FCustomPostProcessShaders() +{ +} + +void FCustomPostProcessShaders::Run(FString target) +{ + if (!gl_custompost) + return; + + for (auto &shader : mShaders) + { + if (shader->Desc->Target == target) + { + shader->Run(); + } + } +} + +///////////////////////////////////////////////////////////////////////////// + +void PostProcessShaderInstance::Run() +{ + if (!Program) + { + const char *lumpName = Desc->ShaderLumpName.GetChars(); + int lump = Wads.CheckNumForFullName(lumpName); + if (lump == -1) I_FatalError("Unable to load '%s'", lumpName); + FString code = Wads.ReadLump(lump).GetString().GetChars(); + + Program.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); // Hmm, should this use shader.shaderversion? + Program.Compile(FShaderProgram::Fragment, lumpName, code, "", Desc->ShaderVersion); + Program.SetFragDataLocation(0, "FragColor"); + Program.Link(Desc->ShaderLumpName.GetChars()); + Program.SetAttribLocation(0, "PositionInProjection"); + InputTexture.Init(Program, "InputTexture"); + CustomTexture.Init(Program, "CustomTexture"); + + if (Desc->Texture) + { + HWTexture = new FHardwareTexture(Desc->Texture->GetWidth(), Desc->Texture->GetHeight(), false); + HWTexture->CreateTexture((unsigned char*)Desc->Texture->GetPixelsBgra(), Desc->Texture->GetWidth(), Desc->Texture->GetHeight(), 0, false, 0, "CustomTexture"); + } + } + + FGLDebug::PushGroup(Desc->ShaderLumpName.GetChars()); + + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); + + GLRenderer->mBuffers->BindNextFB(); + GLRenderer->mBuffers->BindCurrentTexture(0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + Program.Bind(); + + TMap::Iterator it1f(Desc->Uniform1f); + TMap::Pair *pair1f; + while (it1f.NextPair(pair1f)) + { + int location = glGetUniformLocation(Program, pair1f->Key.GetChars()); + if (location != -1) + glUniform1f(location, pair1f->Value); + } + + TMap::Iterator it1i(Desc->Uniform1i); + TMap::Pair *pair1i; + while (it1i.NextPair(pair1i)) + { + int location = glGetUniformLocation(Program, pair1i->Key.GetChars()); + if (location != -1) + glUniform1i(location, pair1i->Value); + } + + InputTexture.Set(0); + + if (HWTexture) + { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, HWTexture->GetTextureHandle(0)); + 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); + + CustomTexture.Set(1); + } + GLRenderer->RenderScreenQuad(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + GLRenderer->mBuffers->NextTexture(); + + FGLDebug::PopGroup(); +} diff --git a/src/gl/shaders/gl_postprocessshader.h b/src/gl/shaders/gl_postprocessshader.h new file mode 100644 index 000000000..171b43945 --- /dev/null +++ b/src/gl/shaders/gl_postprocessshader.h @@ -0,0 +1,48 @@ +#pragma once + +#include "gl_shaderprogram.h" + +class PostProcessShaderInstance; + +struct PostProcessShader +{ + FString Target; + FString ShaderLumpName; + int ShaderVersion = 0; + FTexture *Texture = nullptr; + + FString Name; + TMap Uniform1i; + TMap Uniform1f; +}; + +extern TArray PostProcessShaders; + +class PostProcessShaderInstance +{ +public: + PostProcessShaderInstance(PostProcessShader *desc) : Desc(desc) { } + + void Run(); + + PostProcessShader *Desc; + FShaderProgram Program; + FBufferedUniformSampler InputTexture; + FBufferedUniformSampler CustomTexture; + FHardwareTexture *HWTexture = nullptr; +}; + +class FCustomPostProcessShaders +{ +public: + FCustomPostProcessShaders(); + ~FCustomPostProcessShaders(); + + void Run(FString target); + +private: + std::vector> mShaders; + + FCustomPostProcessShaders(const FCustomPostProcessShaders &) = delete; + FCustomPostProcessShaders &operator=(const FCustomPostProcessShaders &) = delete; +}; diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index ba4c2874c..e153dc653 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -36,6 +36,7 @@ #include "v_palette.h" #include "sc_man.h" #include "cmdlib.h" +#include "vm.h" #include "gl/system/gl_interface.h" #include "gl/system/gl_debug.h" @@ -46,6 +47,7 @@ #include "gl/system/gl_cvars.h" #include "gl/shaders/gl_shader.h" #include "gl/shaders/gl_shaderprogram.h" +#include "gl/shaders/gl_postprocessshader.h" #include "gl/textures/gl_material.h" #include "gl/dynlights/gl_lightbuffer.h" @@ -669,8 +671,6 @@ void gl_DestroyUserShaders() // //========================================================================== -TArray PostProcessShaders; - void gl_ParseHardwareShader(FScanner &sc, int deflump) { sc.MustGetString(); @@ -769,3 +769,34 @@ void gl_ParseHardwareShader(FScanner &sc, int deflump) } } +DEFINE_ACTION_FUNCTION(_Shader, SetUniform1f) +{ + PARAM_PROLOGUE; + PARAM_STRING(shaderName); + PARAM_STRING(uniformName); + PARAM_FLOAT_DEF(value); + + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + if (shader.Name == shaderName) + shader.Uniform1f[uniformName] = value; + } + return 0; +} + +DEFINE_ACTION_FUNCTION(_Shader, SetUniform1i) +{ + PARAM_PROLOGUE; + PARAM_STRING(shaderName); + PARAM_STRING(uniformName); + PARAM_INT_DEF(value); + + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + if (shader.Name == shaderName) + shader.Uniform1i[uniformName] = value; + } + return 0; +}