implement global shaders

This commit is contained in:
Ricardo Luís Vaz Silva 2025-01-06 13:30:42 -03:00 committed by Nash Muhandes
commit 3a31008aa8
8 changed files with 484 additions and 202 deletions

View file

@ -158,3 +158,5 @@ CUSTOM_CVAR(Int, gl_shadowmap_quality, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
break;
}
}
CVAR(Bool, gl_strict_gldefs, true, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)

View file

@ -58,3 +58,5 @@ EXTERN_CVAR(Bool, gl_notexturefill)
EXTERN_CVAR(Bool, r_radarclipper)
EXTERN_CVAR(Bool, r_dithertransparency)
EXTERN_CVAR(Bool, gl_strict_gldefs)

View file

@ -131,21 +131,21 @@ VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key)
// Note: the MaterialShaderIndex enum needs to be updated whenever this array is modified.
static const FDefaultShader defaultshaders[] =
{
{"Default", "shaders/scene/material_default.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", ""},
{"Warp 1", "shaders/scene/material_default.glsl", "shaders/scene/mateffect_warp1.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", ""},
{"Warp 2", "shaders/scene/material_default.glsl", "shaders/scene/mateffect_warp2.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", ""},
{"Specular", "shaders/scene/material_spec.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_specular.glsl", "#define SPECULAR\n#define NORMALMAP\n"},
{"PBR", "shaders/scene/material_pbr.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_pbr.glsl", "#define PBR\n#define NORMALMAP\n"},
{"Paletted", "shaders/scene/material_paletted.glsl", "shaders/scene/mateffect_default.glsl", nullptr, "shaders/scene/lightmodel_nolights.glsl", "#define PALETTE_EMULATION\n"},
{"No Texture", "shaders/scene/material_notexture.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define NO_LAYERS\n"},
{"Basic Fuzz", "shaders/scene/material_fuzz_standard.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", ""},
{"Smooth Fuzz", "shaders/scene/material_fuzz_smooth.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", ""},
{"Swirly Fuzz", "shaders/scene/material_fuzz_swirly.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", ""},
{"Translucent Fuzz", "shaders/scene/material_fuzz_smoothtranslucent.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", ""},
{"Jagged Fuzz", "shaders/scene/material_fuzz_jagged.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", ""},
{"Noise Fuzz", "shaders/scene/material_fuzz_noise.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", ""},
{"Smooth Noise Fuzz", "shaders/scene/material_fuzz_smoothnoise.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", ""},
{"Software Fuzz", "shaders/scene/material_fuzz_software.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", ""},
{"Default", "shaders/scene/material_default.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_DEFAULT\n"},
{"Warp 1", "shaders/scene/material_default.glsl", "shaders/scene/mateffect_warp1.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_WARP1\n"},
{"Warp 2", "shaders/scene/material_default.glsl", "shaders/scene/mateffect_warp2.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_WARP2\n"},
{"Specular", "shaders/scene/material_spec.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_specular.glsl", "#define SHADERTYPE_SPECULAR\n#define SPECULAR\n#define NORMALMAP\n"},
{"PBR", "shaders/scene/material_pbr.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_pbr.glsl", "#define SHADERTYPE_PBR\n#define PBR\n#define NORMALMAP\n"},
{"Paletted", "shaders/scene/material_paletted.glsl", "shaders/scene/mateffect_default.glsl", nullptr, "shaders/scene/lightmodel_nolights.glsl", "#define SHADERTYPE_PALETTE\n#define PALETTE_EMULATION\n"},
{"No Texture", "shaders/scene/material_notexture.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_NOTEXTURE\n#define NO_LAYERS\n"},
{"Basic Fuzz", "shaders/scene/material_fuzz_standard.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_FUZZ\n#define SHADERTYPE_FUZZ_BASIC\n"},
{"Smooth Fuzz", "shaders/scene/material_fuzz_smooth.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_FUZZ\n#define SHADERTYPE_FUZZ_SMOOTH\n"},
{"Swirly Fuzz", "shaders/scene/material_fuzz_swirly.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_FUZZ\n#define SHADERTYPE_FUZZ_SWIRLY\n"},
{"Translucent Fuzz", "shaders/scene/material_fuzz_smoothtranslucent.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_FUZZ\n#define SHADERTYPE_FUZZ_TRANSLUCENT\n"},
{"Jagged Fuzz", "shaders/scene/material_fuzz_jagged.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_FUZZ\n#define SHADERTYPE_FUZZ_JAGGED\n"},
{"Noise Fuzz", "shaders/scene/material_fuzz_noise.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_FUZZ\n#define SHADERTYPE_FUZZ_NOISE\n"},
{"Smooth Noise Fuzz", "shaders/scene/material_fuzz_smoothnoise.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_FUZZ\n#define SHADERTYPE_FUZZ_SMOOTHNOISE\n"},
{"Software Fuzz", "shaders/scene/material_fuzz_software.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_shared.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SHADERTYPE_FUZZ\n#define SHADERTYPE_FUZZ_SOFTWARE\n"},
{nullptr,nullptr,nullptr,nullptr}
};

