From 1cfaae78d9888b4826f06d803ef8277eee56773b Mon Sep 17 00:00:00 2001
From: Rachael Alexanderson <eruanna@drdteam.org>
Date: Sun, 2 Jul 2017 21:04:22 -0400
Subject: [PATCH 1/2] - Add new "scene" target for custom postprocess shaders -
 Add "gl_custompost" cvar to turn off custom postprocess shaders completely -
 Made "scene" affect the screen before 2D drawing, made "screen" affect the
 entire screen after 2D drawing

---
 src/gl/renderer/gl_postprocess.cpp | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp
index 89a18395f..0565bbbce 100644
--- a/src/gl/renderer/gl_postprocess.cpp
+++ b/src/gl/renderer/gl_postprocess.cpp
@@ -147,6 +147,8 @@ CUSTOM_CVAR(Bool, gl_paltonemap_reverselookup, true, CVAR_ARCHIVE | CVAR_NOINITC
 }
 
 
+CVAR(Bool, gl_custompost, true, 0)
+
 EXTERN_CVAR(Float, vid_brightness)
 EXTERN_CVAR(Float, vid_contrast)
 
@@ -175,7 +177,7 @@ void FGLRenderer::PostProcessScene(int fixedcm)
 	ColormapScene(fixedcm);
 	LensDistortScene();
 	ApplyFXAA();
-	RunCustomPostProcessShaders("screen");
+	RunCustomPostProcessShaders("scene");
 }
 
 #include "vm.h"
@@ -214,6 +216,9 @@ DEFINE_ACTION_FUNCTION(_Shader, SetUniform1i)
 
 void FGLRenderer::RunCustomPostProcessShaders(FString target)
 {
+	if (!gl_custompost)
+		return;
+
 	for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
 	{
 		PostProcessShader &shader = PostProcessShaders[i];
@@ -864,6 +869,8 @@ void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma)
 	m2DDrawer->Draw();	// draw all pending 2D stuff before copying the buffer
 	m2DDrawer->Clear();
 
+	RunCustomPostProcessShaders("screen");
+
 	FGLDebug::PushGroup("CopyToBackbuffer");
 	if (FGLRenderBuffers::IsEnabled())
 	{

From 8a0e801cb5a8e540763dad74a193dc2f429060ce Mon Sep 17 00:00:00 2001
From: Magnus Norddahl <dpjudas@users.noreply.github.com>
Date: Thu, 6 Jul 2017 05:36:01 +0200
Subject: [PATCH 2/2] - Move custom postprocess shader to its own file

---
 src/CMakeLists.txt                      |   1 +
 src/gl/renderer/gl_postprocess.cpp      | 140 +----------------------
 src/gl/renderer/gl_renderer.cpp         |   4 +
 src/gl/renderer/gl_renderer.h           |  20 +---
 src/gl/shaders/gl_postprocessshader.cpp | 145 ++++++++++++++++++++++++
 src/gl/shaders/gl_postprocessshader.h   |  48 ++++++++
 src/gl/shaders/gl_shader.cpp            |  35 +++++-
 7 files changed, 237 insertions(+), 156 deletions(-)
 create mode 100644 src/gl/shaders/gl_postprocessshader.cpp
 create mode 100644 src/gl/shaders/gl_postprocessshader.h

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c862d27e5..61b1d9530 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -979,6 +979,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 0565bbbce..da0370883 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"
 
@@ -147,20 +147,9 @@ CUSTOM_CVAR(Bool, gl_paltonemap_reverselookup, true, CVAR_ARCHIVE | CVAR_NOINITC
 }
 
 
-CVAR(Bool, gl_custompost, true, 0)
-
 EXTERN_CVAR(Float, vid_brightness)
 EXTERN_CVAR(Float, vid_contrast)
 
-class PostProcessShaderInstance
-{
-public:
-	FShaderProgram Program;
-	FBufferedUniformSampler InputTexture;
-	FBufferedUniformSampler CustomTexture;
-	FHardwareTexture *HWTexture = nullptr;
-};
-
 void FGLRenderer::RenderScreenQuad()
 {
 	mVBO->BindVBO();
@@ -172,136 +161,15 @@ void FGLRenderer::PostProcessScene(int fixedcm)
 {
 	mBuffers->BlitSceneToTexture();
 	UpdateCameraExposure();
+	mCustomPostProcessShaders->Run("beforebloom");
 	BloomScene(fixedcm);
 	TonemapScene();
 	ColormapScene(fixedcm);
 	LensDistortScene();
 	ApplyFXAA();
-	RunCustomPostProcessShaders("scene");
+	mCustomPostProcessShaders->Run("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<PostProcessShaderInstance>();
-			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<FString, float>::Iterator it1f(shader.Uniform1f);
-		TMap<FString, float>::Pair *pair1f;
-		while (it1f.NextPair(pair1f))
-		{
-			int location = glGetUniformLocation(shader.Instance->Program, pair1f->Key.GetChars());
-			if (location != -1)
-				glUniform1f(location, pair1f->Value);
-		}
-
-		TMap<FString, int>::Iterator it1i(shader.Uniform1i);
-		TMap<FString, int>::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();
-	}
-}
 
 //-----------------------------------------------------------------------------
 //
@@ -869,7 +737,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 9e75e13fc..0021c4f97 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<FString, int> Uniform1i;
-	TMap<FString, float> Uniform1f;
-
-	std::shared_ptr<PostProcessShaderInstance> Instance;
-};
-
-extern TArray<PostProcessShader> 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<PostProcessShader> PostProcessShaders;
+
+FCustomPostProcessShaders::FCustomPostProcessShaders()
+{
+	for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
+	{
+		mShaders.push_back(std::unique_ptr<PostProcessShaderInstance>(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<FString, float>::Iterator it1f(Desc->Uniform1f);
+	TMap<FString, float>::Pair *pair1f;
+	while (it1f.NextPair(pair1f))
+	{
+		int location = glGetUniformLocation(Program, pair1f->Key.GetChars());
+		if (location != -1)
+			glUniform1f(location, pair1f->Value);
+	}
+
+	TMap<FString, int>::Iterator it1i(Desc->Uniform1i);
+	TMap<FString, int>::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<FString, int> Uniform1i;
+	TMap<FString, float> Uniform1f;
+};
+
+extern TArray<PostProcessShader> 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<std::unique_ptr<PostProcessShaderInstance>> 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<PostProcessShader> 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;
+}