diff --git a/src/common/console/c_cvars.cpp b/src/common/console/c_cvars.cpp index 1cbe6772d07..fc8c715b3b7 100644 --- a/src/common/console/c_cvars.cpp +++ b/src/common/console/c_cvars.cpp @@ -240,6 +240,16 @@ void* FBaseCVar::GetExtraDataPointer() return m_ExtraDataPointer; } +void FBaseCVar::SetExtraDataPointer2(void *pointer) +{ + m_ExtraDataPointer2 = pointer; +} + +void* FBaseCVar::GetExtraDataPointer2() +{ + return m_ExtraDataPointer2; +} + const char *FBaseCVar::GetHumanString(int precision) const { return GetGenericRep(CVAR_String).String; diff --git a/src/common/console/c_cvars.h b/src/common/console/c_cvars.h index 47337523fea..c52af0aeb8a 100644 --- a/src/common/console/c_cvars.h +++ b/src/common/console/c_cvars.h @@ -222,8 +222,10 @@ class FBaseCVar void ClearCallback(); void SetExtraDataPointer(void *pointer); + void SetExtraDataPointer2(void *pointer); void* GetExtraDataPointer(); + void* GetExtraDataPointer2(); int pnum = -1; FName userinfoName; @@ -259,7 +261,8 @@ class FBaseCVar static inline bool m_UseCallback = false; static inline bool m_DoNoSet = false; - void *m_ExtraDataPointer; + void *m_ExtraDataPointer = nullptr; + void *m_ExtraDataPointer2 = nullptr; // These need to go away! friend FString C_GetMassCVarString (uint32_t filter, bool compact); @@ -275,6 +278,8 @@ class FBaseCVar friend void FilterCompactCVars (TArray &cvars, uint32_t filter); friend void C_DeinitConsole(); friend void C_ListCVarsWithoutDescription(); + + friend class GLDefsParser; }; // Returns a string with all cvars whose flags match filter. In compact mode, diff --git a/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp b/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp index e339f926782..2a685aa3d32 100644 --- a/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp +++ b/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp @@ -947,6 +947,7 @@ PPCustomShaderInstance::PPCustomShaderInstance(PostProcessShader *desc) : Desc(d case PostProcessUniformType::Int: AddUniformField(offset, name, UniformType::Int, sizeof(int)); break; case PostProcessUniformType::Vec2: AddUniformField(offset, name, UniformType::Vec2, sizeof(float) * 2); break; case PostProcessUniformType::Vec3: AddUniformField(offset, name, UniformType::Vec3, sizeof(float) * 3, sizeof(float) * 4); break; + case PostProcessUniformType::Vec4: AddUniformField(offset, name, UniformType::Vec4, sizeof(float) * 4); break; default: break; } } @@ -1085,6 +1086,13 @@ void PPCustomShaderInstance::SetUniforms(PPRenderState *renderstate) fValues[2] = (float)pair->Value.Values[2]; memcpy(dst, fValues, sizeof(float) * 3); break; + case PostProcessUniformType::Vec4: + fValues[0] = (float)pair->Value.Values[0]; + fValues[1] = (float)pair->Value.Values[1]; + fValues[2] = (float)pair->Value.Values[2]; + fValues[3] = (float)pair->Value.Values[3]; + memcpy(dst, fValues, sizeof(float) * 4); + break; default: break; } diff --git a/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp index f23d4497f16..f48d3f7d140 100644 --- a/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp +++ b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp @@ -116,6 +116,31 @@ DEFINE_ACTION_FUNCTION(_PPShader, SetUniform3f) return 0; } +DEFINE_ACTION_FUNCTION(_PPShader, SetUniform4f) +{ + PARAM_PROLOGUE; + PARAM_STRING(shaderName); + PARAM_STRING(uniformName); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_FLOAT(w); + + 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] = w; + } + } + return 0; +} + DEFINE_ACTION_FUNCTION(_PPShader, SetUniform1i) { PARAM_PROLOGUE; diff --git a/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h index 7ecbd4f84cf..fcb32c5e1b1 100644 --- a/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h +++ b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h @@ -9,7 +9,8 @@ enum class PostProcessUniformType Int, Float, Vec2, - Vec3 + Vec3, + Vec4 }; struct PostProcessUniformValue diff --git a/src/r_data/gldefs.cpp b/src/r_data/gldefs.cpp index d92b9daf68e..6bdb4f2d516 100644 --- a/src/r_data/gldefs.cpp +++ b/src/r_data/gldefs.cpp @@ -59,17 +59,16 @@ void ParseColorization(FScanner& sc); extern TDeletingArray LightDefaults; extern int AttenuationIsSet; -bool addedcvars = false; - struct ExtraUniformCVARData { FString Shader; FString Uniform; double* vec4 = nullptr; ExtraUniformCVARData* Next = nullptr; + void (*OldCallback)(FBaseCVar &); }; -static void do_uniform_set(float value, ExtraUniformCVARData* data) +static void do_uniform_set(DVector4 value, ExtraUniformCVARData* data) { if (!(data->vec4)) { @@ -85,23 +84,33 @@ static void do_uniform_set(float value, ExtraUniformCVARData* data) double* vec4 = data->vec4; if (vec4) { - vec4[0] = value; - vec4[1] = 0.0; - vec4[2] = 0.0; - vec4[3] = 1.0; + vec4[0] = value.X; + vec4[1] = value.Y; + vec4[2] = value.Z; + vec4[3] = value.W; } if (data->Next) do_uniform_set(value, data->Next); } -void uniform_callback_int(FIntCVar &self) +template +void uniform_callback1(T &self) { - do_uniform_set ((float)self, (ExtraUniformCVARData*)self.GetExtraDataPointer()); + auto data = (ExtraUniformCVARData*)self.GetExtraDataPointer2(); + if(data->OldCallback) data->OldCallback(self); + + do_uniform_set(DVector4(*self, 0.0, 0.0, 1.0), data); } -void uniform_callback_float(FFloatCVar &self) +void uniform_callback_color(FColorCVar &self) { - do_uniform_set ((float)self, (ExtraUniformCVARData*)self.GetExtraDataPointer()); + auto data = (ExtraUniformCVARData*)self.GetExtraDataPointer2(); + if(data->OldCallback) data->OldCallback(self); + + PalEntry col; + col.d = *self; + + do_uniform_set(DVector4(col.r / 255.0, col.g / 255.0, col.b / 255.0, col.a / 255.0), data); } //----------------------------------------------------------------------------- @@ -1539,9 +1548,10 @@ class GLDefsParser sc.MustGetString(); shaderdesc.Name = sc.String; } - else if (sc.Compare("uniform") || sc.Compare("cvar_uniform")) + else if (sc.Compare("uniform")) { - bool is_cvar = sc.Compare("cvar_uniform"); + bool is_cvar = false; + bool ok = true; sc.MustGetString(); FString uniformType = sc.String; @@ -1553,104 +1563,180 @@ class GLDefsParser 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; + } + else if (uniformType.Compare("vec4") == 0) + { + parsedType = PostProcessUniformType::Vec4; + } else + { sc.ScriptError("Unrecognized uniform type '%s'", sc.String); + ok = false; + } - auto strUniformType = sc.String; - - if (parsedType != PostProcessUniformType::Undefined) - shaderdesc.Uniforms[uniformName].Type = parsedType; + double Values[4] = {0.0, 0.0, 0.0, 1.0}; - if (is_cvar) + if(ok && sc.CheckToken('=')) { - addedcvars = true; - if (shaderdesc.Name.IsEmpty()) - sc.ScriptError("Shader must have a name to use cvar uniforms"); - - ECVarType cvartype = CVAR_Dummy; - int cvarflags = CVAR_MOD|CVAR_ARCHIVE|CVAR_VIRTUAL; - FBaseCVar *cvar; - void (*callback)(FBaseCVar&) = NULL; - FString cvarname; - switch (parsedType) + if(sc.CheckString("cvar")) + { + is_cvar = true; + } + else switch(parsedType) { case PostProcessUniformType::Int: - cvartype = CVAR_Int; - callback = (void (*)(FBaseCVar&))uniform_callback_int; + sc.MustGetNumber(); + Values[0] = sc.BigNumber; break; case PostProcessUniformType::Float: - cvartype = CVAR_Float; - callback = (void (*)(FBaseCVar&))uniform_callback_float; + sc.MustGetFloat(); + Values[0] = sc.Float; break; - default: - sc.ScriptError("'%s' not supported for CVAR uniforms!", strUniformType); + case PostProcessUniformType::Vec2: + sc.MustGetFloat(); + Values[0] = sc.Float; + sc.MustGetFloat(); + Values[1] = sc.Float; break; + case PostProcessUniformType::Vec3: + sc.MustGetFloat(); + Values[0] = sc.Float; + sc.MustGetFloat(); + Values[1] = sc.Float; + sc.MustGetFloat(); + Values[2] = sc.Float; + break; + case PostProcessUniformType::Vec4: + sc.MustGetFloat(); + Values[0] = sc.Float; + sc.MustGetFloat(); + Values[1] = sc.Float; + sc.MustGetFloat(); + Values[2] = sc.Float; + sc.MustGetFloat(); + Values[3] = sc.Float; + break; + } - sc.MustGetString(); - cvarname = sc.String; - cvar = FindCVar(cvarname.GetChars(), NULL); + } - UCVarValue oldval; - UCVarValue val; - ExtraUniformCVARData* oldextra = nullptr; - sc.MustGetFloat(); - - val.Float = oldval.Float = (float)sc.Float; + if (ok && !is_cvar) + { + shaderdesc.Uniforms[uniformName].Type = parsedType; + shaderdesc.Uniforms[uniformName].Values[0] = Values[0]; + shaderdesc.Uniforms[uniformName].Values[1] = Values[1]; + shaderdesc.Uniforms[uniformName].Values[2] = Values[2]; + shaderdesc.Uniforms[uniformName].Values[3] = Values[3]; + } - if (!Args->CheckParm ("-shaderuniformtest")) - { - // these aren't really release-ready, so lock them behind a command-line argument for now. - sc.ScriptMessage("Warning - Use -shaderuniformtest to enable shader uniforms!"); - } - else + if (ok && is_cvar) + { + if (shaderdesc.Name.IsEmpty()) + sc.ScriptError("Shader must have a name to use cvar uniforms"); + + int cvarflags = CVAR_MOD|CVAR_ARCHIVE|CVAR_VIRTUAL; + FBaseCVar *cvar; + FString cvarname; + void (*callback)(FBaseCVar&) = nullptr; + + if(ok) { - if (!cvar) - { - cvar = C_CreateCVar(cvarname.GetChars(), cvartype, cvarflags); - } - else if (cvar && (((cvar->GetFlags()) & CVAR_MOD) == CVAR_MOD)) - { - // this value may have been previously loaded - oldval.Float = cvar->GetGenericRep(CVAR_Float).Float; - oldextra = (ExtraUniformCVARData*)cvar->GetExtraDataPointer(); - } + sc.MustGetString(); + cvarname = sc.String; + cvar = FindCVar(cvarname.GetChars(), NULL); - if (!(cvar->GetFlags() & CVAR_MOD)) + if (!cvar) { - if (!((cvar->GetFlags() & (CVAR_AUTO | CVAR_UNSETTABLE)) == (CVAR_AUTO | CVAR_UNSETTABLE))) - sc.ScriptError("CVAR '%s' already in use!", cvarname.GetChars()); + sc.ScriptMessage("Unknown cvar passed to cvar_uniform"); + ok = false; } + } - // must've picked this up from an autoexec.cfg, handle accordingly - if (cvar && ((cvar->GetFlags() & (CVAR_MOD|CVAR_AUTO|CVAR_UNSETTABLE)) == (CVAR_AUTO | CVAR_UNSETTABLE))) + if(ok) + { + switch (cvar->GetRealType()) { - oldval.Float = cvar->GetGenericRep(CVAR_Float).Float; - delete cvar; - cvar = C_CreateCVar(cvarname.GetChars(), cvartype, cvarflags); - oldextra = (ExtraUniformCVARData*)cvar->GetExtraDataPointer(); + case CVAR_Int: + if(parsedType != PostProcessUniformType::Int && parsedType != PostProcessUniformType::Float) + { + sc.ScriptError("CVar '%s' type (int) is not convertible to uniform type (%s), must be int or float", cvarname.GetChars(), uniformType.GetChars()); + ok = false; + } + else + { + callback = (void (*)(FBaseCVar&))(&uniform_callback1); + Values[0] = cvar->GetGenericRep(CVAR_Int).Int; + } + break; + case CVAR_Float: + if(parsedType != PostProcessUniformType::Int && parsedType != PostProcessUniformType::Float) + { + sc.ScriptError("CVar '%s' type (float) is not convertible to uniform type (%s), must be int or float", cvarname.GetChars(), uniformType.GetChars()); + ok = false; + } + else + { + callback = (void (*)(FBaseCVar&))(&uniform_callback1); + Values[0] = cvar->GetGenericRep(CVAR_Float).Float; + } + break; + case CVAR_Color: + if(parsedType != PostProcessUniformType::Vec3 && parsedType != PostProcessUniformType::Vec4) + { + sc.ScriptError("CVar '%s' type (color) is not convertible to uniform type (%s), must be vec3 or vec4", cvarname.GetChars(), uniformType.GetChars()); + ok = false; + } + else + { + callback = (void (*)(FBaseCVar&))uniform_callback_color; + + PalEntry col; + col.d = cvar->GetGenericRep(CVAR_Int).Int; + Values[0] = col.r / 255.0; + Values[1] = col.g / 255.0; + Values[2] = col.b / 255.0; + Values[3] = col.a / 255.0; + } + break; + default: + sc.ScriptError("CVar '%s' type not supported for uniforms!", cvarname.GetChars()); + ok = false; + break; } + } - shaderdesc.Uniforms[uniformName].Values[0] = oldval.Float; - - cvar->SetGenericRepDefault(val, CVAR_Float); + if(ok) + { + ExtraUniformCVARData* oldextra = (ExtraUniformCVARData*)cvar->GetExtraDataPointer2(); - if (val.Float != oldval.Float) // it's not default anymore - cvar->SetGenericRep(oldval.Float, CVAR_Float); - - if (callback) - cvar->SetCallback(callback); ExtraUniformCVARData* extra = new ExtraUniformCVARData; extra->Shader = shaderdesc.Name.GetChars(); extra->Uniform = uniformName.GetChars(); + extra->OldCallback = oldextra ? oldextra->OldCallback : cvar->m_Callback; extra->Next = oldextra; - cvar->SetExtraDataPointer(extra); + + cvar->SetCallback(callback); + cvar->SetExtraDataPointer2(extra); + + shaderdesc.Uniforms[uniformName].Type = parsedType; + shaderdesc.Uniforms[uniformName].Values[0] = Values[0]; + shaderdesc.Uniforms[uniformName].Values[1] = Values[1]; + shaderdesc.Uniforms[uniformName].Values[2] = Values[2]; + shaderdesc.Uniforms[uniformName].Values[3] = Values[3]; } } } @@ -1917,8 +2003,6 @@ class GLDefsParser sc.SavePos(); if (!sc.GetToken ()) { - if (addedcvars) - GameConfig->DoModSetup (gameinfo.ConfigName.GetChars()); return; } type = sc.MatchString(CoreKeywords); diff --git a/wadsrc/static/zscript/engine/ppshader.zs b/wadsrc/static/zscript/engine/ppshader.zs index 5c94e7e2305..db29a8c0356 100644 --- a/wadsrc/static/zscript/engine/ppshader.zs +++ b/wadsrc/static/zscript/engine/ppshader.zs @@ -4,5 +4,6 @@ struct PPShader native native clearscope static void SetUniform1f(string shaderName, string uniformName, float value); native clearscope static void SetUniform2f(string shaderName, string uniformName, vector2 value); native clearscope static void SetUniform3f(string shaderName, string uniformName, vector3 value); + native clearscope static void SetUniform4f(string shaderName, string uniformName, vector4 value); native clearscope static void SetUniform1i(string shaderName, string uniformName, int value); }