View file

@ -89,6 +89,15 @@ struct FMaterialLayers
MaterialLayerSampling CustomShaderTextureSampling[MAX_CUSTOM_HW_SHADER_TEXTURES];
};
struct GlobalShaderDesc
{
int shaderindex = -1;
RefCountedPtr<FTexture> CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES];
MaterialLayerSampling CustomShaderTextureSampling[MAX_CUSTOM_HW_SHADER_TEXTURES];
};
extern GlobalShaderDesc globalshaders[NUM_BUILTIN_SHADERS];
// Refactoring helper to allow piece by piece adjustment of the API
class FGameTexture
{

View file

@ -128,26 +128,40 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags)
}
auto index = tx->GetShaderIndex();
if (gl_customshader)
{
if (index >= FIRST_USER_SHADER)
if (index >= FIRST_USER_SHADER || (mShaderIndex < FIRST_USER_SHADER && globalshaders[mShaderIndex].shaderindex >= FIRST_USER_SHADER))
{
const UserShaderDesc& usershader = usershaders[index - FIRST_USER_SHADER];
if (usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material
if (index >= FIRST_USER_SHADER && usershaders[index - FIRST_USER_SHADER].shaderType == mShaderIndex) // Only apply user shader if it matches the expected material
{
if (tx->Layers)
{
size_t index = 0;
size_t i = 0;
for (auto& texture : tx->Layers->CustomShaderTextures)
{
if (texture != nullptr)
{
mTextureLayers.Push({ texture.get(), 0, -1, tx->Layers->CustomShaderTextureSampling[index++]}); // scalability should be user-definable.
mTextureLayers.Push({ texture.get(), 0, -1, tx->Layers->CustomShaderTextureSampling[i++]}); // scalability should be user-definable.
}
}
}
mShaderIndex = index;
}
else if(mShaderIndex < FIRST_USER_SHADER && globalshaders[mShaderIndex].shaderindex >= FIRST_USER_SHADER)
{
size_t i = 0;
for (auto& texture : globalshaders[mShaderIndex].CustomShaderTextures)
{
if (texture != nullptr)
{
mTextureLayers.Push({ texture.get(), 0, -1, globalshaders[mShaderIndex].CustomShaderTextureSampling[i++]}); // scalability should be user-definable.
}
}
mShaderIndex = globalshaders[mShaderIndex].shaderindex;
}
}
}
}

View file

@ -82,7 +82,8 @@ enum MaterialShaderIndex
SHADER_NoiseFuzz,
SHADER_SmoothNoiseFuzz,
SHADER_SoftwareFuzz,
FIRST_USER_SHADER
NUM_BUILTIN_SHADERS,
FIRST_USER_SHADER = NUM_BUILTIN_SHADERS
};
enum texflags
@ -98,9 +99,7 @@ enum texflags
enum
{
SFlag_Brightmap = 1,
SFlag_Detailmap = 2,
SFlag_Glowmap = 4,
SFlag_Global = 1,
};
struct UserShaderDesc

