- implement direct cvar linking to custom shader uniforms

This commit is contained in:
Rachael Alexanderson 2022-02-01 11:42:55 -05:00
parent 95c5449a75
commit 267e714bf1
3 changed files with 135 additions and 1 deletions

View file

@ -145,6 +145,28 @@ FBaseCVar::~FBaseCVar ()
} }
} }
void FBaseCVar::SetCallback(void *callback)
{
m_Callback = reinterpret_cast<void (__cdecl *)(FBaseCVar &)>(callback);
m_UseCallback = true;
}
void FBaseCVar::ClearCallback()
{
m_Callback = nullptr;
m_UseCallback = false;
}
void FBaseCVar::SetExtraDataPointer(void *pointer)
{
m_ExtraDataPointer = pointer;
}
void* FBaseCVar::GetExtraDataPointer()
{
return m_ExtraDataPointer;
}
const char *FBaseCVar::GetHumanString(int precision) const const char *FBaseCVar::GetHumanString(int precision) const
{ {
return GetGenericRep(CVAR_String).String; return GetGenericRep(CVAR_String).String;

View file

@ -184,6 +184,12 @@ public:
ToggleMessages[1] = on; ToggleMessages[1] = on;
} }
void SetCallback(void *callback);
void ClearCallback();
void SetExtraDataPointer(void *pointer);
void* GetExtraDataPointer();
protected: protected:
virtual void DoSet (UCVarValue value, ECVarType type) = 0; virtual void DoSet (UCVarValue value, ECVarType type) = 0;
@ -213,6 +219,8 @@ private:
static bool m_UseCallback; static bool m_UseCallback;
static bool m_DoNoSet; static bool m_DoNoSet;
void *m_ExtraDataPointer;
// These need to go away! // These need to go away!
friend FString C_GetMassCVarString (uint32_t filter, bool compact); friend FString C_GetMassCVarString (uint32_t filter, bool compact);
friend void C_SerializeCVars(FSerializer& arc, const char* label, uint32_t filter); friend void C_SerializeCVars(FSerializer& arc, const char* label, uint32_t filter);

View file

@ -58,6 +58,46 @@ extern TDeletingArray<FLightDefaults *> LightDefaults;
extern int AttenuationIsSet; extern int AttenuationIsSet;
struct ExtraUniformCVARData
{
FString Shader;
FString Uniform;
double* vec4 = nullptr;
};
static void do_uniform_set(float value, ExtraUniformCVARData* data)
{
if (!(data->vec4))
{
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
{
PostProcessShader& shader = PostProcessShaders[i];
if (strcmp(shader.Name, data->Shader) == 0)
{
data->vec4 = shader.Uniforms[data->Uniform].Values;
}
}
}
double* vec4 = data->vec4;
if (vec4)
{
vec4[0] = value;
vec4[1] = 0.0;
vec4[2] = 0.0;
vec4[3] = 1.0;
}
}
void uniform_callback_int(FIntCVar &self)
{
do_uniform_set ((float)self, (ExtraUniformCVARData*)self.GetExtraDataPointer());
}
void uniform_callback_float(FFloatCVar &self)
{
do_uniform_set ((float)self, (ExtraUniformCVARData*)self.GetExtraDataPointer());
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
// ParseVavoomSkybox // ParseVavoomSkybox
@ -1452,8 +1492,10 @@ class GLDefsParser
sc.MustGetString(); sc.MustGetString();
shaderdesc.Name = sc.String; shaderdesc.Name = sc.String;
} }
else if (sc.Compare("uniform")) else if (sc.Compare("uniform") || sc.Compare("cvar_uniform"))
{ {
bool is_cvar = sc.Compare("cvar_uniform");
sc.MustGetString(); sc.MustGetString();
FString uniformType = sc.String; FString uniformType = sc.String;
uniformType.ToLower(); uniformType.ToLower();
@ -1474,8 +1516,70 @@ class GLDefsParser
else else
sc.ScriptError("Unrecognized uniform type '%s'", sc.String); sc.ScriptError("Unrecognized uniform type '%s'", sc.String);
auto strUniformType = sc.String;
if (parsedType != PostProcessUniformType::Undefined) if (parsedType != PostProcessUniformType::Undefined)
shaderdesc.Uniforms[uniformName].Type = parsedType; shaderdesc.Uniforms[uniformName].Type = parsedType;
if (is_cvar)
{
if (!shaderdesc.Name.GetChars())
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 = NULL;
FString cvarname;
switch (parsedType)
{
case PostProcessUniformType::Int:
cvartype = CVAR_Int;
callback = uniform_callback_int;
break;
case PostProcessUniformType::Float:
cvartype = CVAR_Float;
callback = uniform_callback_float;
break;
default:
sc.ScriptError("'%s' not supported for CVAR uniforms!", strUniformType);
break;
}
sc.MustGetString();
cvarname = sc.String;
cvar = FindCVar(cvarname, NULL);
if (!cvar)
cvar = C_CreateCVar(cvarname, cvartype, cvarflags);
if (!(cvar->GetFlags() & CVAR_MOD))
{
if (!((cvar->GetFlags() & (CVAR_AUTO | CVAR_UNSETTABLE)) == (CVAR_AUTO | CVAR_UNSETTABLE)))
sc.ScriptError("CVAR '%s' already in use!", cvarname);
}
UCVarValue val;
sc.MustGetNumber();
val.Float = sc.Number;
// 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)))
{
val = cvar->GetGenericRep(CVAR_Float);
delete cvar;
cvar = C_CreateCVar(cvarname, cvartype, cvarflags);
}
shaderdesc.Uniforms[uniformName].Values[0] = sc.Number;
cvar->SetGenericRepDefault(val, CVAR_Float);
if (callback)
cvar->SetCallback(callback);
ExtraUniformCVARData* extra = new ExtraUniformCVARData;
extra->Shader = shaderdesc.Name.GetChars();
extra->Uniform = uniformName.GetChars();
cvar->SetExtraDataPointer(extra);
}
} }
else if (sc.Compare("texture")) else if (sc.Compare("texture"))
{ {