From c6da4d9312a0add107348f80bdf5857d75a1b31f Mon Sep 17 00:00:00 2001 From: vladislavbelov Date: Sun, 17 Apr 2022 10:10:52 +0000 Subject: [PATCH] Adds a fallback texture to skies to avoid a crash if a sky texture was invalid. This was SVN commit r26800. --- source/graphics/TextureManager.cpp | 69 +++++++++++++++++++++++++++++- source/graphics/TextureManager.h | 5 +++ source/renderer/SkyManager.cpp | 34 +++++++++------ source/renderer/SkyManager.h | 8 +--- 4 files changed, 97 insertions(+), 19 deletions(-) diff --git a/source/graphics/TextureManager.cpp b/source/graphics/TextureManager.cpp index 32fdca13e0..cb0d433a03 100644 --- a/source/graphics/TextureManager.cpp +++ b/source/graphics/TextureManager.cpp @@ -179,6 +179,60 @@ private: CColor m_Color; }; +class CSingleColorTextureCube final : public CPredefinedTexture +{ +public: + CSingleColorTextureCube(const CColor& color, const bool disableGL, + CTextureManagerImpl* textureManager) + : m_Color(color) + { + if (disableGL) + return; + + std::stringstream textureName; + textureName << "SingleColorTextureCube ("; + textureName << "R:" << m_Color.r << ", "; + textureName << "G:" << m_Color.g << ", "; + textureName << "B:" << m_Color.b << ", "; + textureName << "A:" << m_Color.a << ")"; + + std::unique_ptr backendTexture = + g_VideoMode.GetBackendDevice()->CreateTexture( + textureName.str().c_str(), Renderer::Backend::GL::CTexture::Type::TEXTURE_CUBE, + Renderer::Backend::Format::R8G8B8A8_UNORM, + 1, 1, Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, 1); + CreateTexture(std::move(backendTexture), textureManager); + } + + void Upload(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) + { + if (!GetTexture() || !GetTexture()->GetBackendTexture()) + return; + + const SColor4ub color32 = m_Color.AsSColor4ub(); + // Construct 1x1 32-bit texture + const u8 data[4] = + { + color32.R, + color32.G, + color32.B, + color32.A + }; + + for (size_t face = 0; face < 6; ++face) + { + deviceCommandContext->UploadTexture( + GetTexture()->GetBackendTexture(), Renderer::Backend::Format::R8G8B8A8_UNORM, + data, std::size(data), 0, face); + } + } + +private: + CColor m_Color; +}; + class CGradientTexture final : public CPredefinedTexture { public: @@ -310,7 +364,8 @@ public: m_WhiteTexture(CColor(1.0f, 1.0f, 1.0f, 1.0f), disableGL, this), m_TransparentTexture(CColor(0.0f, 0.0f, 0.0f, 0.0f), disableGL, this), m_AlphaGradientTexture( - CColor(1.0f, 1.0f, 1.0f, 0.0f), CColor(1.0f, 1.0f, 1.0f, 1.0f), disableGL, this) + CColor(1.0f, 1.0f, 1.0f, 0.0f), CColor(1.0f, 1.0f, 1.0f, 1.0f), disableGL, this), + m_BlackTextureCube(CColor(0.0f, 0.0f, 0.0f, 1.0f), disableGL, this) { // Allow hotloading of textures RegisterFileReloadFunc(ReloadChangedFileCB, this); @@ -351,6 +406,11 @@ public: return m_AlphaGradientTexture.GetTexture(); } + const CTexturePtr& GetBlackTextureCube() + { + return m_BlackTextureCube.GetTexture(); + } + /** * See CTextureManager::CreateTexture */ @@ -716,6 +776,7 @@ public: m_WhiteTexture.Upload(deviceCommandContext); m_TransparentTexture.Upload(deviceCommandContext); m_AlphaGradientTexture.Upload(deviceCommandContext); + m_BlackTextureCube.Upload(deviceCommandContext); m_PredefinedTexturesUploaded = true; return true; } @@ -833,6 +894,7 @@ private: CSingleColorTexture m_WhiteTexture; CSingleColorTexture m_TransparentTexture; CGradientTexture m_AlphaGradientTexture; + CSingleColorTextureCube m_BlackTextureCube; bool m_PredefinedTexturesUploaded = false; // Cache of all loaded textures @@ -1024,6 +1086,11 @@ const CTexturePtr& CTextureManager::GetAlphaGradientTexture() return m->GetAlphaGradientTexture(); } +const CTexturePtr& CTextureManager::GetBlackTextureCube() +{ + return m->GetBlackTextureCube(); +} + bool CTextureManager::MakeProgress() { return m->MakeProgress(); diff --git a/source/graphics/TextureManager.h b/source/graphics/TextureManager.h index 3686b46366..58a8666fb7 100644 --- a/source/graphics/TextureManager.h +++ b/source/graphics/TextureManager.h @@ -116,6 +116,11 @@ public: */ const CTexturePtr& GetAlphaGradientTexture(); + /** + * Returns a single color RGBA texture cube with CColor(0.0f, 0.0f, 0.0f, 1.0f). + */ + const CTexturePtr& GetBlackTextureCube(); + /** * Work on asynchronous texture loading operations, if any. * Returns true if it did any work. diff --git a/source/renderer/SkyManager.cpp b/source/renderer/SkyManager.cpp index 267fb4e2b4..a11381110f 100644 --- a/source/renderer/SkyManager.cpp +++ b/source/renderer/SkyManager.cpp @@ -49,9 +49,11 @@ SkyManager::SkyManager() void SkyManager::LoadAndUploadSkyTexturesIfNeeded( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) { - if (m_SkyCubeMap) + if (m_SkyTextureCube) return; + m_SkyTextureCube = g_Renderer.GetTextureManager().GetBlackTextureCube(); + GPU_SCOPED_LABEL(deviceCommandContext, "Load Sky Textures"); static const CStrW images[NUMBER_OF_TEXTURES + 1] = { L"front", @@ -115,12 +117,13 @@ void SkyManager::LoadAndUploadSkyTexturesIfNeeded( } } - m_SkyCubeMap = g_VideoMode.GetBackendDevice()->CreateTexture("SkyCubeMap", - Renderer::Backend::GL::CTexture::Type::TEXTURE_CUBE, - Renderer::Backend::Format::R8G8B8A8_UNORM, textures[0].m_Width, textures[0].m_Height, - Renderer::Backend::Sampler::MakeDefaultSampler( - Renderer::Backend::Sampler::Filter::LINEAR, - Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, 1); + std::unique_ptr skyCubeMap = + g_VideoMode.GetBackendDevice()->CreateTexture("SkyCubeMap", + Renderer::Backend::GL::CTexture::Type::TEXTURE_CUBE, + Renderer::Backend::Format::R8G8B8A8_UNORM, textures[0].m_Width, textures[0].m_Height, + Renderer::Backend::Sampler::MakeDefaultSampler( + Renderer::Backend::Sampler::Filter::LINEAR, + Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, 1); std::vector rotated; for (size_t i = 0; i < NUMBER_OF_TEXTURES + 1; ++i) @@ -148,25 +151,32 @@ void SkyManager::LoadAndUploadSkyTexturesIfNeeded( } deviceCommandContext->UploadTexture( - m_SkyCubeMap.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, + skyCubeMap.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, &rotated[0], textures[i].m_DataSize, 0, i); } else { deviceCommandContext->UploadTexture( - m_SkyCubeMap.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, + skyCubeMap.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, data, textures[i].m_DataSize, 0, i); } } + + m_SkyTextureCube = g_Renderer.GetTextureManager().WrapBackendTexture(std::move(skyCubeMap)); /////////////////////////////////////////////////////////////////////////// } +Renderer::Backend::GL::CTexture* SkyManager::GetSkyCube() +{ + return m_SkyTextureCube->GetBackendTexture(); +} + void SkyManager::SetSkySet(const CStrW& newSet) { if (newSet == m_SkySet) return; - m_SkyCubeMap.reset(); + m_SkyTextureCube.reset(); m_SkySet = newSet; } @@ -201,7 +211,7 @@ void SkyManager::RenderSky( return; // Do nothing unless SetSkySet was called - if (m_SkySet.empty() || !m_SkyCubeMap) + if (m_SkySet.empty() || !m_SkyTextureCube) return; if (m_VertexArray.GetNumberOfVertices() == 0) @@ -215,7 +225,7 @@ void SkyManager::RenderSky( skytech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); Renderer::Backend::GL::CShaderProgram* shader = skytech->GetShader(); - shader->BindTexture(str_baseTex, m_SkyCubeMap.get()); + shader->BindTexture(str_baseTex, m_SkyTextureCube->GetBackendTexture()); // Translate so the sky center is at the camera space origin. CMatrix3D translate; diff --git a/source/renderer/SkyManager.h b/source/renderer/SkyManager.h index 9084d79e3c..5e6423f9dd 100644 --- a/source/renderer/SkyManager.h +++ b/source/renderer/SkyManager.h @@ -52,10 +52,7 @@ public: return m_SkySet; } - Renderer::Backend::GL::CTexture* GetSkyCube() - { - return m_SkyCubeMap.get(); - } + Renderer::Backend::GL::CTexture* GetSkyCube(); /** * Set the sky set name. @@ -105,8 +102,7 @@ private: // Sky textures CTexturePtr m_SkyTexture[NUMBER_OF_TEXTURES]; - - std::unique_ptr m_SkyCubeMap; + CTexturePtr m_SkyTextureCube; VertexArray m_VertexArray; VertexArray::Attribute m_AttributePosition;