View file

@ -3972,6 +3972,11 @@ void D_Cleanup()
{
*(afunc->VMPointer) = NULL;
});
for(auto &gshader : globalshaders)
{
gshader = {};
}
GC::DelSoftRootHead();

View file

@ -59,6 +59,8 @@ void ParseColorization(FScanner& sc);
extern TDeletingArray<FLightDefaults *> LightDefaults;
extern int AttenuationIsSet;
GlobalShaderDesc globalshaders[NUM_BUILTIN_SHADERS];
struct ExtraUniformCVARData
{
FString Shader;
@ -1315,6 +1317,10 @@ class GLDefsParser
bool iwad = false;
bool no_mipmap = false;
bool is_globalshader = false;
TArray<int> globaltargets;
FString str_globaltargets;
UserShaderDesc usershader;
TArray<FString> texNameList;
TArray<int> texNameIndex;
@ -1324,263 +1330,508 @@ class GLDefsParser
FGameTexture* textures[6] = {};
const char *keywords[7] = { "brightmap", "normal", "specular", "metallic", "roughness", "ao", nullptr };
const char *notFound[6] = { "Brightmap", "Normalmap", "Specular texture", "Metallic texture", "Roughness texture", "Ambient occlusion texture" };
FGameTexture* tex = nullptr;
sc.MustGetString();
if (sc.Compare("texture")) type = ETextureType::Wall;
else if (sc.Compare("flat")) type = ETextureType::Flat;
else if (sc.Compare("sprite")) type = ETextureType::Sprite;
else sc.UnGet();
sc.MustGetString();
FTextureID no = TexMan.CheckForTexture(sc.String, type, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_Overridable);
auto tex = TexMan.GetGameTexture(no);
if (tex == nullptr)
if(sc.Compare("globalshader"))
{
sc.ScriptMessage("Material definition refers nonexistent texture '%s'\n", sc.String);
is_globalshader = true;
usershader.shaderFlags |= SFlag_Global; // make sure global usershader objects aren't reused for material shaders
sc.MustGetString();
if (sc.Compare("all"))
{
str_globaltargets = "all";
globaltargets.Push(SHADER_Default);
globaltargets.Push(SHADER_Warp1);
globaltargets.Push(SHADER_Warp2);
globaltargets.Push(SHADER_Specular);
globaltargets.Push(SHADER_PBR);
globaltargets.Push(SHADER_Paletted);
globaltargets.Push(SHADER_NoTexture);
globaltargets.Push(SHADER_BasicFuzz);
globaltargets.Push(SHADER_SmoothFuzz);
globaltargets.Push(SHADER_SwirlyFuzz);
globaltargets.Push(SHADER_TranslucentFuzz);
globaltargets.Push(SHADER_JaggedFuzz);
globaltargets.Push(SHADER_NoiseFuzz);
globaltargets.Push(SHADER_SmoothNoiseFuzz);
globaltargets.Push(SHADER_SoftwareFuzz);
}
else if(sc.Compare("default"))
{
str_globaltargets = "default";
globaltargets.Push(SHADER_Default);
}
else if(sc.Compare("defaultwarp"))
{
str_globaltargets = "defaultwarp";
globaltargets.Push(SHADER_Default);
globaltargets.Push(SHADER_Warp1);
globaltargets.Push(SHADER_Warp2);
}
else if(sc.Compare("warp"))
{
str_globaltargets = "warp";
globaltargets.Push(SHADER_Warp1);
globaltargets.Push(SHADER_Warp2);
}
else if(sc.Compare("specular"))
{
str_globaltargets = "specular";
globaltargets.Push(SHADER_Specular);
}
else if(sc.Compare("pbr"))
{
str_globaltargets = "pbr";
globaltargets.Push(SHADER_PBR);
}
else if(sc.Compare("paletted"))
{
str_globaltargets = "paletted";
globaltargets.Push(SHADER_Paletted);
}
else if(sc.Compare("notexture"))
{
str_globaltargets = "notexture";
globaltargets.Push(SHADER_NoTexture);
}
else if(sc.Compare("nonfuzz"))
{
str_globaltargets = "nonfuzz";
globaltargets.Push(SHADER_Default);
globaltargets.Push(SHADER_Warp1);
globaltargets.Push(SHADER_Warp2);
globaltargets.Push(SHADER_Specular);
globaltargets.Push(SHADER_PBR);
globaltargets.Push(SHADER_Paletted);
}
else if(sc.Compare("fuzz"))
{
str_globaltargets = "fuzz";
globaltargets.Push(SHADER_BasicFuzz);
globaltargets.Push(SHADER_SmoothFuzz);
globaltargets.Push(SHADER_SwirlyFuzz);
globaltargets.Push(SHADER_TranslucentFuzz);
globaltargets.Push(SHADER_JaggedFuzz);
globaltargets.Push(SHADER_NoiseFuzz);
globaltargets.Push(SHADER_SmoothNoiseFuzz);
globaltargets.Push(SHADER_SoftwareFuzz);
}
else
{
sc.ScriptMessage("Invalid globalshader target\n", sc.String);
}
}
else tex->AddAutoMaterials(); // We need these before setting up the texture.
else
{
if (sc.Compare("texture")) type = ETextureType::Wall;
else if (sc.Compare("flat")) type = ETextureType::Flat;
else if (sc.Compare("sprite")) type = ETextureType::Sprite;
else sc.UnGet();
sc.MustGetString();
FTextureID no = TexMan.CheckForTexture(sc.String, type, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_Overridable);
tex = TexMan.GetGameTexture(no);
if (tex == nullptr)
{
sc.ScriptMessage("Material definition refers nonexistent texture '%s'\n", sc.String);
}
else tex->AddAutoMaterials(); // We need these before setting up the texture.
}
bool do_strict = gl_strict_gldefs || is_globalshader;
sc.MustGetToken('{');
while (!sc.CheckToken('}'))
{
bool isProperty = false;
sc.MustGetString();
if (sc.Compare("disablefullbright"))
if(!is_globalshader)
{
// This can also be used without a brightness map to disable
// fullbright in rotations that only use brightness maps on
// other angles.
disable_fullbright = true;
disable_fullbright_specified = true;
}
else if (sc.Compare("thiswad"))
{
// only affects textures defined in the WAD containing the definition file.
thiswad = true;
}
else if (sc.Compare ("iwad"))
{
// only affects textures defined in the IWAD.
iwad = true;
}
else if (sc.Compare("nomipmap"))
{
no_mipmap = true;
}
else if (sc.Compare("glossiness"))
{
sc.MustGetFloat();
mlay.Glossiness = (float)sc.Float;
}
else if (sc.Compare("specularlevel"))
{
sc.MustGetFloat();
mlay.SpecularLevel = (float)sc.Float;
}
else if (sc.Compare("depthfadethreshold"))
{
sc.MustGetFloat();
tex->DepthFadeThreshold = (float)sc.Float;
}
else if (sc.Compare("speed"))
{
sc.MustGetFloat();
speed = float(sc.Float);
}
else if (sc.Compare("shader"))
{
sc.MustGetString();
usershader.shader = sc.String;
}
else if (sc.Compare("disablealphatest"))
{
tex->SetTranslucent(true);
if (usershader.shader.IsNotEmpty())
usershader.disablealphatest = true;
}
else if (sc.Compare("texture"))
{
sc.MustGetString();
FString textureName = sc.String;
for (FString &texName : texNameList)
if (sc.Compare("disablefullbright"))
{
if (!texName.Compare(textureName))
{
sc.ScriptError("Trying to redefine custom hardware shader texture '%s' in texture '%s'\n", textureName.GetChars(), tex ? tex->GetName().GetChars() : "(null)");
}
isProperty = true;
// This can also be used without a brightness map to disable
// fullbright in rotations that only use brightness maps on
// other angles.
disable_fullbright = true;
disable_fullbright_specified = true;
}
sc.MustGetString();
if (tex)
else if (sc.Compare("thiswad"))
{
bool okay = false;
size_t texIndex = 0;
for (size_t i = 0; i < countof(mlay.CustomShaderTextures); i++)
isProperty = true;
// only affects textures defined in the WAD containing the definition file.
thiswad = true;
}
else if (sc.Compare ("iwad"))
{
// only affects textures defined in the IWAD.
iwad = true;
isProperty = true;
}
else if (sc.Compare("nomipmap"))
{
isProperty = true;
no_mipmap = true;
}
else if (sc.Compare("glossiness"))
{
isProperty = true;
sc.MustGetFloat();
mlay.Glossiness = (float)sc.Float;
}
else if (sc.Compare("specularlevel"))
{
isProperty = true;
sc.MustGetFloat();
mlay.SpecularLevel = (float)sc.Float;
}
else if (sc.Compare("depthfadethreshold"))
{
isProperty = true;
sc.MustGetFloat();
tex->DepthFadeThreshold = (float)sc.Float;
}
else if (sc.Compare("speed"))
{
isProperty = true;
sc.MustGetFloat();
speed = float(sc.Float);
}
else if (sc.Compare("disablealphatest"))
{
isProperty = true;
tex->SetTranslucent(true);
if (usershader.shader.IsNotEmpty())
usershader.disablealphatest = true;
}
}
if(!isProperty)
{
if (sc.Compare("shader"))
{
isProperty = true;
sc.MustGetString();
usershader.shader = sc.String;
}
else if (sc.Compare("texture"))
{
isProperty = true;
sc.MustGetString();
FString textureName = sc.String;
for (FString &texName : texNameList)
{
if (!mlay.CustomShaderTextures[i])
if (!texName.Compare(textureName))
{
if(is_globalshader)
{
sc.ScriptError("Trying to redefine custom hardware shader texture '%s' in global shader '%s'\n", textureName.GetChars(), str_globaltargets.GetChars());
}
else
{
sc.ScriptError("Trying to redefine custom hardware shader texture '%s' in texture '%s'\n", textureName.GetChars(), tex ? tex->GetName().GetChars() : "(null)");
}
}
}
sc.MustGetString();
if (tex || is_globalshader)
{
bool okay = false;
size_t texIndex = 0;
for (size_t i = 0; i < countof(mlay.CustomShaderTextures); i++)
{
mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::Default;
mlay.CustomShaderTextures[i] = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny);
if (!mlay.CustomShaderTextures[i])
{
sc.ScriptError("Custom hardware shader texture '%s' not found in texture '%s'\n", sc.String, tex->GetName().GetChars());
}
mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::Default;
mlay.CustomShaderTextures[i] = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny);
if (!mlay.CustomShaderTextures[i])
{
if(is_globalshader)
{
sc.ScriptError("Custom hardware shader texture '%s' not found in global shader '%s'\n", sc.String, str_globaltargets.GetChars());
}
else
{
sc.ScriptError("Custom hardware shader texture '%s' not found in texture '%s'\n", sc.String, tex->GetName().GetChars());
}
}
texNameList.Push(textureName);
texNameIndex.Push((int)i);
texIndex = i;
okay = true;
texNameList.Push(textureName);
texNameIndex.Push((int)i);
texIndex = i;
okay = true;
break;
}
}
if (!okay)
{
if(is_globalshader)
{
sc.ScriptError("Error: out of texture units in global shader '%s'\n", str_globaltargets.GetChars());
}
else
{
sc.ScriptError("Error: out of texture units in texture '%s'", tex->GetName().GetChars());
}
}
if (sc.CheckToken('{'))
{
while (!sc.CheckToken('}'))
{
sc.MustGetString();
if (sc.Compare("filter"))
{
sc.MustGetString();
if (sc.Compare("nearest"))
{
if(okay)
mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::NearestMipLinear;
}
else if (sc.Compare("linear"))
{
if (okay)
mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::LinearMipLinear;
}
else if (sc.Compare("default"))
{
if (okay)
mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::Default;
}
else
{
if(is_globalshader)
{
sc.ScriptError("Error: unexpected '%s' when reading filter property in global shader '%s'\n", sc.String, str_globaltargets.GetChars());
}
else
{
sc.ScriptError("Error: unexpected '%s' when reading filter property in texture '%s'\n", sc.String, tex ? tex->GetName().GetChars() : "(null)");
}
}
}
}
}
}
}
else if (sc.Compare("define"))
{
isProperty = true;
sc.MustGetString();
FString defineName = sc.String;
FString defineValue = "";
if (sc.CheckToken('='))
{
sc.MustGetString();
defineValue = sc.String;
}
usershader.defines.AppendFormat("#define %s %s\n", defineName.GetChars(), defineValue.GetChars());
}
else if(!is_globalshader)
{
for (int i = 0; keywords[i] != nullptr; i++)
{
if (sc.Compare (keywords[i]))
{
isProperty = true;
sc.MustGetString();
if (textures[i])
Printf("Multiple %s definitions in texture %s\n", keywords[i], tex? tex->GetName().GetChars() : "(null)");
textures[i] = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny);
if (!textures[i])
Printf("%s '%s' not found in texture '%s'\n", notFound[i], sc.String, tex? tex->GetName().GetChars() : "(null)");
break;
}
}
if (!okay)
{
sc.ScriptError("Error: out of texture units in texture '%s'", tex->GetName().GetChars());
}
if (sc.CheckToken('{'))
{
while (!sc.CheckToken('}'))
{
sc.MustGetString();
if (sc.Compare("filter"))
{
sc.MustGetString();
if (sc.Compare("nearest"))
{
if(okay)
mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::NearestMipLinear;
}
else if (sc.Compare("linear"))
{
if (okay)
mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::LinearMipLinear;
}
else if (sc.Compare("default"))
{
if (okay)
mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::Default;
}
else
{
sc.ScriptError("Error: unexpected '%s' when reading filter property in texture '%s'\n", sc.String, tex ? tex->GetName().GetChars() : "(null)");
}
}
}
}
}
}
else if (sc.Compare("define"))
if(!isProperty && do_strict)
{
sc.MustGetString();
FString defineName = sc.String;
FString defineValue = "";
if (sc.CheckToken('='))
if(is_globalshader)
{
sc.MustGetString();
defineValue = sc.String;
sc.ScriptError("Unknown keyword '%s' in global shader '%s'", sc.String, str_globaltargets.GetChars());
}
usershader.defines.AppendFormat("#define %s %s\n", defineName.GetChars(), defineValue.GetChars());
}
else
{
for (int i = 0; keywords[i] != nullptr; i++)
else
{
if (sc.Compare (keywords[i]))
{
sc.MustGetString();
if (textures[i])
Printf("Multiple %s definitions in texture %s\n", keywords[i], tex? tex->GetName().GetChars() : "(null)");
textures[i] = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny);
if (!textures[i])
Printf("%s '%s' not found in texture '%s'\n", notFound[i], sc.String, tex? tex->GetName().GetChars() : "(null)");
break;
}
sc.ScriptError("Unknown keyword '%s' in texture '%s'", sc.String, tex? tex->GetName().GetChars() : "(null)");
}
}
}
if (!tex)
if (!tex && !is_globalshader)
{
return;
}
if (thiswad || iwad)
if(is_globalshader)
{
bool useme = false;
int lumpnum = tex->GetSourceLump();
if (lumpnum != -1)
if(fileSystem.GetFileContainer(workingLump) > fileSystem.GetMaxIwadNum())
{
if (iwad && fileSystem.GetFileContainer(lumpnum) <= fileSystem.GetMaxIwadNum()) useme = true;
if (thiswad && fileSystem.GetFileContainer(lumpnum) == fileSystem.GetFileContainer(workingLump)) useme = true;
}
if (!useme) return;
}
tex->SetNoMipmap(no_mipmap);
FGameTexture **bindings[6] =
{
&mlay.Brightmap,
&mlay.Normal,
&mlay.Specular,
&mlay.Metallic,
&mlay.Roughness,
&mlay.AmbientOcclusion
};
for (int i = 0; keywords[i] != nullptr; i++)
{
if (textures[i])
{
*bindings[i] = textures[i];
}
}
if (disable_fullbright_specified)
tex->SetDisableFullbright(disable_fullbright);
if (usershader.shader.IsNotEmpty())
{
int firstUserTexture;
if ((mlay.Normal || tex->GetNormalmap()) && (mlay.Specular || tex->GetSpecularmap()))
{
usershader.shaderType = SHADER_Specular;
firstUserTexture = 7;
}
else if ((mlay.Normal || tex->GetNormalmap()) && (mlay.Metallic || tex->GetMetallic()) && (mlay.Roughness || tex->GetRoughness()) && (mlay.AmbientOcclusion || tex->GetAmbientOcclusion()))
{
usershader.shaderType = SHADER_PBR;
firstUserTexture = 9;
}
else
{
usershader.shaderType = SHADER_Default;
firstUserTexture = 5;
}
for (unsigned int i = 0; i < texNameList.Size(); i++)
{
usershader.defines.AppendFormat("#define %s texture%d\n", texNameList[i].GetChars(), texNameIndex[i] + firstUserTexture);
}
if (tex->isWarped() != 0)
{
Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->GetName().GetChars());
sc.ScriptError("globalshader only supported on iwad");
return;
}
tex->SetShaderSpeed(speed);
for (unsigned i = 0; i < usershaders.Size(); i++)
else for(int target : globaltargets)
{
if (!usershaders[i].shader.CompareNoCase(usershader.shader) &&
usershaders[i].shaderType == usershader.shaderType &&
!usershaders[i].defines.Compare(usershader.defines))
if(globalshaders[target].shaderindex >= 0)
{
SetShaderIndex(tex, i + FIRST_USER_SHADER);
tex->SetShaderLayers(mlay);
sc.ScriptError("globalshader already exists for '%s'", str_globaltargets.GetChars());
return;
}
}
SetShaderIndex(tex, usershaders.Push(usershader) + FIRST_USER_SHADER);
if (usershader.shader.IsNotEmpty())
{
int lump = fileSystem.CheckNumForFullName(usershader.shader.GetChars(), 0);
if (lump == -1)
{
sc.ScriptError("inexistent shader lump '%s' in globalshader '%s'", usershader.shader.GetChars(), str_globaltargets.GetChars());
return;
}
for(int target : globaltargets)
{
FString baseDefines = usershader.defines;
int firstUserTexture;
if (target == SHADER_Specular)
{
firstUserTexture = 7;
}
else if (target == SHADER_PBR)
{
firstUserTexture = 9;
}
else
{
firstUserTexture = 5;
}
for (unsigned int i = 0; i < texNameList.Size(); i++)
{
usershader.defines.AppendFormat("#define %s texture%d\n", texNameList[i].GetChars(), texNameIndex[i] + firstUserTexture);
}
usershader.shaderType = MaterialShaderIndex(target);
globalshaders[target].shaderindex = usershaders.Push(usershader) + FIRST_USER_SHADER;
for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES; i++)
{
if (mlay.CustomShaderTextures[i])
{
globalshaders[target].CustomShaderTextureSampling[i] = mlay.CustomShaderTextureSampling[i];
globalshaders[target].CustomShaderTextures[i] = mlay.CustomShaderTextures[i]->GetTexture();
}
}
usershader.defines = baseDefines;
}
}
else
{
sc.ScriptError("shader lump not specified for global shader '%s'", usershader.shader.GetChars(), str_globaltargets.GetChars());
}
}
else
{
if (thiswad || iwad)
{
bool useme = false;
int lumpnum = tex->GetSourceLump();
if (lumpnum != -1)
{
if (iwad && fileSystem.GetFileContainer(lumpnum) <= fileSystem.GetMaxIwadNum()) useme = true;
if (thiswad && fileSystem.GetFileContainer(lumpnum) == fileSystem.GetFileContainer(workingLump)) useme = true;
}
if (!useme) return;
}
tex->SetNoMipmap(no_mipmap);
FGameTexture **bindings[6] =
{
&mlay.Brightmap,
&mlay.Normal,
&mlay.Specular,
&mlay.Metallic,
&mlay.Roughness,
&mlay.AmbientOcclusion
};
for (int i = 0; keywords[i] != nullptr; i++)
{
if (textures[i])
{
*bindings[i] = textures[i];
}
}
if (disable_fullbright_specified)
tex->SetDisableFullbright(disable_fullbright);
if (usershader.shader.IsNotEmpty())
{
if(do_strict)
{
int lump = fileSystem.CheckNumForFullName(usershader.shader.GetChars(), 0);
if (lump == -1)
{
sc.ScriptError("inexistent shader lump '%s' in globalshader '%s'", usershader.shader.GetChars(), str_globaltargets.GetChars());
return;
}
}
int firstUserTexture;
if ((mlay.Normal || tex->GetNormalmap()) && (mlay.Specular || tex->GetSpecularmap()))
{
usershader.shaderType = SHADER_Specular;
firstUserTexture = 7;
}
else if ((mlay.Normal || tex->GetNormalmap()) && (mlay.Metallic || tex->GetMetallic()) && (mlay.Roughness || tex->GetRoughness()) && (mlay.AmbientOcclusion || tex->GetAmbientOcclusion()))
{
usershader.shaderType = SHADER_PBR;
firstUserTexture = 9;
}
else
{
usershader.shaderType = SHADER_Default;
firstUserTexture = 5;
}
for (unsigned int i = 0; i < texNameList.Size(); i++)
{
usershader.defines.AppendFormat("#define %s texture%d\n", texNameList[i].GetChars(), texNameIndex[i] + firstUserTexture);
}
if (tex->isWarped() != 0)
{
Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->GetName().GetChars());
return;
}
tex->SetShaderSpeed(speed);
for (unsigned i = 0; i < usershaders.Size(); i++)
{
if (!usershaders[i].shader.CompareNoCase(usershader.shader) &&
usershaders[i].shaderType == usershader.shaderType &&
usershaders[i].shaderFlags == usershader.shaderFlags &&
!usershaders[i].defines.Compare(usershader.defines))
{
SetShaderIndex(tex, i + FIRST_USER_SHADER);
tex->SetShaderLayers(mlay);
return;
}
}
SetShaderIndex(tex, usershaders.Push(usershader) + FIRST_USER_SHADER);
}
tex->SetShaderLayers(mlay);
}
tex->SetShaderLayers(mlay);
}
@ -1888,7 +2139,6 @@ class GLDefsParser
if (sc.Compare(typeName[i]))
{
desc.shaderType = typeIndex[i];
if (usesBrightmap[i]) desc.shaderFlags |= SFlag_Brightmap;
found = true;
break;
}
@ -1992,6 +2242,7 @@ class GLDefsParser
{
if (!usershaders[i].shader.CompareNoCase(desc.shader) &&
usershaders[i].shaderType == desc.shaderType &&
usershaders[i].shaderFlags == desc.shaderFlags &&
!usershaders[i].defines.Compare(desc.defines))
{
SetShaderIndex(tex, i + FIRST_USER_SHADER);