LCOV - code coverage report
Current view: top level - source/renderer - SkyManager.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 5 155 3.2 %
Date: 2023-01-19 00:18:29 Functions: 3 10 30.0 %

          Line data    Source code
       1             : /* Copyright (C) 2023 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "renderer/SkyManager.h"
      21             : 
      22             : #include "graphics/LightEnv.h"
      23             : #include "graphics/ShaderManager.h"
      24             : #include "graphics/Terrain.h"
      25             : #include "graphics/TextureManager.h"
      26             : #include "lib/bits.h"
      27             : #include "lib/tex/tex.h"
      28             : #include "maths/MathUtil.h"
      29             : #include "ps/CLogger.h"
      30             : #include "ps/ConfigDB.h"
      31             : #include "ps/CStr.h"
      32             : #include "ps/CStrInternStatic.h"
      33             : #include "ps/Filesystem.h"
      34             : #include "ps/Game.h"
      35             : #include "ps/VideoMode.h"
      36             : #include "renderer/backend/IDevice.h"
      37             : #include "renderer/Renderer.h"
      38             : #include "renderer/SceneRenderer.h"
      39             : #include "renderer/RenderingOptions.h"
      40             : 
      41             : #include <algorithm>
      42             : 
      43           6 : SkyManager::SkyManager()
      44           6 :     : m_VertexArray(Renderer::Backend::IBuffer::Type::VERTEX, false)
      45             : {
      46           6 :     CFG_GET_VAL("showsky", m_SkyVisible);
      47           6 : }
      48             : 
      49           0 : void SkyManager::LoadAndUploadSkyTexturesIfNeeded(
      50             :     Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
      51             : {
      52           0 :     if (m_VertexArray.GetNumberOfVertices() == 0)
      53           0 :         CreateSkyCube();
      54             : 
      55           0 :     if (m_SkyTextureCube)
      56           0 :         return;
      57             : 
      58           0 :     m_SkyTextureCube = g_Renderer.GetTextureManager().GetBlackTextureCube();
      59             : 
      60           0 :     GPU_SCOPED_LABEL(deviceCommandContext, "Load Sky Textures");
      61             :     static const CStrW images[NUMBER_OF_TEXTURES + 1] = {
      62             :         L"front",
      63             :         L"back",
      64             :         L"top",
      65             :         L"top",
      66             :         L"right",
      67             :         L"left"
      68           0 :     };
      69             : 
      70             :     /*for (size_t i = 0; i < ARRAY_SIZE(m_SkyTexture); ++i)
      71             :     {
      72             :         VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(s_imageNames[i])+L".dds");
      73             : 
      74             :         CTextureProperties textureProps(path);
      75             :         textureProps.SetWrap(GL_CLAMP_TO_EDGE);
      76             :         CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
      77             :         texture->Prefetch();
      78             :         m_SkyTexture[i] = texture;
      79             :     }*/
      80             : 
      81             :     ///////////////////////////////////////////////////////////////////////////
      82             :     // HACK: THE HORRIBLENESS HERE IS OVER 9000. The following code is a HUGE hack and will be removed completely
      83             :     // as soon as all the hardcoded GL_TEXTURE_2D references are corrected in the TextureManager/OGL/tex libs.
      84             : 
      85           0 :     Tex textures[NUMBER_OF_TEXTURES + 1];
      86             : 
      87           0 :     for (size_t i = 0; i < NUMBER_OF_TEXTURES + 1; ++i)
      88             :     {
      89           0 :         VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i]) + L".dds");
      90             : 
      91           0 :         std::shared_ptr<u8> file;
      92             :         size_t fileSize;
      93           0 :         if (g_VFS->LoadFile(path, file, fileSize) != INFO::OK)
      94             :         {
      95           0 :             path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i]) + L".dds.cached.dds");
      96           0 :             if (g_VFS->LoadFile(path, file, fileSize) != INFO::OK)
      97             :             {
      98           0 :                 LOGERROR("Error creating sky cubemap '%s', can't load file: '%s'.", m_SkySet.ToUTF8().c_str(), path.string8().c_str());
      99           0 :                 return;
     100             :             }
     101             :         }
     102             : 
     103           0 :         if (textures[i].decode(file, fileSize) != INFO::OK ||
     104           0 :             textures[i].transform_to((textures[i].m_Flags | TEX_BOTTOM_UP | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS)) != INFO::OK)
     105             :         {
     106           0 :             LOGERROR("Error creating sky cubemap '%s', can't decode file: '%s'.", m_SkySet.ToUTF8().c_str(), path.string8().c_str());
     107           0 :             return;
     108             :         }
     109             : 
     110           0 :         if (!is_pow2(textures[i].m_Width) || !is_pow2(textures[i].m_Height))
     111             :         {
     112           0 :             LOGERROR("Error creating sky cubemap '%s', cube textures should have power of 2 sizes.", m_SkySet.ToUTF8().c_str());
     113           0 :             return;
     114             :         }
     115             : 
     116           0 :         if (textures[i].m_Width != textures[0].m_Width || textures[i].m_Height != textures[0].m_Height)
     117             :         {
     118           0 :             LOGERROR("Error creating sky cubemap '%s', cube textures have different sizes.", m_SkySet.ToUTF8().c_str());
     119           0 :             return;
     120             :         }
     121             :     }
     122             : 
     123             :     std::unique_ptr<Renderer::Backend::ITexture> skyCubeMap =
     124           0 :         g_VideoMode.GetBackendDevice()->CreateTexture("SkyCubeMap",
     125             :             Renderer::Backend::ITexture::Type::TEXTURE_CUBE,
     126             :             Renderer::Backend::ITexture::Usage::TRANSFER_DST |
     127             :                 Renderer::Backend::ITexture::Usage::SAMPLED,
     128           0 :             Renderer::Backend::Format::R8G8B8A8_UNORM, textures[0].m_Width, textures[0].m_Height,
     129           0 :             Renderer::Backend::Sampler::MakeDefaultSampler(
     130             :                 Renderer::Backend::Sampler::Filter::LINEAR,
     131           0 :                 Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, 1);
     132             : 
     133           0 :     std::vector<u8> rotated;
     134           0 :     for (size_t i = 0; i < NUMBER_OF_TEXTURES + 1; ++i)
     135             :     {
     136           0 :         u8* data = textures[i].get_data();
     137             : 
     138             :         // We need to rotate the side if it's looking up or down.
     139             :         // TODO: maybe it should be done during texture conversion.
     140           0 :         if (i == 2 || i == 3)
     141             :         {
     142           0 :             rotated.resize(textures[i].m_DataSize);
     143             : 
     144           0 :             for (size_t y = 0; y < textures[i].m_Height; ++y)
     145             :             {
     146           0 :                 for (size_t x = 0; x < textures[i].m_Width; ++x)
     147             :                 {
     148           0 :                     const size_t invX = y;
     149           0 :                     const size_t invY = textures[i].m_Width - x - 1;
     150             : 
     151           0 :                     rotated[(y * textures[i].m_Width + x) * 4 + 0] = data[(invY * textures[i].m_Width + invX) * 4 + 0];
     152           0 :                     rotated[(y * textures[i].m_Width + x) * 4 + 1] = data[(invY * textures[i].m_Width + invX) * 4 + 1];
     153           0 :                     rotated[(y * textures[i].m_Width + x) * 4 + 2] = data[(invY * textures[i].m_Width + invX) * 4 + 2];
     154           0 :                     rotated[(y * textures[i].m_Width + x) * 4 + 3] = data[(invY * textures[i].m_Width + invX) * 4 + 3];
     155             :                 }
     156             :             }
     157             : 
     158           0 :             deviceCommandContext->UploadTexture(
     159             :                 skyCubeMap.get(), Renderer::Backend::Format::R8G8B8A8_UNORM,
     160           0 :                 &rotated[0], textures[i].m_DataSize, 0, i);
     161             :         }
     162             :         else
     163             :         {
     164           0 :             deviceCommandContext->UploadTexture(
     165             :                 skyCubeMap.get(), Renderer::Backend::Format::R8G8B8A8_UNORM,
     166           0 :                 data, textures[i].m_DataSize, 0, i);
     167             :         }
     168             :     }
     169             : 
     170           0 :     m_SkyTextureCube = g_Renderer.GetTextureManager().WrapBackendTexture(std::move(skyCubeMap));
     171             :     ///////////////////////////////////////////////////////////////////////////
     172             : }
     173             : 
     174           0 : Renderer::Backend::ITexture* SkyManager::GetSkyCube()
     175             : {
     176           0 :     return m_SkyTextureCube->GetBackendTexture();
     177             : }
     178             : 
     179           0 : void SkyManager::SetSkySet(const CStrW& newSet)
     180             : {
     181           0 :     if (newSet == m_SkySet)
     182           0 :         return;
     183             : 
     184           0 :     m_SkyTextureCube.reset();
     185             : 
     186           0 :     m_SkySet = newSet;
     187             : }
     188             : 
     189           0 : std::vector<CStrW> SkyManager::GetSkySets() const
     190             : {
     191           0 :     std::vector<CStrW> skies;
     192             : 
     193             :     // Find all subdirectories in art/textures/skies
     194             : 
     195           0 :     const VfsPath path(L"art/textures/skies/");
     196           0 :     DirectoryNames subdirectories;
     197           0 :     if (g_VFS->GetDirectoryEntries(path, 0, &subdirectories) != INFO::OK)
     198             :     {
     199           0 :         LOGERROR("Error opening directory '%s'", path.string8());
     200           0 :         return std::vector<CStrW>(1, GetSkySet()); // just return what we currently have
     201             :     }
     202             : 
     203           0 :     for(size_t i = 0; i < subdirectories.size(); i++)
     204           0 :         skies.push_back(subdirectories[i].string());
     205           0 :     sort(skies.begin(), skies.end());
     206             : 
     207           0 :     return skies;
     208             : }
     209             : 
     210           0 : void SkyManager::RenderSky(
     211             :     Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
     212             : {
     213           0 :     GPU_SCOPED_LABEL(deviceCommandContext, "Render sky");
     214             : 
     215             :     const CTexturePtr& skyTextureCube =
     216           0 :         !m_SkyVisible || m_SkySet.empty() || !m_SkyTextureCube
     217           0 :             ? g_Renderer.GetTextureManager().GetBlackTextureCube()
     218           0 :             : m_SkyTextureCube;
     219             : 
     220           0 :     const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera();
     221             : 
     222             :     CShaderTechniquePtr skytech =
     223           0 :         g_Renderer.GetShaderManager().LoadEffect(str_sky_simple);
     224           0 :     deviceCommandContext->SetGraphicsPipelineState(
     225           0 :         skytech->GetGraphicsPipelineState());
     226           0 :     deviceCommandContext->BeginPass();
     227           0 :     Renderer::Backend::IShaderProgram* shader = skytech->GetShader();
     228           0 :     deviceCommandContext->SetTexture(
     229           0 :         shader->GetBindingSlot(str_baseTex), skyTextureCube->GetBackendTexture());
     230             : 
     231             :     // Translate so the sky center is at the camera space origin.
     232           0 :     CMatrix3D translate;
     233           0 :     translate.SetTranslation(camera.GetOrientation().GetTranslation());
     234             : 
     235             :     // Currently we have a hardcoded near plane in the projection matrix.
     236           0 :     CMatrix3D scale;
     237           0 :     scale.SetScaling(10.0f, 10.0f, 10.0f);
     238             : 
     239             :     // Rotate so that the "left" face, which contains the brightest part of
     240             :     // each skymap, is in the direction of the sun from our light
     241             :     // environment.
     242           0 :     CMatrix3D rotate;
     243           0 :     rotate.SetYRotation(M_PI + g_Renderer.GetSceneRenderer().GetLightEnv().GetRotation());
     244             : 
     245           0 :     const CMatrix3D transform = camera.GetViewProjection() * translate * rotate * scale;
     246           0 :     deviceCommandContext->SetUniform(
     247           0 :         shader->GetBindingSlot(str_transform), transform.AsFloatArray());
     248             : 
     249           0 :     const uint32_t stride = m_VertexArray.GetStride();
     250           0 :     const uint32_t firstVertexOffset = m_VertexArray.GetOffset() * stride;
     251             : 
     252           0 :     deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout);
     253             : 
     254           0 :     deviceCommandContext->SetVertexBuffer(
     255           0 :         0, m_VertexArray.GetBuffer(), firstVertexOffset);
     256             : 
     257           0 :     deviceCommandContext->Draw(0, m_VertexArray.GetNumberOfVertices());
     258             : 
     259           0 :     deviceCommandContext->EndPass();
     260           0 : }
     261             : 
     262           0 : void SkyManager::CreateSkyCube()
     263             : {
     264           0 :     m_AttributePosition.format = Renderer::Backend::Format::R32G32B32_SFLOAT;
     265           0 :     m_VertexArray.AddAttribute(&m_AttributePosition);
     266             : 
     267           0 :     m_AttributeUV.format = Renderer::Backend::Format::R32G32B32_SFLOAT;
     268           0 :     m_VertexArray.AddAttribute(&m_AttributeUV);
     269             : 
     270             :     // 6 sides of cube with 6 vertices.
     271           0 :     m_VertexArray.SetNumberOfVertices(6 * 6);
     272           0 :     m_VertexArray.Layout();
     273             : 
     274           0 :     VertexArrayIterator<CVector3D> attrPosition = m_AttributePosition.GetIterator<CVector3D>();
     275           0 :     VertexArrayIterator<CVector3D> attrUV = m_AttributeUV.GetIterator<CVector3D>();
     276             : 
     277             : #define ADD_VERTEX(U, V, W, VX, VY, VZ) \
     278             :     STMT( \
     279             :         attrPosition->X = VX; \
     280             :         attrPosition->Y = VY; \
     281             :         attrPosition->Z = VZ; \
     282             :         ++attrPosition; \
     283             :         attrUV->X = U; \
     284             :         attrUV->Y = V; \
     285             :         attrUV->Z = W; \
     286             :         ++attrUV;)
     287             : 
     288             :     // Axis -X
     289           0 :     ADD_VERTEX(+1, +1, +1, -1.0f, -1.0f, -1.0f);
     290           0 :     ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f);
     291           0 :     ADD_VERTEX(+1, -1, -1, -1.0f, +1.0f, +1.0f);
     292           0 :     ADD_VERTEX(+1, +1, +1, -1.0f, -1.0f, -1.0f);
     293           0 :     ADD_VERTEX(+1, -1, -1, -1.0f, +1.0f, +1.0f);
     294           0 :     ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f);
     295             : 
     296             :     // Axis +X
     297           0 :     ADD_VERTEX(-1, +1, -1, +1.0f, -1.0f, +1.0f);
     298           0 :     ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f);
     299           0 :     ADD_VERTEX(-1, -1, +1, +1.0f, +1.0f, -1.0f);
     300           0 :     ADD_VERTEX(-1, +1, -1, +1.0f, -1.0f, +1.0f);
     301           0 :     ADD_VERTEX(-1, -1, +1, +1.0f, +1.0f, -1.0f);
     302           0 :     ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f);
     303             : 
     304             :     // Axis -Y
     305           0 :     ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f);
     306           0 :     ADD_VERTEX(-1, +1, -1, +1.0f, -1.0f, +1.0f);
     307           0 :     ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f);
     308           0 :     ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f);
     309           0 :     ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f);
     310           0 :     ADD_VERTEX(+1, +1, +1, -1.0f, -1.0f, -1.0f);
     311             : 
     312             :     // Axis +Y
     313           0 :     ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f);
     314           0 :     ADD_VERTEX(+1, -1, -1, -1.0f, +1.0f, +1.0f);
     315           0 :     ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f);
     316           0 :     ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f);
     317           0 :     ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f);
     318           0 :     ADD_VERTEX(-1, -1, +1, +1.0f, +1.0f, -1.0f);
     319             : 
     320             :     // Axis -Z
     321           0 :     ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f);
     322           0 :     ADD_VERTEX(+1, +1, +1, -1.0f, -1.0f, -1.0f);
     323           0 :     ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f);
     324           0 :     ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f);
     325           0 :     ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f);
     326           0 :     ADD_VERTEX(-1, -1, +1, +1.0f, +1.0f, -1.0f);
     327             : 
     328             :     // Axis +Z
     329           0 :     ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f);
     330           0 :     ADD_VERTEX(-1, +1, -1, +1.0f, -1.0f, +1.0f);
     331           0 :     ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f);
     332           0 :     ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f);
     333           0 :     ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f);
     334           0 :     ADD_VERTEX(+1, -1, -1, -1.0f, +1.0f, +1.0f);
     335             : #undef ADD_VERTEX
     336             : 
     337           0 :     m_VertexArray.Upload();
     338           0 :     m_VertexArray.FreeBackingStore();
     339             : 
     340           0 :     const uint32_t stride = m_VertexArray.GetStride();
     341           0 :     const std::array<Renderer::Backend::SVertexAttributeFormat, 2> attributes{{
     342             :         {Renderer::Backend::VertexAttributeStream::POSITION,
     343           0 :             m_AttributePosition.format, m_AttributePosition.offset, stride,
     344             :             Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0},
     345             :         {Renderer::Backend::VertexAttributeStream::UV0,
     346           0 :             m_AttributeUV.format, m_AttributeUV.offset, stride,
     347             :             Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}
     348           0 :     }};
     349           0 :     m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes);
     350           3 : }

Generated by: LCOV version 1.13