mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 21:11:39 +00:00
- Move uniform declarations to the GLDEFS lump to make it Vulkan safe (a vulkan implementation can then declare them in an uniform block)
- Change SetUniform functions to be clearscope as they can be safely called from both play and ui - Add PlayerInfo argument to SetUniform functions to force the modder to take network play into account - Add enabled flag on custom postprocess shaders - Removed custom texture support until a more clean implementation is written
This commit is contained in:
parent
8a0e801cb5
commit
a38de996e7
4 changed files with 262 additions and 71 deletions
|
@ -69,72 +69,29 @@ void FCustomPostProcessShaders::Run(FString target)
|
||||||
|
|
||||||
void PostProcessShaderInstance::Run()
|
void PostProcessShaderInstance::Run()
|
||||||
{
|
{
|
||||||
if (!Program)
|
if (!IsShaderSupported())
|
||||||
{
|
return;
|
||||||
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?
|
CompileShader();
|
||||||
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)
|
if (!Desc->Enabled)
|
||||||
{
|
return;
|
||||||
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());
|
FGLDebug::PushGroup(Desc->ShaderLumpName.GetChars());
|
||||||
|
|
||||||
FGLPostProcessState savedState;
|
FGLPostProcessState savedState;
|
||||||
savedState.SaveTextureBindings(2);
|
|
||||||
|
|
||||||
GLRenderer->mBuffers->BindNextFB();
|
GLRenderer->mBuffers->BindNextFB();
|
||||||
GLRenderer->mBuffers->BindCurrentTexture(0);
|
GLRenderer->mBuffers->BindCurrentTexture(0);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
Program.Bind();
|
mProgram.Bind();
|
||||||
|
|
||||||
TMap<FString, float>::Iterator it1f(Desc->Uniform1f);
|
UpdateUniforms();
|
||||||
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);
|
mInputTexture.Set(0);
|
||||||
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();
|
GLRenderer->RenderScreenQuad();
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
@ -143,3 +100,95 @@ void PostProcessShaderInstance::Run()
|
||||||
|
|
||||||
FGLDebug::PopGroup();
|
FGLDebug::PopGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PostProcessShaderInstance::IsShaderSupported()
|
||||||
|
{
|
||||||
|
int activeShaderVersion = (int)round(gl.glslversion * 10) * 10;
|
||||||
|
return activeShaderVersion >= Desc->ShaderVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessShaderInstance::CompileShader()
|
||||||
|
{
|
||||||
|
if (mProgram)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get the custom shader
|
||||||
|
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();
|
||||||
|
|
||||||
|
// Build an uniform block to use be used as input
|
||||||
|
// (this is technically not an uniform block, but it could be changed into that for Vulkan GLSL support)
|
||||||
|
FString uniformBlock;
|
||||||
|
TMap<FString, PostProcessUniformValue>::Iterator it(Desc->Uniforms);
|
||||||
|
TMap<FString, PostProcessUniformValue>::Pair *pair;
|
||||||
|
while (it.NextPair(pair))
|
||||||
|
{
|
||||||
|
FString type;
|
||||||
|
FString name = pair->Key;
|
||||||
|
|
||||||
|
switch (pair->Value.Type)
|
||||||
|
{
|
||||||
|
case PostProcessUniformType::Float: type = "float"; break;
|
||||||
|
case PostProcessUniformType::Int: type = "int"; break;
|
||||||
|
case PostProcessUniformType::Vec2: type = "vec2"; break;
|
||||||
|
case PostProcessUniformType::Vec3: type = "vec3"; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type.IsEmpty())
|
||||||
|
uniformBlock.AppendFormat("uniform %s %s;\n", type.GetChars(), name.GetChars());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the input textures
|
||||||
|
FString uniformTextures;
|
||||||
|
uniformTextures += "uniform sampler2D InputTexture;\n";
|
||||||
|
|
||||||
|
// Setup pipeline
|
||||||
|
FString pipelineInOut;
|
||||||
|
pipelineInOut += "in vec2 TexCoord;\n";
|
||||||
|
pipelineInOut += "out vec4 FragColor;\n";
|
||||||
|
|
||||||
|
FString prolog;
|
||||||
|
prolog += uniformBlock;
|
||||||
|
prolog += uniformTextures;
|
||||||
|
prolog += pipelineInOut;
|
||||||
|
|
||||||
|
mProgram.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", Desc->ShaderVersion);
|
||||||
|
mProgram.Compile(FShaderProgram::Fragment, lumpName, code, prolog.GetChars(), Desc->ShaderVersion);
|
||||||
|
mProgram.SetFragDataLocation(0, "FragColor");
|
||||||
|
mProgram.Link(Desc->ShaderLumpName.GetChars());
|
||||||
|
mProgram.SetAttribLocation(0, "PositionInProjection");
|
||||||
|
mInputTexture.Init(mProgram, "InputTexture");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessShaderInstance::UpdateUniforms()
|
||||||
|
{
|
||||||
|
TMap<FString, PostProcessUniformValue>::Iterator it(Desc->Uniforms);
|
||||||
|
TMap<FString, PostProcessUniformValue>::Pair *pair;
|
||||||
|
while (it.NextPair(pair))
|
||||||
|
{
|
||||||
|
int location = glGetUniformLocation(mProgram, pair->Key.GetChars());
|
||||||
|
if (location != -1)
|
||||||
|
{
|
||||||
|
switch (pair->Value.Type)
|
||||||
|
{
|
||||||
|
case PostProcessUniformType::Float:
|
||||||
|
glUniform1f(location, (float)pair->Value.Values[0]);
|
||||||
|
break;
|
||||||
|
case PostProcessUniformType::Int:
|
||||||
|
glUniform1i(location, (int)pair->Value.Values[0]);
|
||||||
|
break;
|
||||||
|
case PostProcessUniformType::Vec2:
|
||||||
|
glUniform2f(location, (float)pair->Value.Values[0], (float)pair->Value.Values[1]);
|
||||||
|
break;
|
||||||
|
case PostProcessUniformType::Vec3:
|
||||||
|
glUniform3f(location, (float)pair->Value.Values[0], (float)pair->Value.Values[1], (float)pair->Value.Values[2]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,16 +4,31 @@
|
||||||
|
|
||||||
class PostProcessShaderInstance;
|
class PostProcessShaderInstance;
|
||||||
|
|
||||||
|
enum class PostProcessUniformType
|
||||||
|
{
|
||||||
|
Undefined,
|
||||||
|
Int,
|
||||||
|
Float,
|
||||||
|
Vec2,
|
||||||
|
Vec3
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PostProcessUniformValue
|
||||||
|
{
|
||||||
|
PostProcessUniformType Type = PostProcessUniformType::Undefined;
|
||||||
|
double Values[4] = { 0.0, 0.0, 0.0, 0.0 };
|
||||||
|
};
|
||||||
|
|
||||||
struct PostProcessShader
|
struct PostProcessShader
|
||||||
{
|
{
|
||||||
FString Target;
|
FString Target;
|
||||||
FString ShaderLumpName;
|
FString ShaderLumpName;
|
||||||
int ShaderVersion = 0;
|
int ShaderVersion = 0;
|
||||||
FTexture *Texture = nullptr;
|
|
||||||
|
|
||||||
FString Name;
|
FString Name;
|
||||||
TMap<FString, int> Uniform1i;
|
bool Enabled = false;
|
||||||
TMap<FString, float> Uniform1f;
|
|
||||||
|
TMap<FString, PostProcessUniformValue> Uniforms;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern TArray<PostProcessShader> PostProcessShaders;
|
extern TArray<PostProcessShader> PostProcessShaders;
|
||||||
|
@ -26,10 +41,14 @@ public:
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
PostProcessShader *Desc;
|
PostProcessShader *Desc;
|
||||||
FShaderProgram Program;
|
|
||||||
FBufferedUniformSampler InputTexture;
|
private:
|
||||||
FBufferedUniformSampler CustomTexture;
|
bool IsShaderSupported();
|
||||||
FHardwareTexture *HWTexture = nullptr;
|
void CompileShader();
|
||||||
|
void UpdateUniforms();
|
||||||
|
|
||||||
|
FShaderProgram mProgram;
|
||||||
|
FBufferedUniformSampler mInputTexture;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FCustomPostProcessShaders
|
class FCustomPostProcessShaders
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "sc_man.h"
|
#include "sc_man.h"
|
||||||
#include "cmdlib.h"
|
#include "cmdlib.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
#include "d_player.h"
|
||||||
|
|
||||||
#include "gl/system/gl_interface.h"
|
#include "gl/system/gl_interface.h"
|
||||||
#include "gl/system/gl_debug.h"
|
#include "gl/system/gl_debug.h"
|
||||||
|
@ -698,11 +699,28 @@ void gl_ParseHardwareShader(FScanner &sc, int deflump)
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
shaderdesc.Name = sc.String;
|
shaderdesc.Name = sc.String;
|
||||||
}
|
}
|
||||||
else if (sc.Compare("texture"))
|
else if (sc.Compare("uniform"))
|
||||||
{
|
{
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
FTextureID no = TexMan.CheckForTexture(sc.String, FTexture::TEX_Wall);
|
FString uniformType = sc.String;
|
||||||
shaderdesc.Texture = TexMan[no];
|
uniformType.ToLower();
|
||||||
|
|
||||||
|
sc.MustGetString();
|
||||||
|
FString uniformName = sc.String;
|
||||||
|
|
||||||
|
PostProcessUniformType parsedType = PostProcessUniformType::Undefined;
|
||||||
|
|
||||||
|
if (uniformType.Compare("int") == 0)
|
||||||
|
parsedType = PostProcessUniformType::Int;
|
||||||
|
else if (uniformType.Compare("float") == 0)
|
||||||
|
parsedType = PostProcessUniformType::Float;
|
||||||
|
else if (uniformType.Compare("vec2") == 0)
|
||||||
|
parsedType = PostProcessUniformType::Vec2;
|
||||||
|
else if (uniformType.Compare("vec3") == 0)
|
||||||
|
parsedType = PostProcessUniformType::Vec3;
|
||||||
|
|
||||||
|
if (parsedType != PostProcessUniformType::Undefined)
|
||||||
|
shaderdesc.Uniforms[uniformName].Type = parsedType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,18 +787,110 @@ void gl_ParseHardwareShader(FScanner &sc, int deflump)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsConsolePlayer(player_t *player)
|
||||||
|
{
|
||||||
|
AActor *activator = player ? player->mo : nullptr;
|
||||||
|
if (activator == nullptr || activator->player == nullptr)
|
||||||
|
return false;
|
||||||
|
return int(activator->player - players) == consoleplayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_Shader, SetEnabled)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_POINTER_DEF(player, player_t);
|
||||||
|
PARAM_STRING(shaderName);
|
||||||
|
PARAM_BOOL_DEF(value);
|
||||||
|
|
||||||
|
if (IsConsolePlayer(player))
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
|
||||||
|
{
|
||||||
|
PostProcessShader &shader = PostProcessShaders[i];
|
||||||
|
if (shader.Name == shaderName)
|
||||||
|
shader.Enabled = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(_Shader, SetUniform1f)
|
DEFINE_ACTION_FUNCTION(_Shader, SetUniform1f)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_POINTER_DEF(player, player_t);
|
||||||
PARAM_STRING(shaderName);
|
PARAM_STRING(shaderName);
|
||||||
PARAM_STRING(uniformName);
|
PARAM_STRING(uniformName);
|
||||||
PARAM_FLOAT_DEF(value);
|
PARAM_FLOAT_DEF(value);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
|
if (IsConsolePlayer(player))
|
||||||
{
|
{
|
||||||
PostProcessShader &shader = PostProcessShaders[i];
|
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
|
||||||
if (shader.Name == shaderName)
|
{
|
||||||
shader.Uniform1f[uniformName] = value;
|
PostProcessShader &shader = PostProcessShaders[i];
|
||||||
|
if (shader.Name == shaderName)
|
||||||
|
{
|
||||||
|
double *vec4 = shader.Uniforms[uniformName].Values;
|
||||||
|
vec4[0] = value;
|
||||||
|
vec4[1] = 0.0;
|
||||||
|
vec4[2] = 0.0;
|
||||||
|
vec4[3] = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_Shader, SetUniform2f)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_POINTER_DEF(player, player_t);
|
||||||
|
PARAM_STRING(shaderName);
|
||||||
|
PARAM_STRING(uniformName);
|
||||||
|
PARAM_FLOAT_DEF(x);
|
||||||
|
PARAM_FLOAT_DEF(y);
|
||||||
|
|
||||||
|
if (IsConsolePlayer(player))
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
|
||||||
|
{
|
||||||
|
PostProcessShader &shader = PostProcessShaders[i];
|
||||||
|
if (shader.Name == shaderName)
|
||||||
|
{
|
||||||
|
double *vec4 = shader.Uniforms[uniformName].Values;
|
||||||
|
vec4[0] = x;
|
||||||
|
vec4[1] = y;
|
||||||
|
vec4[2] = 0.0;
|
||||||
|
vec4[3] = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_Shader, SetUniform3f)
|
||||||
|
{
|
||||||
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_POINTER_DEF(player, player_t);
|
||||||
|
PARAM_STRING(shaderName);
|
||||||
|
PARAM_STRING(uniformName);
|
||||||
|
PARAM_FLOAT_DEF(x);
|
||||||
|
PARAM_FLOAT_DEF(y);
|
||||||
|
PARAM_FLOAT_DEF(z);
|
||||||
|
|
||||||
|
if (IsConsolePlayer(player))
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
|
||||||
|
{
|
||||||
|
PostProcessShader &shader = PostProcessShaders[i];
|
||||||
|
if (shader.Name == shaderName)
|
||||||
|
{
|
||||||
|
double *vec4 = shader.Uniforms[uniformName].Values;
|
||||||
|
vec4[0] = x;
|
||||||
|
vec4[1] = y;
|
||||||
|
vec4[2] = z;
|
||||||
|
vec4[3] = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -788,15 +898,25 @@ DEFINE_ACTION_FUNCTION(_Shader, SetUniform1f)
|
||||||
DEFINE_ACTION_FUNCTION(_Shader, SetUniform1i)
|
DEFINE_ACTION_FUNCTION(_Shader, SetUniform1i)
|
||||||
{
|
{
|
||||||
PARAM_PROLOGUE;
|
PARAM_PROLOGUE;
|
||||||
|
PARAM_POINTER_DEF(player, player_t);
|
||||||
PARAM_STRING(shaderName);
|
PARAM_STRING(shaderName);
|
||||||
PARAM_STRING(uniformName);
|
PARAM_STRING(uniformName);
|
||||||
PARAM_INT_DEF(value);
|
PARAM_INT_DEF(value);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
|
if (IsConsolePlayer(player))
|
||||||
{
|
{
|
||||||
PostProcessShader &shader = PostProcessShaders[i];
|
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
|
||||||
if (shader.Name == shaderName)
|
{
|
||||||
shader.Uniform1i[uniformName] = value;
|
PostProcessShader &shader = PostProcessShaders[i];
|
||||||
|
if (shader.Name == shaderName)
|
||||||
|
{
|
||||||
|
double *vec4 = shader.Uniforms[uniformName].Values;
|
||||||
|
vec4[0] = (double)value;
|
||||||
|
vec4[1] = 0.0;
|
||||||
|
vec4[2] = 0.0;
|
||||||
|
vec4[3] = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -777,6 +777,9 @@ class Lighting : SectorEffect native
|
||||||
|
|
||||||
struct Shader native
|
struct Shader native
|
||||||
{
|
{
|
||||||
native static void SetUniform1f(string shaderName, string uniformName, float value);
|
native clearscope static void SetEnabled(PlayerInfo player, string shaderName, bool enable);
|
||||||
native static void SetUniform1i(string shaderName, string uniformName, int value);
|
native clearscope static void SetUniform1f(PlayerInfo player, string shaderName, string uniformName, float value);
|
||||||
|
native clearscope static void SetUniform2f(PlayerInfo player, string shaderName, string uniformName, vector2 value);
|
||||||
|
native clearscope static void SetUniform3f(PlayerInfo player, string shaderName, string uniformName, vector3 value);
|
||||||
|
native clearscope static void SetUniform1i(PlayerInfo player, string shaderName, string uniformName, int value);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue