diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d39eca9dde..95c07ac7df 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1465,8 +1465,8 @@ source_group("Common\\Scripting\\Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_S source_group("Common\\Scripting\\Core" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/core/.+") source_group("Common\\Scripting\\JIT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/jit/.+") source_group("Common\\Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/vm/.+") -source_group("Common\\Rendering" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/.+") -source_group("Common\\Rendering\\OpenGL Loader" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl_load/.+") +source_group("Common\\Rendering" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/.+") +source_group("Common\\Rendering\\OpenGL Loader" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/gl_load/.+") source_group("Common\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/.+") source_group("Common\\Textures\\Hires" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/hires/.+") source_group("Common\\Textures\\Hires\\HQ Resize" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/hires/hqnx/.+") diff --git a/src/common/2d/v_2ddrawer.cpp b/src/common/2d/v_2ddrawer.cpp index 39398b8007..4cee865ab3 100644 --- a/src/common/2d/v_2ddrawer.cpp +++ b/src/common/2d/v_2ddrawer.cpp @@ -755,7 +755,7 @@ void F2DDrawer::ClearScreen(PalEntry color) // //========================================================================== -void F2DDrawer::AddLine(float x1, float y1, float x2, float y2, int clipx1, int clipy1, int clipx2, int clipy2, uint32_t color, uint8_t alpha) +void F2DDrawer::AddLine(double x1, double y1, double x2, double y2, int clipx1, int clipy1, int clipx2, int clipy2, uint32_t color, uint8_t alpha) { PalEntry p = (PalEntry)color; p.a = alpha; diff --git a/src/common/2d/v_2ddrawer.h b/src/common/2d/v_2ddrawer.h index ed4c1ee94d..7c759b1954 100644 --- a/src/common/2d/v_2ddrawer.h +++ b/src/common/2d/v_2ddrawer.h @@ -190,7 +190,7 @@ public: void AddClear(int left, int top, int right, int bottom, int palcolor, uint32_t color); - void AddLine(float x1, float y1, float x2, float y2, int cx, int cy, int cx2, int cy2, uint32_t color, uint8_t alpha = 255); + void AddLine(double x1, double y1, double x2, double y2, int cx, int cy, int cx2, int cy2, uint32_t color, uint8_t alpha = 255); void AddThickLine(int x1, int y1, int x2, int y2, double thickness, uint32_t color, uint8_t alpha = 255); void AddPixel(int x1, int y1, uint32_t color); diff --git a/src/common/filesystem/filesystem.h b/src/common/filesystem/filesystem.h index f71aefb85d..dd5cc8234f 100644 --- a/src/common/filesystem/filesystem.h +++ b/src/common/filesystem/filesystem.h @@ -38,7 +38,7 @@ public: ~FileData (); void *GetMem () { return Block.Len() == 0 ? NULL : (void *)Block.GetChars(); } size_t GetSize () { return Block.Len(); } - FString GetString () { return Block; } + const FString &GetString () const { return Block; } private: FileData (const FString &source); diff --git a/src/common/textures/formats/emptytexture.cpp b/src/common/textures/formats/emptytexture.cpp index ab4703e4ee..bcbd682e0c 100644 --- a/src/common/textures/formats/emptytexture.cpp +++ b/src/common/textures/formats/emptytexture.cpp @@ -69,6 +69,11 @@ FImageSource *EmptyImage_TryCreate(FileReader & file, int lumpnum) return new FEmptyTexture(lumpnum); } +FImageSource* CreateEmptyTexture() +{ + return new FEmptyTexture(0); +} + //========================================================================== // // diff --git a/src/common/textures/hw_material.cpp b/src/common/textures/hw_material.cpp index 803cd34e42..8c0bc06ef8 100644 --- a/src/common/textures/hw_material.cpp +++ b/src/common/textures/hw_material.cpp @@ -45,10 +45,6 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) { mShaderIndex = SHADER_Paletted; } - else if (tx->isWarped()) - { - mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2 - } else if (tx->isHardwareCanvas()) { if (tx->shaderindex >= FIRST_USER_SHADER) @@ -59,7 +55,11 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) } else { - if (tx->Normal && tx->Specular) + if (tx->isWarped()) + { + mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2 + } + else if (tx->Normal && tx->Specular) { for (auto &texture : { tx->Normal, tx->Specular }) { @@ -76,16 +76,34 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) mShaderIndex = SHADER_PBR; } + // Note that these layers must present a valid texture even if not used, because empty TMUs in the shader are an undefined condition. tx->CreateDefaultBrightmap(); if (tx->Brightmap) { mTextureLayers.Push(tx->Brightmap); - if (mShaderIndex == SHADER_Specular) - mShaderIndex = SHADER_SpecularBrightmap; - else if (mShaderIndex == SHADER_PBR) - mShaderIndex = SHADER_PBRBrightmap; - else - mShaderIndex = SHADER_Brightmap; + mLayerFlags |= TEXF_Brightmap; + } + else + { + mTextureLayers.Push(TexMan.ByIndex(1)); + } + if (tx->Detailmap) + { + mTextureLayers.Push(tx->Detailmap); + mLayerFlags |= TEXF_Detailmap; + } + else + { + mTextureLayers.Push(TexMan.ByIndex(1)); + } + if (tx->Glowmap) + { + mTextureLayers.Push(tx->Glowmap); + mLayerFlags |= TEXF_Glowmap; + } + else + { + mTextureLayers.Push(TexMan.ByIndex(1)); } if (tx->shaderindex >= FIRST_USER_SHADER) @@ -347,7 +365,7 @@ again: { if (expand) { - if (tex->isWarped() || tex->isHardwareCanvas() || tex->shaderindex >= FIRST_USER_SHADER || (tex->shaderindex >= SHADER_Specular && tex->shaderindex <= SHADER_PBRBrightmap)) + if (tex->isWarped() || tex->isHardwareCanvas() || tex->shaderindex >= FIRST_USER_SHADER || tex->shaderindex == SHADER_Specular || tex->shaderindex == SHADER_PBR) { tex->bNoExpand = true; goto again; diff --git a/src/common/textures/hw_material.h b/src/common/textures/hw_material.h index f6311c9628..0265573768 100644 --- a/src/common/textures/hw_material.h +++ b/src/common/textures/hw_material.h @@ -30,6 +30,7 @@ class FMaterial { TArray mTextureLayers; int mShaderIndex; + int mLayerFlags = 0; short mLeftOffset; short mTopOffset; @@ -52,6 +53,7 @@ public: FMaterial(FTexture *tex, bool forceexpand); ~FMaterial(); + int GetLayerFlags() const { return mLayerFlags; } void SetSpriteRect(); int GetShaderIndex() const { return mShaderIndex; } void AddTextureLayer(FTexture *tex) diff --git a/src/common/textures/texture.cpp b/src/common/textures/texture.cpp index 401b61b13f..be2b730e79 100644 --- a/src/common/textures/texture.cpp +++ b/src/common/textures/texture.cpp @@ -116,7 +116,7 @@ FTexture::FTexture (const char *name, int lumpnum) : Scale(1,1), SourceLump(lumpnum), UseType(ETextureType::Any), bNoDecals(false), bNoRemap0(false), bWorldPanning(false), - bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(0), bComplex(false), bMultiPatch(false), bFullNameTexture(false), + bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(1), bComplex(false), bMultiPatch(false), bFullNameTexture(false), Rotations(0xFFFF), SkyOffset(0), Width(0), Height(0) { bBrightmapChecked = false; @@ -384,7 +384,7 @@ void FTexture::CreateDefaultBrightmap() // Check for brightmaps if (GetImage() && GetImage()->UseGamePalette() && GPalette.HasGlobalBrightmap && UseType != ETextureType::Decal && UseType != ETextureType::MiscPatch && UseType != ETextureType::FontChar && - Brightmap == NULL && bWarped == 0) + Brightmap == NULL) { // May have one - let's check when we use this texture auto texbuf = Get8BitPixels(false); diff --git a/src/common/textures/texturemanager.cpp b/src/common/textures/texturemanager.cpp index 66a196a310..76024b4ecd 100644 --- a/src/common/textures/texturemanager.cpp +++ b/src/common/textures/texturemanager.cpp @@ -1083,6 +1083,7 @@ void FTextureManager::AddLocalizedVariants() //========================================================================== FTexture *CreateShaderTexture(bool, bool); void InitBuildTiles(); +FImageSource* CreateEmptyTexture(); void FTextureManager::Init(void (*progressFunc_)(), void (*checkForHacks)(BuildInfo&)) { @@ -1094,6 +1095,10 @@ void FTextureManager::Init(void (*progressFunc_)(), void (*checkForHacks)(BuildI auto nulltex = new FImageTexture(nullptr, ""); nulltex->SetUseType(ETextureType::Null); AddTexture (nulltex); + // This is for binding to unused texture units, because accessing an unbound texture unit is undefined. It's a one pixel empty texture. + auto emptytex = new FImageTexture(CreateEmptyTexture(), ""); + emptytex->SetSize(1, 1); + AddTexture(emptytex); // some special textures used in the game. AddTexture(CreateShaderTexture(false, false)); AddTexture(CreateShaderTexture(false, true)); diff --git a/src/common/textures/textures.h b/src/common/textures/textures.h index e1fa263fde..cefb39114b 100644 --- a/src/common/textures/textures.h +++ b/src/common/textures/textures.h @@ -54,11 +54,8 @@ enum MaterialShaderIndex SHADER_Default, SHADER_Warp1, SHADER_Warp2, - SHADER_Brightmap, SHADER_Specular, - SHADER_SpecularBrightmap, SHADER_PBR, - SHADER_PBRBrightmap, SHADER_Paletted, SHADER_NoTexture, SHADER_BasicFuzz, @@ -72,12 +69,30 @@ enum MaterialShaderIndex FIRST_USER_SHADER }; +enum texflags +{ + // These get Or'ed into uTextureMode because it only uses its 3 lowermost bits. + TEXF_Brightmap = 0x10000, + TEXF_Detailmap = 0x20000, + TEXF_Glowmap = 0x40000, +}; + + + +enum +{ + SFlag_Brightmap = 1, + SFlag_Detailmap = 2, + SFlag_Glowmap = 4, +}; + struct UserShaderDesc { FString shader; MaterialShaderIndex shaderType; FString defines; bool disablealphatest = false; + uint8_t shaderFlags = 0; }; extern TArray usershaders; @@ -341,6 +356,8 @@ protected: FTexture *PalVersion = nullptr; // Material layers FTexture *Brightmap = nullptr; + FTexture* Detailmap = nullptr; + FTexture* Glowmap = nullptr; FTexture *Normal = nullptr; // Normal map texture FTexture *Specular = nullptr; // Specular light texture for the diffuse+normal+specular light model FTexture *Metallic = nullptr; // Metalness texture for the physically based rendering (PBR) light model diff --git a/src/r_data/gldefs.cpp b/src/r_data/gldefs.cpp index a8f68d5f18..40f32f306b 100644 --- a/src/r_data/gldefs.cpp +++ b/src/r_data/gldefs.cpp @@ -1372,18 +1372,18 @@ class GLDefsParser int firstUserTexture; if (tex->Normal && tex->Specular) { - usershader.shaderType = tex->Brightmap ? SHADER_SpecularBrightmap : SHADER_Specular; - firstUserTexture = tex->Brightmap ? 5 : 4; + usershader.shaderType = SHADER_Specular; + firstUserTexture = 7; } else if (tex->Normal && tex->Metallic && tex->Roughness && tex->AmbientOcclusion) { - usershader.shaderType = tex->Brightmap ? SHADER_PBRBrightmap : SHADER_PBR; - firstUserTexture = tex->Brightmap ? 7 : 6; + usershader.shaderType = SHADER_PBR; + firstUserTexture = 9; } else { - usershader.shaderType = tex->Brightmap ? SHADER_Brightmap : SHADER_Default; - firstUserTexture = tex->Brightmap ? 3 : 2; + usershader.shaderType = SHADER_Default; + firstUserTexture = 5; } for (unsigned int i = 0; i < texNameList.Size(); i++) @@ -1537,14 +1537,16 @@ class GLDefsParser else if (sc.Compare("material")) { sc.MustGetString(); - MaterialShaderIndex typeIndex[6] = { SHADER_Default, SHADER_Brightmap, SHADER_Specular, SHADER_SpecularBrightmap, SHADER_PBR, SHADER_PBRBrightmap }; - const char *typeName[6] = { "normal", "brightmap", "specular", "specularbrightmap", "pbr", "pbrbrightmap" }; + static MaterialShaderIndex typeIndex[6] = { SHADER_Default, SHADER_Default, SHADER_Specular, SHADER_Specular, SHADER_PBR, SHADER_PBR }; + static bool usesBrightmap[6] = { false, true, false, true, false, true }; + static const char *typeName[6] = { "normal", "brightmap", "specular", "specularbrightmap", "pbr", "pbrbrightmap" }; bool found = false; for (int i = 0; i < 6; i++) { if (sc.Compare(typeName[i])) { desc.shaderType = typeIndex[i]; + if (usesBrightmap[i]) desc.shaderFlags |= SFlag_Brightmap; found = true; break; } @@ -1617,12 +1619,9 @@ class GLDefsParser switch (desc.shaderType) { default: - case SHADER_Default: firstUserTexture = 2; break; - case SHADER_Brightmap: firstUserTexture = 3; break; - case SHADER_Specular: firstUserTexture = 4; break; - case SHADER_SpecularBrightmap: firstUserTexture = 5; break; - case SHADER_PBR: firstUserTexture = 6; break; - case SHADER_PBRBrightmap: firstUserTexture = 7; break; + case SHADER_Default: firstUserTexture = 5; break; + case SHADER_Specular: firstUserTexture = 7; break; + case SHADER_PBR: firstUserTexture = 9; break; } for (unsigned int i = 0; i < texNameList.Size(); i++) diff --git a/src/rendering/gl/renderer/gl_renderstate.cpp b/src/rendering/gl/renderer/gl_renderstate.cpp index fdaebfcd37..8bb637ca4d 100644 --- a/src/rendering/gl/renderer/gl_renderstate.cpp +++ b/src/rendering/gl/renderer/gl_renderstate.cpp @@ -126,7 +126,10 @@ bool FGLRenderState::ApplyShader() activeShader->muDesaturation.Set(mStreamData.uDesaturationFactor); activeShader->muFogEnabled.Set(fogset); - activeShader->muTextureMode.Set(mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode); + + int f = mTextureModeFlags; + if (!mBrightmapEnabled) f &= TEXF_Detailmap; + activeShader->muTextureMode.Set((mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode) | f); activeShader->muLightParms.Set(mLightParms); activeShader->muFogColor.Set(mStreamData.uFogColor); activeShader->muObjectColor.Set(mStreamData.uObjectColor); @@ -141,6 +144,7 @@ bool FGLRenderState::ApplyShader() activeShader->muTextureAddColor.Set(mStreamData.uTextureAddColor); activeShader->muTextureModulateColor.Set(mStreamData.uTextureModulateColor); activeShader->muTextureBlendColor.Set(mStreamData.uTextureBlendColor); + activeShader->muDetailParms.Set(&mStreamData.uDetailParms.X); if (mGlowEnabled || activeShader->currentglowstate) { @@ -166,6 +170,7 @@ bool FGLRenderState::ApplyShader() activeShader->currentsplitstate = mSplitEnabled; } + if (mTextureMatrixEnabled) { matrixToGL(mTextureMatrix, activeShader->texturematrix_index); diff --git a/src/rendering/gl/shaders/gl_shader.cpp b/src/rendering/gl/shaders/gl_shader.cpp index 1aa23bcbd7..8487c29818 100644 --- a/src/rendering/gl/shaders/gl_shader.cpp +++ b/src/rendering/gl/shaders/gl_shader.cpp @@ -262,6 +262,8 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * i_data += "uniform vec4 uSplitTopPlane;\n"; i_data += "uniform vec4 uSplitBottomPlane;\n"; + i_data += "uniform vec4 uDetailParms;\n"; + // Lighting + Fog i_data += "uniform vec4 uLightAttr;\n"; i_data += "#define uLightLevel uLightAttr.a\n"; @@ -302,6 +304,8 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * i_data += "uniform sampler2D texture4;\n"; i_data += "uniform sampler2D texture5;\n"; i_data += "uniform sampler2D texture6;\n"; + i_data += "uniform sampler2D texture7;\n"; + i_data += "uniform sampler2D texture8;\n"; // timer data i_data += "uniform float timer;\n"; @@ -311,14 +315,20 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * i_data += "#define normaltexture texture2\n"; i_data += "#define speculartexture texture3\n"; i_data += "#define brighttexture texture4\n"; + i_data += "#define detailtexture texture5\n"; + i_data += "#define glowtexture texture6\n"; i_data += "#elif defined(PBR)\n"; i_data += "#define normaltexture texture2\n"; i_data += "#define metallictexture texture3\n"; i_data += "#define roughnesstexture texture4\n"; i_data += "#define aotexture texture5\n"; i_data += "#define brighttexture texture6\n"; + i_data += "#define detailtexture texture7\n"; + i_data += "#define glowtexture texture8\n"; i_data += "#else\n"; i_data += "#define brighttexture texture2\n"; + i_data += "#define detailtexture texture3\n"; + i_data += "#define glowtexture texture4\n"; i_data += "#endif\n"; #ifdef __APPLE__ @@ -387,22 +397,31 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * if (pp_lump == -1) I_Error("Unable to load '%s'", proc_prog_lump); FileData pp_data = fileSystem.ReadFile(pp_lump); - if (pp_data.GetString().IndexOf("ProcessMaterial") < 0) + if (pp_data.GetString().IndexOf("ProcessMaterial") < 0 && pp_data.GetString().IndexOf("SetupMaterial") < 0) { // this looks like an old custom hardware shader. - // add ProcessMaterial function that calls the older ProcessTexel function - int pl_lump = fileSystem.CheckNumForFullName("shaders/glsl/func_defaultmat.fp", 0); - if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders/glsl/func_defaultmat.fp"); - FileData pl_data = fileSystem.ReadFile(pl_lump); - fp_comb << "\n" << pl_data.GetString().GetChars(); - - if (pp_data.GetString().IndexOf("ProcessTexel") < 0) + if (pp_data.GetString().IndexOf("GetTexCoord") >= 0) { - // this looks like an even older custom hardware shader. - // We need to replace the ProcessTexel call to make it work. + int pl_lump = fileSystem.CheckNumForFullName("shaders/glsl/func_defaultmat2.fp", 0); + if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders/glsl/func_defaultmat2.fp"); + FileData pl_data = fileSystem.ReadFile(pl_lump); + fp_comb << "\n" << pl_data.GetString().GetChars(); + } + else + { + int pl_lump = fileSystem.CheckNumForFullName("shaders/glsl/func_defaultmat.fp", 0); + if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders/glsl/func_defaultmat.fp"); + FileData pl_data = fileSystem.ReadFile(pl_lump); + fp_comb << "\n" << pl_data.GetString().GetChars(); - fp_comb.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));"); + if (pp_data.GetString().IndexOf("ProcessTexel") < 0) + { + // this looks like an even older custom hardware shader. + // We need to replace the ProcessTexel call to make it work. + + fp_comb.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));"); + } } if (pp_data.GetString().IndexOf("ProcessLight") >= 0) @@ -423,6 +442,14 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * FileData pl_data = fileSystem.ReadFile(pl_lump); fp_comb << "\n" << pl_data.GetString().GetChars(); } + + // ProcessMaterial must be considered broken because it requires the user to fill in data they possibly cannot know all about. + if (pp_data.GetString().IndexOf("ProcessMaterial") >= 0 && pp_data.GetString().IndexOf("SetupMaterial") < 0) + { + // This reactivates the old logic and disables all features that cannot be supported with that method. + fp_comb.Insert(0, "#define LEGACY_USER_SHADER\n"); + } + } else { @@ -546,6 +573,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * muGradientTopPlane.Init(hShader, "uGradientTopPlane"); muSplitBottomPlane.Init(hShader, "uSplitBottomPlane"); muSplitTopPlane.Init(hShader, "uSplitTopPlane"); + muDetailParms.Init(hShader, "uDetailParms"); muInterpolationFactor.Init(hShader, "uInterpolationFactor"); muAlphaThreshold.Init(hShader, "uAlphaThreshold"); muSpecularMaterial.Init(hShader, "uSpecularMaterial"); diff --git a/src/rendering/gl/shaders/gl_shader.h b/src/rendering/gl/shaders/gl_shader.h index e9d638446b..c5068f5a23 100644 --- a/src/rendering/gl/shaders/gl_shader.h +++ b/src/rendering/gl/shaders/gl_shader.h @@ -257,6 +257,7 @@ class FShader FUniform4f muGradientTopPlane; FUniform4f muSplitBottomPlane; FUniform4f muSplitTopPlane; + FUniform4f muDetailParms; FBufferedUniform1f muInterpolationFactor; FBufferedUniform1f muAlphaThreshold; FBufferedUniform2f muSpecularMaterial; @@ -331,8 +332,8 @@ public: FShader *Get(unsigned int eff, bool alphateston) { - // indices 0-2 match the warping modes, 3 is brightmap, 4 no texture, the following are custom - if (!alphateston && eff <= 3) + // indices 0-2 match the warping modes, 3 no texture, the following are custom + if (!alphateston && eff <= 2) { return mMaterialShadersNAT[eff]; // Non-alphatest shaders are only created for default, warp1+2 and brightmap. The rest won't get used anyway } diff --git a/src/rendering/hwrenderer/scene/hw_renderstate.h b/src/rendering/hwrenderer/scene/hw_renderstate.h index 6ec91b6c35..7791dbc287 100644 --- a/src/rendering/hwrenderer/scene/hw_renderstate.h +++ b/src/rendering/hwrenderer/scene/hw_renderstate.h @@ -199,6 +199,8 @@ struct StreamData FVector4 uSplitTopPlane; FVector4 uSplitBottomPlane; + + FVector4 uDetailParms; }; class FRenderState @@ -208,14 +210,15 @@ protected: uint8_t mTextureEnabled:1; uint8_t mGlowEnabled : 1; uint8_t mGradientEnabled : 1; - uint8_t mBrightmapEnabled : 1; uint8_t mModelMatrixEnabled : 1; uint8_t mTextureMatrixEnabled : 1; uint8_t mSplitEnabled : 1; + uint8_t mBrightmapEnabled : 1; int mLightIndex; int mSpecialEffect; int mTextureMode; + int mTextureModeFlags; int mSoftLight; float mLightParms[4]; @@ -247,10 +250,11 @@ public: void Reset() { mTextureEnabled = true; - mGradientEnabled = mBrightmapEnabled = mFogEnabled = mGlowEnabled = false; + mBrightmapEnabled = mGradientEnabled = mFogEnabled = mGlowEnabled = false; mFogColor = 0xffffffff; mStreamData.uFogColor = mFogColor; mTextureMode = -1; + mTextureModeFlags = 0; mStreamData.uDesaturationFactor = 0.0f; mAlphaThreshold = 0.5f; mModelMatrixEnabled = false; @@ -287,6 +291,7 @@ public: mStreamData.uSplitTopPlane = { 0.0f, 0.0f, 0.0f, 0.0f }; mStreamData.uSplitBottomPlane = { 0.0f, 0.0f, 0.0f, 0.0f }; mStreamData.uDynLightColor = { 0.0f, 0.0f, 0.0f, 0.0f }; + mStreamData.uDetailParms = { 0.0f, 0.0f, 0.0f, 0.0f }; mModelMatrix.loadIdentity(); mTextureMatrix.loadIdentity(); @@ -338,15 +343,15 @@ public: { if (style.Flags & STYLEF_RedIsAlpha) { - mTextureMode = TM_ALPHATEXTURE; + SetTextureMode(TM_ALPHATEXTURE); } else if (style.Flags & STYLEF_ColorIsFixed) { - mTextureMode = TM_STENCIL; + SetTextureMode(TM_STENCIL); } else if (style.Flags & STYLEF_InvertSource) { - mTextureMode = TM_INVERSE; + SetTextureMode(TM_INVERSE); } } @@ -451,6 +456,11 @@ public: mStreamData.uSplitBottomPlane = { (float)bn.X, (float)bn.Y, (float)bottom.negiC, (float)bottom.fD() }; } + void SetDetailParms(float xscale, float yscale, float bias) + { + mStreamData.uDetailParms = { xscale, yscale, bias, 0 }; + } + void SetDynLight(float r, float g, float b) { mStreamData.uDynLightColor = { r, g, b, 0.0f }; @@ -556,6 +566,7 @@ public: mMaterial.mTranslation = translation; mMaterial.mOverrideShader = overrideshader; mMaterial.mChanged = true; + mTextureModeFlags = mat->GetLayerFlags(); } void SetClipSplit(float bottom, float top) diff --git a/src/rendering/hwrenderer/utility/hw_shaderpatcher.cpp b/src/rendering/hwrenderer/utility/hw_shaderpatcher.cpp index bdbaa50b4a..cfe2b754c4 100644 --- a/src/rendering/hwrenderer/utility/hw_shaderpatcher.cpp +++ b/src/rendering/hwrenderer/utility/hw_shaderpatcher.cpp @@ -268,11 +268,8 @@ const FDefaultShader defaultshaders[] = {"Default", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", ""}, {"Warp 1", "shaders/glsl/func_warp1.fp", "shaders/glsl/material_normal.fp", ""}, {"Warp 2", "shaders/glsl/func_warp2.fp", "shaders/glsl/material_normal.fp", ""}, - {"Brightmap","shaders/glsl/func_brightmap.fp", "shaders/glsl/material_normal.fp", "#define BRIGHTMAP\n"}, {"Specular", "shaders/glsl/func_spec.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n"}, - {"SpecularBrightmap", "shaders/glsl/func_spec.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n#define BRIGHTMAP\n"}, {"PBR","shaders/glsl/func_pbr.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n"}, - {"PBRBrightmap","shaders/glsl/func_pbr.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n#define BRIGHTMAP\n"}, {"Paletted", "shaders/glsl/func_paletted.fp", "shaders/glsl/material_nolight.fp", ""}, {"No Texture", "shaders/glsl/func_notexture.fp", "shaders/glsl/material_normal.fp", ""}, {"Basic Fuzz", "shaders/glsl/fuzz_standard.fp", "shaders/glsl/material_normal.fp", ""}, diff --git a/src/rendering/polyrenderer/backend/poly_renderstate.cpp b/src/rendering/polyrenderer/backend/poly_renderstate.cpp index 1d19460ec6..cc763b89a1 100644 --- a/src/rendering/polyrenderer/backend/poly_renderstate.cpp +++ b/src/rendering/polyrenderer/backend/poly_renderstate.cpp @@ -287,7 +287,7 @@ void PolyRenderState::Apply() PolyPushConstants constants; constants.uFogEnabled = fogset; - constants.uTextureMode = mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode; + constants.uTextureMode = (mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode); constants.uLightDist = mLightParms[0]; constants.uLightFactor = mLightParms[1]; constants.uFogDensity = mLightParms[2]; diff --git a/src/rendering/vulkan/renderer/vk_renderstate.cpp b/src/rendering/vulkan/renderer/vk_renderstate.cpp index abf2ba12a6..11f0403205 100644 --- a/src/rendering/vulkan/renderer/vk_renderstate.cpp +++ b/src/rendering/vulkan/renderer/vk_renderstate.cpp @@ -372,7 +372,9 @@ void VkRenderState::ApplyPushConstants() tempTM = TM_OPAQUE; mPushConstants.uFogEnabled = fogset; - mPushConstants.uTextureMode = mTextureMode == TM_NORMAL && tempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode; + int f = mTextureModeFlags; + if (!mBrightmapEnabled) f &= TEXF_Detailmap; + mPushConstants.uTextureMode = (mTextureMode == TM_NORMAL && tempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode) | f; mPushConstants.uLightDist = mLightParms[0]; mPushConstants.uLightFactor = mLightParms[1]; mPushConstants.uFogDensity = mLightParms[2]; diff --git a/src/rendering/vulkan/shaders/vk_shader.cpp b/src/rendering/vulkan/shaders/vk_shader.cpp index 6432abc50e..d7b461cf10 100644 --- a/src/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/rendering/vulkan/shaders/vk_shader.cpp @@ -90,10 +90,10 @@ VkShaderProgram *VkShaderManager::GetEffect(int effect, EPassType passType) VkShaderProgram *VkShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType) { - // indices 0-2 match the warping modes, 3 is brightmap, 4 no texture, the following are custom - if (!alphateston && eff <= 3) + // indices 0-2 match the warping modes, 3 no texture, the following are custom + if (!alphateston && eff <= 2) { - return &mMaterialShadersNAT[passType][eff]; // Non-alphatest shaders are only created for default, warp1+2 and brightmap. The rest won't get used anyway + return &mMaterialShadersNAT[passType][eff]; // Non-alphatest shaders are only created for default, warp1+2. The rest won't get used anyway } else if (eff < (unsigned int)mMaterialShaders[passType].size()) { @@ -160,6 +160,8 @@ static const char *shaderBindings = R"( vec4 uSplitTopPlane; vec4 uSplitBottomPlane; + + vec4 uDetailParms; }; layout(set = 0, binding = 3, std140) uniform StreamUBO { @@ -175,6 +177,8 @@ static const char *shaderBindings = R"( layout(set = 1, binding = 3) uniform sampler2D texture4; layout(set = 1, binding = 4) uniform sampler2D texture5; layout(set = 1, binding = 5) uniform sampler2D texture6; + layout(set = 1, binding = 6) uniform sampler2D texture7; + layout(set = 1, binding = 7) uniform sampler2D texture8; // This must match the PushConstants struct layout(push_constant) uniform PushConstants @@ -205,14 +209,20 @@ static const char *shaderBindings = R"( #define normaltexture texture2 #define speculartexture texture3 #define brighttexture texture4 + #define detailtexture texture5 + #define glowtexture texture6 #elif defined(PBR) #define normaltexture texture2 #define metallictexture texture3 #define roughnesstexture texture4 #define aotexture texture5 #define brighttexture texture6 + #define detailtexture texture7 + #define glowtexture texture8 #else #define brighttexture texture2 + #define detailtexture texture3 + #define glowtexture texture4 #endif #define uObjectColor data[uDataIndex].uObjectColor @@ -237,6 +247,7 @@ static const char *shaderBindings = R"( #define uGradientBottomPlane data[uDataIndex].uGradientBottomPlane #define uSplitTopPlane data[uDataIndex].uSplitTopPlane #define uSplitBottomPlane data[uDataIndex].uSplitBottomPlane + #define uDetailParms data[uDataIndex].uDetailParms #define SUPPORTS_SHADOWMAPS #define VULKAN_COORDINATE_SYSTEM @@ -289,18 +300,25 @@ std::unique_ptr VkShaderManager::LoadFragShader(FString shadername { FString pp_code = LoadPublicShaderLump(material_lump); - if (pp_code.IndexOf("ProcessMaterial") < 0) + if (pp_code.IndexOf("ProcessMaterial") < 0 && pp_code.IndexOf("SetupMaterial") < 0) { // this looks like an old custom hardware shader. // add ProcessMaterial function that calls the older ProcessTexel function - code << "\n" << LoadPrivateShaderLump("shaders/glsl/func_defaultmat.fp").GetChars() << "\n"; - if (pp_code.IndexOf("ProcessTexel") < 0) + if (pp_code.IndexOf("GetTexCoord") >= 0) { - // this looks like an even older custom hardware shader. - // We need to replace the ProcessTexel call to make it work. + code << "\n" << LoadPrivateShaderLump("shaders/glsl/func_defaultmat2.fp").GetChars() << "\n"; + } + else + { + code << "\n" << LoadPrivateShaderLump("shaders/glsl/func_defaultmat.fp").GetChars() << "\n"; + if (pp_code.IndexOf("ProcessTexel") < 0) + { + // this looks like an even older custom hardware shader. + // We need to replace the ProcessTexel call to make it work. - code.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));"); + code.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));"); + } } if (pp_code.IndexOf("ProcessLight") >= 0) @@ -319,6 +337,13 @@ std::unique_ptr VkShaderManager::LoadFragShader(FString shadername { code << "\n" << LoadPrivateShaderLump("shaders/glsl/func_defaultlight.fp").GetChars() << "\n"; } + + // ProcessMaterial must be considered broken because it requires the user to fill in data they possibly cannot know all about. + if (pp_code.IndexOf("ProcessMaterial") >= 0 && pp_code.IndexOf("SetupMaterial") < 0) + { + // This reactivates the old logic and disables all features that cannot be supported with that method. + code.Insert(0, "#define LEGACY_USER_SHADER\n"); + } } else { diff --git a/wadsrc/static/shaders/glsl/func_brightmap.fp b/wadsrc/static/shaders/glsl/func_brightmap.fp deleted file mode 100644 index 30c2a737b8..0000000000 --- a/wadsrc/static/shaders/glsl/func_brightmap.fp +++ /dev/null @@ -1,9 +0,0 @@ - -Material ProcessMaterial() -{ - Material material; - material.Base = getTexel(vTexCoord.st); - material.Normal = ApplyNormalMap(vTexCoord.st); - material.Bright = texture(brighttexture, vTexCoord.st); - return material; -} diff --git a/wadsrc/static/shaders/glsl/func_defaultlight.fp b/wadsrc/static/shaders/glsl/func_defaultlight.fp index 7463528fd2..6738af8f5f 100644 --- a/wadsrc/static/shaders/glsl/func_defaultlight.fp +++ b/wadsrc/static/shaders/glsl/func_defaultlight.fp @@ -1,17 +1,5 @@ -#if defined(BRIGHTMAP) - -vec4 ProcessLight(Material material, vec4 color) -{ - vec4 brightpix = desaturate(material.Bright); - return vec4(min(color.rgb + brightpix.rgb, 1.0), color.a); -} - -#else - vec4 ProcessLight(Material material, vec4 color) { return color; } - -#endif diff --git a/wadsrc/static/shaders/glsl/func_defaultmat.fp b/wadsrc/static/shaders/glsl/func_defaultmat.fp index 0535b8750a..d4c3c99f78 100644 --- a/wadsrc/static/shaders/glsl/func_defaultmat.fp +++ b/wadsrc/static/shaders/glsl/func_defaultmat.fp @@ -1,11 +1,7 @@ -Material ProcessMaterial() +void SetupMaterial(inout Material material) { - Material material; material.Base = ProcessTexel(); material.Normal = ApplyNormalMap(vTexCoord.st); -#if defined(BRIGHTMAP) material.Bright = texture(brighttexture, vTexCoord.st); -#endif - return material; } diff --git a/wadsrc/static/shaders/glsl/func_defaultmat2.fp b/wadsrc/static/shaders/glsl/func_defaultmat2.fp new file mode 100644 index 0000000000..b2beb254e6 --- /dev/null +++ b/wadsrc/static/shaders/glsl/func_defaultmat2.fp @@ -0,0 +1,6 @@ + +void SetupMaterial(inout Material material) +{ + vec2 texCoord = GetTexCoord(); + SetMaterialProps(material, texCoord); +} diff --git a/wadsrc/static/shaders/glsl/func_normal.fp b/wadsrc/static/shaders/glsl/func_normal.fp index fbf40113f9..49dfadd9aa 100644 --- a/wadsrc/static/shaders/glsl/func_normal.fp +++ b/wadsrc/static/shaders/glsl/func_normal.fp @@ -1,8 +1,5 @@ -Material ProcessMaterial() +void SetupMaterial(inout Material material) { - Material material; - material.Base = getTexel(vTexCoord.st); - material.Normal = ApplyNormalMap(vTexCoord.st); - return material; + SetMaterialProps(material, vTexCoord.st); } diff --git a/wadsrc/static/shaders/glsl/func_pbr.fp b/wadsrc/static/shaders/glsl/func_pbr.fp index b0e61d1014..79de3bb857 100644 --- a/wadsrc/static/shaders/glsl/func_pbr.fp +++ b/wadsrc/static/shaders/glsl/func_pbr.fp @@ -1,14 +1,8 @@ -Material ProcessMaterial() +void SetupMaterial(inout Material material) { - Material material; - material.Base = getTexel(vTexCoord.st); - material.Normal = ApplyNormalMap(vTexCoord.st); + SetMaterialProps(material, vTexCoord.st); material.Metallic = texture(metallictexture, vTexCoord.st).r; material.Roughness = texture(roughnesstexture, vTexCoord.st).r; material.AO = texture(aotexture, vTexCoord.st).r; -#if defined(BRIGHTMAP) - material.Bright = texture(brighttexture, vTexCoord.st); -#endif - return material; } diff --git a/wadsrc/static/shaders/glsl/func_spec.fp b/wadsrc/static/shaders/glsl/func_spec.fp index afa1af8435..7de5b1d4ea 100644 --- a/wadsrc/static/shaders/glsl/func_spec.fp +++ b/wadsrc/static/shaders/glsl/func_spec.fp @@ -1,14 +1,8 @@ -Material ProcessMaterial() +void SetupMaterial(inout Material material) { - Material material; - material.Base = getTexel(vTexCoord.st); - material.Normal = ApplyNormalMap(vTexCoord.st); + SetMaterialProps(material, vTexCoord.st); material.Specular = texture(speculartexture, vTexCoord.st).rgb; material.Glossiness = uSpecularMaterial.x; material.SpecularLevel = uSpecularMaterial.y; -#if defined(BRIGHTMAP) - material.Bright = texture(brighttexture, vTexCoord.st); -#endif - return material; } diff --git a/wadsrc/static/shaders/glsl/func_warp1.fp b/wadsrc/static/shaders/glsl/func_warp1.fp index 4214f771f2..dfadf8ada8 100644 --- a/wadsrc/static/shaders/glsl/func_warp1.fp +++ b/wadsrc/static/shaders/glsl/func_warp1.fp @@ -1,5 +1,5 @@ -vec4 ProcessTexel() +vec2 GetTexCoord() { vec2 texCoord = vTexCoord.st; @@ -9,8 +9,11 @@ vec4 ProcessTexel() offset.y = sin(pi * 2.0 * (texCoord.x + timer * 0.125)) * 0.1; offset.x = sin(pi * 2.0 * (texCoord.y + timer * 0.125)) * 0.1; - texCoord += offset; - - return getTexel(texCoord); + return texCoord + offset; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); } diff --git a/wadsrc/static/shaders/glsl/func_warp2.fp b/wadsrc/static/shaders/glsl/func_warp2.fp index 389fad9df7..1ee0f7fd02 100644 --- a/wadsrc/static/shaders/glsl/func_warp2.fp +++ b/wadsrc/static/shaders/glsl/func_warp2.fp @@ -1,5 +1,6 @@ -vec4 ProcessTexel() + +vec2 GetTexCoord() { vec2 texCoord = vTexCoord.st; @@ -9,8 +10,11 @@ vec4 ProcessTexel() offset.y = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.61 + 900.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.36 + 300.0/8192.0)); offset.x = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.49 + 700.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.49 + 1200.0/8192.0)); - texCoord += offset * 0.025; - - return getTexel(texCoord); + return texCoord + offset * 0.025; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); } diff --git a/wadsrc/static/shaders/glsl/func_warp3.fp b/wadsrc/static/shaders/glsl/func_warp3.fp index dceca24773..9edea0004e 100644 --- a/wadsrc/static/shaders/glsl/func_warp3.fp +++ b/wadsrc/static/shaders/glsl/func_warp3.fp @@ -1,5 +1,6 @@ -vec4 ProcessTexel() + +vec2 GetTexCoord() { vec2 texCoord = vTexCoord.st; @@ -10,8 +11,11 @@ vec4 ProcessTexel() offset.y = siny + sin(pi * 2.0 * (texCoord.x + timer * 0.75)) * 0.03; offset.x = siny + sin(pi * 2.0 * (texCoord.x + timer * 0.45)) * 0.02; - texCoord += offset; - - return getTexel(texCoord); + return texCoord + offset; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); } diff --git a/wadsrc/static/shaders/glsl/func_wavex.fp b/wadsrc/static/shaders/glsl/func_wavex.fp index 05ab530284..3b892da9d7 100644 --- a/wadsrc/static/shaders/glsl/func_wavex.fp +++ b/wadsrc/static/shaders/glsl/func_wavex.fp @@ -1,5 +1,5 @@ -vec4 ProcessTexel() +vec2 GetTexCoord() { vec2 texCoord = vTexCoord.st; @@ -7,6 +7,11 @@ vec4 ProcessTexel() texCoord.x += sin(pi * 2.0 * (texCoord.y + timer * 0.125)) * 0.1; - return getTexel(texCoord); + return texCoord; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); } diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 095c16a35f..06011501be 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -22,6 +22,7 @@ struct Material { vec4 Base; vec4 Bright; + vec4 Glow; vec3 Normal; vec3 Specular; float Glossiness; @@ -33,9 +34,16 @@ struct Material vec4 Process(vec4 color); vec4 ProcessTexel(); -Material ProcessMaterial(); +Material ProcessMaterial(); // note that this is deprecated. Use SetupMaterial! +void SetupMaterial(inout Material mat); vec4 ProcessLight(Material mat, vec4 color); vec3 ProcessMaterialLight(Material material, vec3 color); +vec2 GetTexCoord(); + +// These get Or'ed into uTextureMode because it only uses its 3 lowermost bits. +const int TEXF_Brightmap = 0x10000; +const int TEXF_Detailmap = 0x20000; +const int TEXF_Glowmap = 0x40000; //=========================================================================== // @@ -157,7 +165,7 @@ vec4 getTexel(vec2 st) // // Apply texture modes // - switch (uTextureMode) + switch (uTextureMode & 0xffff) { case 1: // TM_STENCIL texel.rgb = vec3(1.0,1.0,1.0); @@ -524,6 +532,30 @@ vec3 ApplyNormalMap(vec2 texcoord) } #endif +//=========================================================================== +// +// Sets the common material properties. +// +//=========================================================================== + +void SetMaterialProps(inout Material material, vec2 texCoord) +{ + material.Base = getTexel(texCoord.st); + material.Normal = ApplyNormalMap(texCoord.st); + + if ((uTextureMode & TEXF_Brightmap) != 0) + material.Bright = texture(brighttexture, texCoord.st); + + if ((uTextureMode & TEXF_Detailmap) != 0) + { + vec4 Detail = texture(detailtexture, texCoord.st * uDetailParms.xy) * uDetailParms.z; + material.Base *= Detail; + } + + if ((uTextureMode & TEXF_Glowmap) != 0) + material.Glow = texture(glowtexture, texCoord.st); +} + //=========================================================================== // // Calculate light @@ -574,8 +606,21 @@ vec4 getLightColor(Material material, float fogdist, float fogfactor) } color = min(color, 1.0); + // these cannot be safely applied by the legacy format where the implementation cannot guarantee that the values are set. +#ifndef LEGACY_USER_SHADER // - // apply brightmaps (or other light manipulation by custom shaders. + // apply glow + // + color.rgb = mix(color.rgb, material.Glow.rgb, material.Glow.a); + + // + // apply brightmaps + // + color.rgb = min(color.rgb + material.Bright.rgb, 1.0); +#endif + + // + // apply other light manipulation by custom shaders, default is a NOP. // color = ProcessLight(material, color); @@ -635,7 +680,23 @@ void main() if (ClipDistanceA.x < 0 || ClipDistanceA.y < 0 || ClipDistanceA.z < 0 || ClipDistanceA.w < 0 || ClipDistanceB.x < 0) discard; #endif +#ifndef LEGACY_USER_SHADER + Material material; + + material.Base = vec4(0.0); + material.Bright = vec4(0.0); + material.Glow = vec4(0.0); + material.Normal = vec3(0.0); + material.Specular = vec3(0.0); + material.Glossiness = 0.0; + material.SpecularLevel = 0.0; + material.Metallic = 0.0; + material.Roughness = 0.0; + material.AO = 0.0; + SetupMaterial(material); +#else Material material = ProcessMaterial(); +#endif vec4 frag = material.Base; #ifndef NO_ALPHATEST @@ -663,9 +724,10 @@ void main() fogfactor = exp2 (uFogDensity * fogdist); } - if (uTextureMode != 7) + if ((uTextureMode & 0xffff) != 7) { frag = getLightColor(material, fogdist, fogfactor); + // // colored fog // @@ -681,7 +743,7 @@ void main() } else // simple 2D (uses the fog color to add a color overlay) { - if (uTextureMode == 7) + if ((uTextureMode & 0xffff) == 7) { float gray = grayscale(frag); vec4 cm = (uObjectColor + gray * (uAddColor - uObjectColor)) * 2;