From 990ce7c6c9c6f84af934159963b3d663b64cbc0e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 19 May 2025 05:55:03 +0200 Subject: [PATCH] Render scene with indexed textures for vid_rendermode 2 --- src/common/engine/fcolormap.h | 13 ++ .../hwrenderer/data/hw_materialstate.h | 2 + .../hwrenderer/data/hw_renderstate.h | 16 ++ .../hwrenderer/data/hw_surfaceuniforms.h | 4 +- src/common/rendering/v_video.h | 2 +- .../descriptorsets/vk_descriptorset.cpp | 18 +++ .../vulkan/descriptorsets/vk_descriptorset.h | 4 + .../rendering/vulkan/shaders/vk_shader.cpp | 1 + .../rendering/vulkan/shaders/vk_shader.h | 2 +- .../vulkan/textures/vk_hwtexture.cpp | 76 +++++---- .../rendering/vulkan/textures/vk_hwtexture.h | 12 +- .../rendering/vulkan/textures/vk_texture.cpp | 109 +++++++++++++ .../rendering/vulkan/textures/vk_texture.h | 19 +++ src/common/rendering/vulkan/vk_levelmesh.cpp | 4 +- .../rendering/vulkan/vk_renderdevice.cpp | 5 +- src/common/rendering/vulkan/vk_renderdevice.h | 2 +- .../rendering/vulkan/vk_renderstate.cpp | 17 ++ src/common/textures/hw_texcontainer.h | 1 + src/common/textures/texture.cpp | 5 +- src/d_main.cpp | 15 +- src/d_main.h | 7 +- src/playsim/dthinker.cpp | 2 +- .../hwrenderer/scene/hw_drawinfo.cpp | 13 ++ src/rendering/swrenderer/r_swcolormaps.h | 8 - .../shaders/binding_struct_definitions.glsl | 4 +- .../static/shaders/scene/layout_shared.glsl | 1 + wadsrc/static/shaders/scene/lightmode.glsl | 145 ++++++++++-------- wadsrc/static/shaders/shaderkey.glsl | 2 +- 28 files changed, 381 insertions(+), 128 deletions(-) diff --git a/src/common/engine/fcolormap.h b/src/common/engine/fcolormap.h index ffb0c136e..999e12934 100644 --- a/src/common/engine/fcolormap.h +++ b/src/common/engine/fcolormap.h @@ -64,4 +64,17 @@ struct FColormap }; +struct FSWColormap +{ + uint8_t* Maps = nullptr; + PalEntry Color = 0xffffffff; + PalEntry Fade = 0xff000000; + int Desaturate = 0; + + struct + { + int textureIndex = -1; + int bindIndex = -1; + } Renderdev; +}; diff --git a/src/common/rendering/hwrenderer/data/hw_materialstate.h b/src/common/rendering/hwrenderer/data/hw_materialstate.h index 3a308eaa8..d552f756a 100644 --- a/src/common/rendering/hwrenderer/data/hw_materialstate.h +++ b/src/common/rendering/hwrenderer/data/hw_materialstate.h @@ -12,6 +12,7 @@ struct FMaterialState int mTranslation = CLAMP_NONE; int mOverrideShader = -1; bool mChanged = false; + bool mPaletteMode = false; GlobalShaderAddr globalShaderAddr = {0, 3, 0}; // null global shader entry, TODO void Reset() @@ -21,6 +22,7 @@ struct FMaterialState mClampMode = CLAMP_NONE; mOverrideShader = -1; mChanged = false; + mPaletteMode = false; globalShaderAddr = {0, 3, 0}; } }; diff --git a/src/common/rendering/hwrenderer/data/hw_renderstate.h b/src/common/rendering/hwrenderer/data/hw_renderstate.h index 236cc9e45..adf2f3e92 100644 --- a/src/common/rendering/hwrenderer/data/hw_renderstate.h +++ b/src/common/rendering/hwrenderer/data/hw_renderstate.h @@ -16,6 +16,7 @@ struct FColormap; class IBuffer; struct HWViewpointUniforms; struct FDynLightData; +struct FSWColormap; enum class LevelMeshDrawType; enum EClearTarget @@ -159,6 +160,9 @@ protected: int mColorMapSpecial; float mColorMapFlash; + bool mPaletteMode = false; + FSWColormap* mSWColormap = nullptr; + SurfaceUniforms mSurfaceUniforms = {}; PalEntry mFogColor; @@ -223,6 +227,8 @@ public: mMaterial.Reset(); mBias.Reset(); mPassType = NORMAL_PASS; + mPaletteMode = false; + mSWColormap = nullptr; mColorMapSpecial = 0; mColorMapFlash = 1; @@ -621,6 +627,16 @@ public: SetMaterial(tex, upscalemask, scaleflags, clampmode, translation.index(), overrideshader, cls); } + void SetPaletteMode(bool palette) + { + mPaletteMode = palette; + } + + void SetSWColormap(FSWColormap* cm) + { + mSWColormap = cm; + } + void SetClipSplit(float bottom, float top) { mSurfaceUniforms.uClipSplit.X = bottom; diff --git a/src/common/rendering/hwrenderer/data/hw_surfaceuniforms.h b/src/common/rendering/hwrenderer/data/hw_surfaceuniforms.h index 01d0fc877..ffe6bd14b 100644 --- a/src/common/rendering/hwrenderer/data/hw_surfaceuniforms.h +++ b/src/common/rendering/hwrenderer/data/hw_surfaceuniforms.h @@ -44,10 +44,10 @@ struct SurfaceUniforms float uAlphaThreshold; int uTextureIndex; - float uDepthFadeThreshold; + int uColormapIndex; int uLightProbeIndex; FVector3 uActorCenter; - float padding2; + float uDepthFadeThreshold; }; struct SurfaceLightUniforms diff --git a/src/common/rendering/v_video.h b/src/common/rendering/v_video.h index 9633f5aab..c8e55a5ce 100644 --- a/src/common/rendering/v_video.h +++ b/src/common/rendering/v_video.h @@ -227,7 +227,7 @@ public: virtual void SetActiveRenderTarget() {} // Get the array index for the material in the textures array accessible from shaders - virtual int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation) { return -1; } + virtual int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation, bool paletteMode) { return -1; } virtual void RenderEnvironmentMap(std::function renderFunc, TArrayView& irradianceMap, TArrayView& prefilterMap) {} virtual void UploadEnvironmentMaps(int cubemapCount, const TArray& irradianceMaps, const TArray& prefilterMaps) {} diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp index 9d1a440c0..51de680be 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp @@ -37,6 +37,7 @@ #include "flatvertices.h" #include "hw_viewpointuniforms.h" #include "v_2ddrawer.h" +#include "fcolormap.h" VkDescriptorSetManager::VkDescriptorSetManager(VulkanRenderDevice* fb) : fb(fb) { @@ -170,6 +171,10 @@ void VkDescriptorSetManager::ResetHWTextureSets() for (auto mat : Materials) mat->DeleteDescriptors(); + for (FSWColormap* colormap : Colormaps) + colormap->Renderdev.bindIndex = -1; + Colormaps.clear(); + Bindless.Writer = WriteDescriptors(); Bindless.NextIndex = 0; @@ -178,6 +183,9 @@ void VkDescriptorSetManager::ResetHWTextureSets() // And slot 1 is always our BRDF LUT texture AddBindlessTextureIndex(fb->GetTextureManager()->GetBrdfLutTextureView(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP)); + + // Slot 2 is always our game palette texture + AddBindlessTextureIndex(fb->GetTextureManager()->GetGamePaletteView(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP)); } void VkDescriptorSetManager::AddMaterial(VkMaterial* texture) @@ -408,3 +416,13 @@ int VkDescriptorSetManager::AddBindlessTextureIndex(VulkanImageView* imageview, Bindless.Writer.AddCombinedImageSampler(Bindless.Set.get(), 0, index, imageview, sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); return index; } + +int VkDescriptorSetManager::GetSWColormapTextureIndex(FSWColormap* colormap) +{ + if (colormap->Renderdev.bindIndex != -1) + return colormap->Renderdev.bindIndex; + + colormap->Renderdev.bindIndex = AddBindlessTextureIndex(fb->GetTextureManager()->GetSWColormapView(colormap), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP)); + Colormaps.push_back(colormap); + return colormap->Renderdev.bindIndex; +} diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h index d85ca280f..8f227c55f 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h @@ -10,6 +10,7 @@ class VulkanRenderDevice; class VkMaterial; class PPTextureInput; class VkPPRenderPassSetup; +struct FSWColormap; class VkDescriptorSetManager { @@ -44,6 +45,8 @@ public: void UpdateBindlessDescriptorSet(); int AddBindlessTextureIndex(VulkanImageView* imageview, VulkanSampler* sampler); + int GetSWColormapTextureIndex(FSWColormap* colormap); + private: void CreateLevelMeshLayout(); void CreateRSBufferLayout(); @@ -115,6 +118,7 @@ private: } ZMinMax; std::list Materials; + std::vector Colormaps; static const int MaxFixedSets = 100; static const int MaxBindlessTextures = 16536; diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index a8dcd9818..aa6f2a6ac 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -464,6 +464,7 @@ void VkShaderManager::BuildDefinesBlock(FString &definesBlock, const char *defin definesBlock << "#define LIGHT_ATTENUATION_INVERSE_SQUARE ((uShaderKey1 & SK1_LIGHTATTENUATIONMODE) != 0)\n"; definesBlock << "#define FOGBALLS ((uShaderKey1 & SK1_FOGBALLS) != 0)\n"; + definesBlock << "#define PALETTEMODE ((uShaderKey1 & SK1_PALETTEMODE) != 0)\n"; definesBlock << "#define USE_DEPTHFADETHRESHOLD ((uShaderKey2 & SK2_USE_DEPTHFADETHRESHOLD) != 0)\n"; definesBlock << "#define NOT_ALPHATEST_ONLY ((uShaderKey2 & SK2_ALPHATEST_ONLY) == 0)\n"; diff --git a/src/common/rendering/vulkan/shaders/vk_shader.h b/src/common/rendering/vulkan/shaders/vk_shader.h index f9a35b9cc..62b0b49ad 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.h +++ b/src/common/rendering/vulkan/shaders/vk_shader.h @@ -105,7 +105,7 @@ public: uint64_t LightMode : 2; // LIGHTMODE_DEFAULT, LIGHTMODE_SOFTWARE, LIGHTMODE_VANILLA, LIGHTMODE_BUILD uint64_t LightBlendMode : 2; // LIGHT_BLEND_CLAMPED , LIGHT_BLEND_COLORED_CLAMP , LIGHT_BLEND_UNCLAMPED uint64_t LightAttenuationMode : 1; // LIGHT_ATTENUATION_LINEAR , LIGHT_ATTENUATION_INVERSE_SQUARE - uint64_t Unused5: 1; + uint64_t PaletteMode: 1; uint64_t FogBalls : 1; // FOGBALLS uint64_t NoFragmentShader : 1; uint64_t DepthFadeThreshold : 1; diff --git a/src/common/rendering/vulkan/textures/vk_hwtexture.cpp b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp index 6a211278d..0c4082d6d 100644 --- a/src/common/rendering/vulkan/textures/vk_hwtexture.cpp +++ b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp @@ -62,17 +62,25 @@ void VkHardwareTexture::Reset() } mImage.Reset(fb); + mPaletteImage.Reset(fb); mDepthStencil.Reset(fb); } } VkTextureImage *VkHardwareTexture::GetImage(FTexture *tex, int translation, int flags) { - if (!mImage.Image) + if (flags & (CTF_Indexed | CTF_IndexedRedIsAlpha)) { - CreateImage(tex, translation, flags); + if (!mPaletteImage.Image) + CreateImage(&mPaletteImage, tex, translation, flags); + return &mPaletteImage; + } + else + { + if (!mImage.Image) + CreateImage(&mImage, tex, translation, flags); + return &mImage; } - return &mImage; } VkTextureImage *VkHardwareTexture::GetDepthStencil(FTexture *tex) @@ -105,7 +113,7 @@ VkTextureImage *VkHardwareTexture::GetDepthStencil(FTexture *tex) return &mDepthStencil; } -void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) +void VkHardwareTexture::CreateImage(VkTextureImage* image, FTexture *tex, int translation, int flags) { if (!tex->isHardwareCanvas()) { @@ -115,7 +123,7 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_CheckOnly); bool indexed = flags & CTF_Indexed; - CreateTexture(texbuffer.mWidth, texbuffer.mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer, !indexed); + CreateTexture(image, texbuffer.mWidth, texbuffer.mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer, !indexed); auto textureManager = fb->GetTextureManager(); @@ -130,7 +138,7 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) // Upload the texture on the main thread, as long as the hwrenderer didn't destroy this hwtexture already. if (textureManager->CheckUploadID(uploadID)) { - UploadTexture(imagedata->mWidth, imagedata->mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, imagedata->mBuffer, !indexed); + UploadTexture(image, imagedata->mWidth, imagedata->mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, imagedata->mBuffer, !indexed); } }); @@ -140,7 +148,7 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) { FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData); bool indexed = flags & CTF_Indexed; - CreateTexture(texbuffer.mWidth, texbuffer.mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer, !indexed); + CreateTexture(image, texbuffer.mWidth, texbuffer.mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer, !indexed); } } else @@ -149,25 +157,25 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) int w = tex->GetWidth(); int h = tex->GetHeight(); - mImage.Image = ImageBuilder() + image->Image = ImageBuilder() .Format(format) .Size(w, h) .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) .DebugName("VkHardwareTexture.mImage") .Create(fb->GetDevice()); - mImage.View = ImageViewBuilder() - .Image(mImage.Image.get(), format) + image->View = ImageViewBuilder() + .Image(image->Image.get(), format) .DebugName("VkHardwareTexture.mImageView") .Create(fb->GetDevice()); VkImageTransition() - .AddImage(&mImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true) + .AddImage(image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true) .Execute(fb->GetCommands()->GetTransferCommands()); } } -void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap) +void VkHardwareTexture::CreateTexture(VkTextureImage* image, int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap) { if (w <= 0 || h <= 0) throw CVulkanError("Trying to create zero size texture"); @@ -189,22 +197,22 @@ void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat form stagingBuffer->Unmap(); - mImage.Image = ImageBuilder() + image->Image = ImageBuilder() .Format(format) .Size(w, h, !mipmap ? 1 : GetMipLevels(w, h)) .Usage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) .DebugName("VkHardwareTexture.mImage") .Create(fb->GetDevice()); - mImage.View = ImageViewBuilder() - .Image(mImage.Image.get(), format) + image->View = ImageViewBuilder() + .Image(image->Image.get(), format) .DebugName("VkHardwareTexture.mImageView") .Create(fb->GetDevice()); auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); VkImageTransition() - .AddImage(&mImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true) + .AddImage(image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true) .Execute(cmdbuffer); VkBufferImageCopy region = {}; @@ -213,9 +221,9 @@ void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat form region.imageExtent.depth = 1; region.imageExtent.width = w; region.imageExtent.height = h; - cmdbuffer->copyBufferToImage(stagingBuffer->buffer, mImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + cmdbuffer->copyBufferToImage(stagingBuffer->buffer, image->Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - if (mipmap) mImage.GenerateMipmaps(cmdbuffer); + if (mipmap) image->GenerateMipmaps(cmdbuffer); // If we queued more than 64 MB of data already: wait until the uploads finish before continuing fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); @@ -223,7 +231,7 @@ void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat form fb->GetCommands()->WaitForCommands(false, true); } -void VkHardwareTexture::UploadTexture(int w, int h, int pixelsize, VkFormat format, const void* pixels, bool mipmap) +void VkHardwareTexture::UploadTexture(VkTextureImage* image, int w, int h, int pixelsize, VkFormat format, const void* pixels, bool mipmap) { if (w <= 0 || h <= 0) throw CVulkanError("Trying to create zero size texture"); @@ -243,7 +251,7 @@ void VkHardwareTexture::UploadTexture(int w, int h, int pixelsize, VkFormat form auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); VkImageTransition() - .AddImage(&mImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true) + .AddImage(image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true) .Execute(cmdbuffer); VkBufferImageCopy region = {}; @@ -252,9 +260,9 @@ void VkHardwareTexture::UploadTexture(int w, int h, int pixelsize, VkFormat form region.imageExtent.depth = 1; region.imageExtent.width = w; region.imageExtent.height = h; - cmdbuffer->copyBufferToImage(stagingBuffer->buffer, mImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + cmdbuffer->copyBufferToImage(stagingBuffer->buffer, image->Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - if (mipmap) mImage.GenerateMipmaps(cmdbuffer); + if (mipmap) image->GenerateMipmaps(cmdbuffer); // If we queued more than 64 MB of data already: wait until the uploads finish before continuing fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); @@ -323,7 +331,7 @@ unsigned int VkHardwareTexture::CreateTexture(unsigned char * buffer, int w, int { // CreateTexture is used by the software renderer to create a screen output but without any screen data. if (buffer) - CreateTexture(w, h, mTexelsize, mTexelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM, buffer, mipmap); + CreateTexture(&mImage, w, h, mTexelsize, mTexelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM, buffer, mipmap); return 0; } @@ -409,9 +417,19 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState clampmode = base->GetClampMode(clampmode); + int paletteFlags = 0; + if (state.mPaletteMode) + { + paletteFlags |= CTF_Indexed; // To do: may need to implement CTF_IndexedRedIsAlpha too for the "style.Flags & STYLEF_RedIsAlpha" case + + // We can't do linear filtering for indexed textures + if (clampmode < CLAMP_NOFILTER) + clampmode += CLAMP_NOFILTER; + } + for (auto& set : mDescriptorSets) { - if (set.clampmode == clampmode && set.remap == translationp && set.globalShaderAddr == globalShaderAddr) return set; + if (set.clampmode == clampmode && set.remap == translationp && set.globalShaderAddr == globalShaderAddr && set.indexed == state.mPaletteMode) return set; } auto globalshader = GetGlobalShader(globalShaderAddr); @@ -421,7 +439,7 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState MaterialLayerInfo *layer; auto systex = static_cast(GetLayer(0, state.mTranslation, &layer)); - auto systeximage = systex->GetImage(layer->layerTexture, state.mTranslation, layer->scaleFlags); + auto systeximage = systex->GetImage(layer->layerTexture, state.mTranslation, layer->scaleFlags | paletteFlags); int bindlessIndex = descriptors->AddBindlessTextureIndex(systeximage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(0), clampmode)); if (!(layer->scaleFlags & CTF_Indexed)) @@ -429,7 +447,7 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState for (int i = 1; i < numLayersMat; i++) { auto syslayer = static_cast(GetLayer(i, 0, &layer)); - auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags); + auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags | paletteFlags); descriptors->AddBindlessTextureIndex(syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode)); } @@ -441,7 +459,7 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState if (texture != nullptr) { VkHardwareTexture *tex = static_cast(texture.get()->GetHardwareTexture(0, 0)); - VkTextureImage *img = tex->GetImage(texture.get(), 0, 0); + VkTextureImage *img = tex->GetImage(texture.get(), 0, paletteFlags); descriptors->AddBindlessTextureIndex(img->View.get(), fb->GetSamplerManager()->Get(globalshader->CustomShaderTextureSampling[i], clampmode)); } i++; @@ -453,11 +471,11 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState for (int i = 1; i < 3; i++) { auto syslayer = static_cast(GetLayer(i, translation, &layer)); - auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags); + auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags | paletteFlags); descriptors->AddBindlessTextureIndex(syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode)); } } - mDescriptorSets.emplace_back(clampmode, translationp, bindlessIndex, globalShaderAddr); + mDescriptorSets.emplace_back(clampmode, translationp, bindlessIndex, globalShaderAddr, state.mPaletteMode); return mDescriptorSets.back(); } diff --git a/src/common/rendering/vulkan/textures/vk_hwtexture.h b/src/common/rendering/vulkan/textures/vk_hwtexture.h index 4dd924bf8..b212f46ce 100644 --- a/src/common/rendering/vulkan/textures/vk_hwtexture.h +++ b/src/common/rendering/vulkan/textures/vk_hwtexture.h @@ -46,13 +46,13 @@ public: std::list::iterator it; private: - void CreateImage(FTexture *tex, int translation, int flags); + void CreateImage(VkTextureImage* image, FTexture *tex, int translation, int flags); - void CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap); - void UploadTexture(int w, int h, int pixelsize, VkFormat format, const void* pixels, bool mipmap); + void CreateTexture(VkTextureImage* image, int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap); + void UploadTexture(VkTextureImage* image, int w, int h, int pixelsize, VkFormat format, const void* pixels, bool mipmap); static int GetMipLevels(int w, int h); - VkTextureImage mImage; + VkTextureImage mImage, mPaletteImage; int mTexelsize = 4; VkTextureImage mDepthStencil; @@ -80,13 +80,15 @@ private: intptr_t remap; int bindlessIndex; GlobalShaderAddr globalShaderAddr; + bool indexed; - DescriptorEntry(int cm, intptr_t f, int index, GlobalShaderAddr addr) + DescriptorEntry(int cm, intptr_t f, int index, GlobalShaderAddr addr, bool paletteMode) { clampmode = cm; remap = f; bindlessIndex = index; globalShaderAddr = addr; + indexed = paletteMode; } }; diff --git a/src/common/rendering/vulkan/textures/vk_texture.cpp b/src/common/rendering/vulkan/textures/vk_texture.cpp index 5fe88603e..52e9111f0 100644 --- a/src/common/rendering/vulkan/textures/vk_texture.cpp +++ b/src/common/rendering/vulkan/textures/vk_texture.cpp @@ -26,11 +26,13 @@ #include "vk_renderbuffers.h" #include "vulkan/vk_postprocess.h" #include "hw_cvars.h" +#include "fcolormap.h" VkTextureManager::VkTextureManager(VulkanRenderDevice* fb) : fb(fb) { CreateNullTexture(); CreateBrdfLutTexture(); + CreateGamePalette(); CreateShadowmap(); CreateLightmap(); CreateIrradiancemap(); @@ -231,6 +233,113 @@ void VkTextureManager::CreateBrdfLutTexture() .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); } +void VkTextureManager::CreateGamePalette() +{ + GamePalette = ImageBuilder() + .Format(VK_FORMAT_B8G8R8A8_UNORM) + .Size(256, 1) + .Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) + .DebugName("VkDescriptorSetManager.GamePalette") + .Create(fb->GetDevice()); + + GamePaletteView = ImageViewBuilder() + .Image(GamePalette.get(), VK_FORMAT_B8G8R8A8_UNORM) + .DebugName("VkDescriptorSetManager.GamePaletteView") + .Create(fb->GetDevice()); +} + +void VkTextureManager::SetGamePalette() +{ + auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); + + PipelineBarrier() + .AddImage(GamePalette.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT) + .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + + auto stagingBuffer = BufferBuilder() + .Size(256 * 4) + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .DebugName("VkDescriptorSetManager.GamePaletteStagingBuffer") + .Create(fb->GetDevice()); + + void* data = stagingBuffer->Map(0, 256 * 4); + memcpy(data, GPalette.BaseColors, 256 * 4); + stagingBuffer->Unmap(); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = 1; + region.imageExtent.depth = 1; + region.imageExtent.width = 256; + region.imageExtent.height = 1; + cmdbuffer->copyBufferToImage(stagingBuffer->buffer, GamePalette->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); + + PipelineBarrier() + .AddImage(GamePalette.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT) + .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); +} + +VulkanImageView* VkTextureManager::GetSWColormapView(FSWColormap* colormap) +{ + if (colormap->Renderdev.textureIndex != -1) + return Colormaps[colormap->Renderdev.textureIndex].View.get(); + + SWColormapTexture tex; + + tex.Texture = ImageBuilder() + .Format(VK_FORMAT_B8G8R8A8_UNORM) + .Size(256, 32) + .Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) + .DebugName("VkDescriptorSetManager.SWColormap") + .Create(fb->GetDevice()); + + tex.View = ImageViewBuilder() + .Image(tex.Texture.get(), VK_FORMAT_B8G8R8A8_UNORM) + .DebugName("VkDescriptorSetManager.SWColormapView") + .Create(fb->GetDevice()); + + auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); + + PipelineBarrier() + .AddImage(tex.Texture.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT) + .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + + auto stagingBuffer = BufferBuilder() + .Size(256 * 32 * sizeof(uint32_t)) + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .DebugName("VkDescriptorSetManager.SWColormapStagingBuffer") + .Create(fb->GetDevice()); + + const uint8_t* src = colormap->Maps; + uint32_t* data = static_cast(stagingBuffer->Map(0, 256 * 32 * sizeof(uint32_t))); + for (int i = 0; i < 256 * 32; i++) + { + data[i] = GPalette.BaseColors[src[i]].d; + } + stagingBuffer->Unmap(); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = 1; + region.imageExtent.depth = 1; + region.imageExtent.width = 256; + region.imageExtent.height = 32; + cmdbuffer->copyBufferToImage(stagingBuffer->buffer, tex.Texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); + + PipelineBarrier() + .AddImage(tex.Texture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT) + .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + colormap->Renderdev.textureIndex = Colormaps.size(); + Colormaps.push_back(std::move(tex)); + + return Colormaps[colormap->Renderdev.textureIndex].View.get(); +} + void VkTextureManager::CreateShadowmap() { Shadowmap.Image = ImageBuilder() diff --git a/src/common/rendering/vulkan/textures/vk_texture.h b/src/common/rendering/vulkan/textures/vk_texture.h index f15f228a3..25ac45529 100644 --- a/src/common/rendering/vulkan/textures/vk_texture.h +++ b/src/common/rendering/vulkan/textures/vk_texture.h @@ -16,6 +16,7 @@ class VkPPTexture; class VkTextureImage; enum class PPTextureType; class PPTexture; +struct FSWColormap; class VkTextureManager { @@ -32,6 +33,8 @@ public: void CreatePrefiltermap(int size, int count, const TArray& data); void DownloadLightmap(int arrayIndex, uint16_t* buffer); + void SetGamePalette(); + VkTextureImage* GetTexture(const PPTextureType& type, PPTexture* tex); VkFormat GetTextureFormat(PPTexture* texture); @@ -47,6 +50,11 @@ public: VulkanImage* GetBrdfLutTexture() { return BrdfLutTexture.get(); } VulkanImageView* GetBrdfLutTextureView() { return BrdfLutTextureView.get(); } + VulkanImage* GetGamePalette() { return GamePalette.get(); } + VulkanImageView* GetGamePaletteView() { return GamePaletteView.get(); } + + VulkanImageView* GetSWColormapView(FSWColormap* colormap); + int GetHWTextureCount() { return (int)Textures.size(); } VkTextureImage Shadowmap; @@ -70,6 +78,7 @@ public: private: void CreateNullTexture(); void CreateBrdfLutTexture(); + void CreateGamePalette(); void CreateShadowmap(); void CreateLightmap(); void CreateIrradiancemap(); @@ -92,6 +101,16 @@ private: std::unique_ptr BrdfLutTexture; std::unique_ptr BrdfLutTextureView; + std::unique_ptr GamePalette; + std::unique_ptr GamePaletteView; + + struct SWColormapTexture + { + std::unique_ptr Texture; + std::unique_ptr View; + }; + std::vector Colormaps; + int NextUploadID = 1; std::unordered_map PendingUploads; diff --git a/src/common/rendering/vulkan/vk_levelmesh.cpp b/src/common/rendering/vulkan/vk_levelmesh.cpp index 9be513a4d..ecd5ed244 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.cpp +++ b/src/common/rendering/vulkan/vk_levelmesh.cpp @@ -844,7 +844,7 @@ void VkLevelMeshUploader::UploadSurfaces() if (surface->Texture) { auto mat = FMaterial::ValidateTexture(surface->Texture, 0); - info.TextureIndex = Mesh->fb->GetBindlessTextureIndex(mat, CLAMP_NONE, 0); + info.TextureIndex = Mesh->fb->GetBindlessTextureIndex(mat, CLAMP_NONE, 0, false); } else { @@ -873,7 +873,7 @@ void VkLevelMeshUploader::UploadUniforms() auto source = material.mMaterial->Source(); surfaceUniforms.uSpecularMaterial = { source->GetGlossiness(), source->GetSpecularLevel() }; surfaceUniforms.uDepthFadeThreshold = source->GetDepthFadeThreshold(); - surfaceUniforms.uTextureIndex = Mesh->fb->GetBindlessTextureIndex(material.mMaterial, material.mClampMode, material.mTranslation); + surfaceUniforms.uTextureIndex = Mesh->fb->GetBindlessTextureIndex(material.mMaterial, material.mClampMode, material.mTranslation, false); } else { diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index 604537161..cd3fb7167 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -482,6 +482,8 @@ void VulkanRenderDevice::UpdatePalette() { if (mPostprocess) mPostprocess->ClearTonemapPalette(); + + mTextureManager->SetGamePalette(); } FTexture *VulkanRenderDevice::WipeStartScreen() @@ -748,7 +750,7 @@ void VulkanRenderDevice::DownloadLightmap(int arrayIndex, uint16_t* buffer) mTextureManager->DownloadLightmap(arrayIndex, buffer); } -int VulkanRenderDevice::GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation) +int VulkanRenderDevice::GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation, bool paletteMode) { GlobalShaderAddr addr; auto globalshader = GetGlobalShader(material->GetShaderIndex(), nullptr, addr); @@ -757,6 +759,7 @@ int VulkanRenderDevice::GetBindlessTextureIndex(FMaterial* material, int clampmo materialState.mMaterial = material; materialState.mClampMode = clampmode; materialState.mTranslation = translation; + materialState.mPaletteMode = paletteMode; if(addr.type == 1 && *globalshader) { // handle per-map global shaders diff --git a/src/common/rendering/vulkan/vk_renderdevice.h b/src/common/rendering/vulkan/vk_renderdevice.h index 16757cdf6..c56ef5b10 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.h +++ b/src/common/rendering/vulkan/vk_renderdevice.h @@ -95,7 +95,7 @@ public: void WaitForCommands(bool finish) override; - int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation) override; + int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation, bool paletteMode) override; int GetLevelMeshPipelineID(const MeshApplyData& applyData, const SurfaceUniforms& surfaceUniforms, const FMaterialState& material) override; void DownloadLightmap(int arrayIndex, uint16_t* buffer) override; diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index 701e641c4..cd08a2af9 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -343,6 +343,8 @@ void VkRenderState::ApplyRenderPass(int dt) pipelineKey.ShaderKey.LightBlendMode = (level.info ? static_cast(level.info->lightblendmode) : 0); pipelineKey.ShaderKey.LightAttenuationMode = (level.info ? static_cast(level.info->lightattenuationmode) : 0); + pipelineKey.ShaderKey.PaletteMode = mPaletteMode; + // Is this the one we already have? bool inRenderPass = mCommandBuffer; bool changingPipeline = (!inRenderPass) || (pipelineKey != mPipelineKey); @@ -441,6 +443,21 @@ void VkRenderState::ApplySurfaceUniforms() else mSurfaceUniforms.timer = 0.0f; + if (mMaterial.mPaletteMode != mPaletteMode) + { + mMaterial.mPaletteMode = mPaletteMode; + mMaterial.mChanged = true; + } + + if (mPaletteMode && mSWColormap) + { + mSurfaceUniforms.uColormapIndex = fb->GetDescriptorSetManager()->GetSWColormapTextureIndex(mSWColormap); + } + else + { + mSurfaceUniforms.uColormapIndex = 0; + } + if (mMaterial.mChanged) { if (mMaterial.mMaterial) diff --git a/src/common/textures/hw_texcontainer.h b/src/common/textures/hw_texcontainer.h index e8777b00e..de2eb65f9 100644 --- a/src/common/textures/hw_texcontainer.h +++ b/src/common/textures/hw_texcontainer.h @@ -15,6 +15,7 @@ enum ECreateTexBufferFlags CTF_Indexed = 4, // Tell the backend to create an indexed texture. CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures. CTF_ProcessData = 16, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture. + CTF_IndexedRedIsAlpha = 32, // Tell the backend to create an indexed alpha texture. }; class FHardwareTextureContainer diff --git a/src/common/textures/texture.cpp b/src/common/textures/texture.cpp index 1155c64dc..27e95614c 100644 --- a/src/common/textures/texture.cpp +++ b/src/common/textures/texture.cpp @@ -332,12 +332,13 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags) std::unique_lock lock(mutex); FTextureBuffer result; - if (flags & CTF_Indexed) + if (flags & (CTF_Indexed | CTF_IndexedRedIsAlpha)) { // Indexed textures will never be translated and never be scaled. int w = GetWidth(), h = GetHeight(); - auto store = Get8BitPixels(false); + bool alpha = !!(flags & CTF_IndexedRedIsAlpha); + auto store = Get8BitPixels(alpha); const uint8_t* p = store.Data(); result.mBuffer = new uint8_t[w * h]; diff --git a/src/d_main.cpp b/src/d_main.cpp index 32b50caed..0c863b49d 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -241,9 +241,9 @@ CUSTOM_CVAR(Int, vid_rendermode, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOIN { self = 4; } - else if (self == 2 || self == 3) + else if (self == 3) { - self = self - 2; // softpoly to software + self = 4; // map old softpoly truecolor to hwrenderer } if (usergame) @@ -405,7 +405,7 @@ void D_Render(std::function action, bool interpolate) for (auto Level : AllLevels()) { // Check for the presence of dynamic lights at the start of the frame once. - if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4) || Level->lightmaps) + if ((gl_lights && V_IsHardwareRenderer()) || (r_dynlights && V_IsSoftwareRenderer()) || Level->lightmaps) { Level->HasDynamicLights = Level->lights || Level->lightmaps; } @@ -987,7 +987,7 @@ void D_Display () // No wipes when in a stereo3D VR mode else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE && gamestate != GS_TITLELEVEL) { - if (vr_mode == 0 || vid_rendermode != 4) + if (vr_mode == 0 || V_IsSoftwareRenderer()) { // save the current screen if about to wipe wipestart = screen->WipeStartScreen(); @@ -3320,11 +3320,8 @@ static int D_InitGame(const FIWADInfo* iwad_info, std::vector& allw screen->CompileNextShader(); if (StartScreen != nullptr) StartScreen->Render(); } - else - { - // Update screen palette when restarting - screen->UpdatePalette(); - } + + screen->UpdatePalette(); // Base systems have been inited; enable cvar callbacks FBaseCVar::EnableCallbacks (); diff --git a/src/d_main.h b/src/d_main.h index b5a08750c..661e2ab1e 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -161,7 +161,12 @@ constexpr int vid_rendermode = 4; inline bool V_IsHardwareRenderer() { - return vid_rendermode == 4; + return vid_rendermode == 4 || vid_rendermode == 2; +} + +inline bool V_IsSoftwareRenderer() +{ + return !V_IsHardwareRenderer(); } inline bool V_IsTrueColor() diff --git a/src/playsim/dthinker.cpp b/src/playsim/dthinker.cpp index dce8f8f00..635f27e87 100644 --- a/src/playsim/dthinker.cpp +++ b/src/playsim/dthinker.cpp @@ -111,7 +111,7 @@ void FThinkerCollection::RunThinkers(FLevelLocals *Level) ThinkCycles.Clock(); bool dolights; - if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4) || Level->lightmaps) + if ((gl_lights && V_IsHardwareRenderer()) || (r_dynlights && V_IsSoftwareRenderer()) || Level->lightmaps) { dolights = true;// Level->lights || (Level->flags3 & LEVEL3_LIGHTCREATED) || Level->lightmaps; } diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index 7a17a52e8..19ce76d74 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -48,6 +48,8 @@ #include "actorinlines.h" #include "g_levellocals.h" #include "hw_lighting.h" +#include "d_main.h" +#include "swrenderer/r_swcolormaps.h" EXTERN_CVAR(Float, r_visibility) EXTERN_CVAR(Int, lm_background_updates); @@ -783,6 +785,15 @@ void HWDrawInfo::RenderScene(FRenderState &state) UpdateLightmaps(); state.SetLightMode((int)lightmode); + + if (!V_IsTrueColor()) + { + state.SetPaletteMode(!V_IsTrueColor()); + + FColormap cm; + cm.Clear(); + state.SetSWColormap(GetColorTable(cm)); + } state.SetDepthMask(true); @@ -829,6 +840,8 @@ void HWDrawInfo::RenderScene(FRenderState &state) state.SetDepthFunc(DF_LEqual); DrawDecals(state, Decals[0]); + state.SetPaletteMode(false); + RenderAll.Unclock(); } diff --git a/src/rendering/swrenderer/r_swcolormaps.h b/src/rendering/swrenderer/r_swcolormaps.h index 73b484c9f..a12403fb9 100644 --- a/src/rendering/swrenderer/r_swcolormaps.h +++ b/src/rendering/swrenderer/r_swcolormaps.h @@ -3,14 +3,6 @@ #include "g_levellocals.h" -struct FSWColormap -{ - uint8_t *Maps = nullptr; - PalEntry Color = 0xffffffff; - PalEntry Fade = 0xff000000; - int Desaturate = 0; -}; - struct FDynamicColormap : FSWColormap { void ChangeFade (PalEntry fadecolor); diff --git a/wadsrc/static/shaders/binding_struct_definitions.glsl b/wadsrc/static/shaders/binding_struct_definitions.glsl index fdb4dd660..b9279fa3f 100644 --- a/wadsrc/static/shaders/binding_struct_definitions.glsl +++ b/wadsrc/static/shaders/binding_struct_definitions.glsl @@ -114,10 +114,10 @@ struct SurfaceUniforms float uAlphaThreshold; int uTextureIndex; - float uDepthFadeThreshold; + int uColormapIndex; int uLightProbeIndex; vec3 uActorCenter; - float padding2; + float uDepthFadeThreshold; }; struct SurfaceLightUniforms diff --git a/wadsrc/static/shaders/scene/layout_shared.glsl b/wadsrc/static/shaders/scene/layout_shared.glsl index b7f7a4e24..e4351a049 100644 --- a/wadsrc/static/shaders/scene/layout_shared.glsl +++ b/wadsrc/static/shaders/scene/layout_shared.glsl @@ -55,6 +55,7 @@ #define uLightDist data[uDataIndex].uLightDist #define uAlphaThreshold data[uDataIndex].uAlphaThreshold #define uTextureIndex data[uDataIndex].uTextureIndex +#define uColormapIndex data[uDataIndex].uColormapIndex #define uDepthFadeThreshold data[uDataIndex].uDepthFadeThreshold #define uActorCenter data[uDataIndex].uActorCenter #define uLightProbeIndex data[uDataIndex].uLightProbeIndex diff --git a/wadsrc/static/shaders/scene/lightmode.glsl b/wadsrc/static/shaders/scene/lightmode.glsl index f8fcbb34d..76c01b255 100644 --- a/wadsrc/static/shaders/scene/lightmode.glsl +++ b/wadsrc/static/shaders/scene/lightmode.glsl @@ -22,75 +22,96 @@ vec4 getLightColor(Material material) { - vec4 color; - if (LIGHTMODE_DEFAULT) - color = Lightmode_Default(); - else if (LIGHTMODE_SOFTWARE) - color = Lightmode_Software(); - else if (LIGHTMODE_VANILLA) - color = Lightmode_Vanilla(); - else if (LIGHTMODE_BUILD) - color = Lightmode_Build(); - - // - // handle glowing walls - // - if (uGlowTopColor.a > 0.0 && glowdist.x < uGlowTopColor.a) + if (PALETTEMODE) { - color.rgb += desaturate(uGlowTopColor * (1.0 - glowdist.x / uGlowTopColor.a)).rgb; - } - if (uGlowBottomColor.a > 0.0 && glowdist.y < uGlowBottomColor.a) - { - color.rgb += desaturate(uGlowBottomColor * (1.0 - glowdist.y / uGlowBottomColor.a)).rgb; - } - color = min(color, 1.0); + int color = int(material.Base.r * 255.0 + 0.5); - // these cannot be safely applied by the legacy format where the implementation cannot guarantee that the values are set. -#if !defined LEGACY_USER_SHADER && !defined NO_LAYERS - // - // 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 lightmaps - // - if (vLightmap.z >= 0.0) - { - color.rgb += texture(LightMap, vLightmap).rgb; - } - - // - // apply dynamic lights - // - vec4 frag = vec4(ProcessMaterialLight(material, color.rgb), material.Base.a * vColor.a); - - // - // colored fog - // - if (FOG_AFTER_LIGHTS) - { - // calculate fog factor - float fogdist; - if (FOG_RADIAL) - fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz)); + // z is the depth in view space, positive going into the screen + float z; + if (SWLIGHT_RADIAL) + z = distance(pixelpos.xyz, uCameraPos.xyz); else - fogdist = max(16.0, pixelpos.w); - float fogfactor = exp2 (uFogDensity * fogdist); + z = pixelpos.w; - frag = vec4(mix(uFogColor.rgb, frag.rgb, fogfactor), frag.a); + float L = uLightLevel * 255.0; + float vis = min(uGlobVis / z, 24.0 / 32.0); + float shade = 2.0 - (L + 12.0) / 128.0; + int light = max(int((shade - vis) * 32), 0); + + return vec4(texelFetch(textures[uColormapIndex], ivec2(color, light), 0).rgb, 1.0); } + else + { + vec4 color; + if (LIGHTMODE_DEFAULT) + color = Lightmode_Default(); + else if (LIGHTMODE_SOFTWARE) + color = Lightmode_Software(); + else if (LIGHTMODE_VANILLA) + color = Lightmode_Vanilla(); + else if (LIGHTMODE_BUILD) + color = Lightmode_Build(); - if (FOGBALLS) - frag = ProcessFogBalls(frag); + // + // handle glowing walls + // + if (uGlowTopColor.a > 0.0 && glowdist.x < uGlowTopColor.a) + { + color.rgb += desaturate(uGlowTopColor * (1.0 - glowdist.x / uGlowTopColor.a)).rgb; + } + if (uGlowBottomColor.a > 0.0 && glowdist.y < uGlowBottomColor.a) + { + color.rgb += desaturate(uGlowBottomColor * (1.0 - glowdist.y / uGlowBottomColor.a)).rgb; + } + color = min(color, 1.0); - return frag; + // these cannot be safely applied by the legacy format where the implementation cannot guarantee that the values are set. + #if !defined LEGACY_USER_SHADER && !defined NO_LAYERS + // + // 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 lightmaps + // + if (vLightmap.z >= 0.0) + { + color.rgb += texture(LightMap, vLightmap).rgb; + } + + // + // apply dynamic lights + // + vec4 frag = vec4(ProcessMaterialLight(material, color.rgb), material.Base.a * vColor.a); + + // + // colored fog + // + if (FOG_AFTER_LIGHTS) + { + // calculate fog factor + float fogdist; + if (FOG_RADIAL) + fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz)); + else + fogdist = max(16.0, pixelpos.w); + float fogfactor = exp2 (uFogDensity * fogdist); + + frag = vec4(mix(uFogColor.rgb, frag.rgb, fogfactor), frag.a); + } + + if (FOGBALLS) + frag = ProcessFogBalls(frag); + + return frag; + } } // The color of the fragment if it is fully occluded by ambient lighting diff --git a/wadsrc/static/shaders/shaderkey.glsl b/wadsrc/static/shaders/shaderkey.glsl index 6a853f52a..8697bbffd 100644 --- a/wadsrc/static/shaders/shaderkey.glsl +++ b/wadsrc/static/shaders/shaderkey.glsl @@ -37,7 +37,7 @@ #define SK1_LIGHT_LIGHT_BLEND_COLORED_CLAMP 1 #define SK1_LIGHT_BLEND_UNCLAMPED 2 #define SK1_LIGHTATTENUATIONMODE (1 << 29) -//#define SK1_USE_LEVELMESH (1 << 30) +#define SK1_PALETTEMODE (1 << 30) #define SK1_FOGBALLS (1 << 31) //#define SK2_NOFRAGMENTSHADER (1 << 0)