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: 0 145 0.0 %
Date: 2022-03-08 13:03:03 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2022 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 "lib/timer.h"
      29             : #include "maths/MathUtil.h"
      30             : #include "ps/CLogger.h"
      31             : #include "ps/ConfigDB.h"
      32             : #include "ps/CStr.h"
      33             : #include "ps/CStrInternStatic.h"
      34             : #include "ps/Filesystem.h"
      35             : #include "ps/Game.h"
      36             : #include "ps/Loader.h"
      37             : #include "ps/VideoMode.h"
      38             : #include "ps/World.h"
      39             : #include "renderer/backend/gl/Device.h"
      40             : #include "renderer/Renderer.h"
      41             : #include "renderer/SceneRenderer.h"
      42             : #include "renderer/RenderingOptions.h"
      43             : 
      44             : #include <algorithm>
      45             : 
      46           0 : SkyManager::SkyManager()
      47           0 :     : m_VertexArray(Renderer::Backend::GL::CBuffer::Type::VERTEX, false)
      48             : {
      49           0 :     CFG_GET_VAL("showsky", m_RenderSky);
      50           0 : }
      51             : 
      52           0 : void SkyManager::LoadAndUploadSkyTexturesIfNeeded(
      53             :     Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext)
      54             : {
      55           0 :     if (m_SkyCubeMap)
      56           0 :         return;
      57             : 
      58           0 :     GPU_SCOPED_LABEL(deviceCommandContext, "Load Sky Textures");
      59           0 :     static const CStrW images[NUMBER_OF_TEXTURES + 1] = {
      60             :         L"front",
      61             :         L"back",
      62             :         L"top",
      63             :         L"top",
      64             :         L"right",
      65             :         L"left"
      66           0 :     };
      67             : 
      68             :     /*for (size_t i = 0; i < ARRAY_SIZE(m_SkyTexture); ++i)
      69             :     {
      70             :         VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(s_imageNames[i])+L".dds");
      71             : 
      72             :         CTextureProperties textureProps(path);
      73             :         textureProps.SetWrap(GL_CLAMP_TO_EDGE);
      74             :         CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
      75             :         texture->Prefetch();
      76             :         m_SkyTexture[i] = texture;
      77             :     }*/
      78             : 
      79             :     ///////////////////////////////////////////////////////////////////////////
      80             :     // HACK: THE HORRIBLENESS HERE IS OVER 9000. The following code is a HUGE hack and will be removed completely
      81             :     // as soon as all the hardcoded GL_TEXTURE_2D references are corrected in the TextureManager/OGL/tex libs.
      82             : 
      83           0 :     Tex textures[NUMBER_OF_TEXTURES + 1];
      84             : 
      85           0 :     for (size_t i = 0; i < NUMBER_OF_TEXTURES + 1; ++i)
      86             :     {
      87           0 :         VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i]) + L".dds");
      88             : 
      89           0 :         std::shared_ptr<u8> file;
      90           0 :         size_t fileSize;
      91           0 :         if (g_VFS->LoadFile(path, file, fileSize) != INFO::OK)
      92             :         {
      93           0 :             path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i]) + L".dds.cached.dds");
      94           0 :             if (g_VFS->LoadFile(path, file, fileSize) != INFO::OK)
      95             :             {
      96           0 :                 LOGERROR("Error creating sky cubemap '%s', can't load file: '%s'.", m_SkySet.ToUTF8().c_str(), path.string8().c_str());
      97           0 :                 return;
      98             :             }
      99             :         }
     100             : 
     101           0 :         textures[i].decode(file, fileSize);
     102           0 :         textures[i].transform_to((textures[i].m_Flags | TEX_BOTTOM_UP | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS));
     103             : 
     104           0 :         if (!is_pow2(textures[i].m_Width) || !is_pow2(textures[i].m_Height))
     105             :         {
     106           0 :             LOGERROR("Error creating sky cubemap '%s', cube textures should have power of 2 sizes.", m_SkySet.ToUTF8().c_str());
     107           0 :             return;
     108             :         }
     109             : 
     110           0 :         if (textures[i].m_Width != textures[0].m_Width || textures[i].m_Height != textures[0].m_Height)
     111             :         {
     112           0 :             LOGERROR("Error creating sky cubemap '%s', cube textures have different sizes.", m_SkySet.ToUTF8().c_str());
     113           0 :             return;
     114             :         }
     115             :     }
     116             : 
     117           0 :     m_SkyCubeMap = g_VideoMode.GetBackendDevice()->CreateTexture("SkyCubeMap",
     118             :         Renderer::Backend::GL::CTexture::Type::TEXTURE_CUBE,
     119           0 :         Renderer::Backend::Format::R8G8B8A8_UNORM, textures[0].m_Width, textures[0].m_Height,
     120           0 :         Renderer::Backend::Sampler::MakeDefaultSampler(
     121             :             Renderer::Backend::Sampler::Filter::LINEAR,
     122           0 :             Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, 1);
     123             : 
     124           0 :     std::vector<u8> rotated;
     125           0 :     for (size_t i = 0; i < NUMBER_OF_TEXTURES + 1; ++i)
     126             :     {
     127           0 :         u8* data = textures[i].get_data();
     128             : 
     129             :         // We need to rotate the side if it's looking up or down.
     130             :         // TODO: maybe it should be done during texture conversion.
     131           0 :         if (i == 2 || i == 3)
     132             :         {
     133           0 :             rotated.resize(textures[i].m_DataSize);
     134             : 
     135           0 :             for (size_t y = 0; y < textures[i].m_Height; ++y)
     136             :             {
     137           0 :                 for (size_t x = 0; x < textures[i].m_Width; ++x)
     138             :                 {
     139           0 :                     const size_t invX = y;
     140           0 :                     const size_t invY = textures[i].m_Width - x - 1;
     141             : 
     142           0 :                     rotated[(y * textures[i].m_Width + x) * 4 + 0] = data[(invY * textures[i].m_Width + invX) * 4 + 0];
     143           0 :                     rotated[(y * textures[i].m_Width + x) * 4 + 1] = data[(invY * textures[i].m_Width + invX) * 4 + 1];
     144           0 :                     rotated[(y * textures[i].m_Width + x) * 4 + 2] = data[(invY * textures[i].m_Width + invX) * 4 + 2];
     145           0 :                     rotated[(y * textures[i].m_Width + x) * 4 + 3] = data[(invY * textures[i].m_Width + invX) * 4 + 3];
     146             :                 }
     147             :             }
     148             : 
     149           0 :             deviceCommandContext->UploadTexture(
     150             :                 m_SkyCubeMap.get(), Renderer::Backend::Format::R8G8B8A8_UNORM,
     151           0 :                 &rotated[0], textures[i].m_DataSize, 0, i);
     152             :         }
     153             :         else
     154             :         {
     155           0 :             deviceCommandContext->UploadTexture(
     156             :                 m_SkyCubeMap.get(), Renderer::Backend::Format::R8G8B8A8_UNORM,
     157             :                 data, textures[i].m_DataSize, 0, i);
     158             :         }
     159             :     }
     160             :     ///////////////////////////////////////////////////////////////////////////
     161             : }
     162             : 
     163           0 : void SkyManager::SetSkySet(const CStrW& newSet)
     164             : {
     165           0 :     if (newSet == m_SkySet)
     166             :         return;
     167             : 
     168           0 :     m_SkyCubeMap.reset();
     169             : 
     170           0 :     m_SkySet = newSet;
     171             : }
     172             : 
     173           0 : std::vector<CStrW> SkyManager::GetSkySets() const
     174             : {
     175           0 :     std::vector<CStrW> skies;
     176             : 
     177             :     // Find all subdirectories in art/textures/skies
     178             : 
     179           0 :     const VfsPath path(L"art/textures/skies/");
     180           0 :     DirectoryNames subdirectories;
     181           0 :     if (g_VFS->GetDirectoryEntries(path, 0, &subdirectories) != INFO::OK)
     182             :     {
     183           0 :         LOGERROR("Error opening directory '%s'", path.string8());
     184           0 :         return std::vector<CStrW>(1, GetSkySet()); // just return what we currently have
     185             :     }
     186             : 
     187           0 :     for(size_t i = 0; i < subdirectories.size(); i++)
     188           0 :         skies.push_back(subdirectories[i].string());
     189           0 :     sort(skies.begin(), skies.end());
     190             : 
     191           0 :     return skies;
     192             : }
     193             : 
     194           0 : void SkyManager::RenderSky(
     195             :     Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext)
     196             : {
     197           0 :     GPU_SCOPED_LABEL(deviceCommandContext, "Render sky");
     198             : #if CONFIG2_GLES
     199             :     UNUSED2(deviceCommandContext);
     200             : #warning TODO: implement SkyManager::RenderSky for GLES
     201             : #else
     202           0 :     if (!m_RenderSky)
     203           0 :         return;
     204             : 
     205             :     // Do nothing unless SetSkySet was called
     206           0 :     if (m_SkySet.empty() || !m_SkyCubeMap)
     207             :         return;
     208             : 
     209           0 :     if (m_VertexArray.GetNumberOfVertices() == 0)
     210           0 :         CreateSkyCube();
     211             : 
     212           0 :     const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera();
     213             : 
     214           0 :     CShaderTechniquePtr skytech =
     215           0 :         g_Renderer.GetShaderManager().LoadEffect(str_sky_simple);
     216           0 :     skytech->BeginPass();
     217           0 :     deviceCommandContext->SetGraphicsPipelineState(
     218             :         skytech->GetGraphicsPipelineStateDesc());
     219           0 :     const CShaderProgramPtr& shader = skytech->GetShader();
     220           0 :     shader->BindTexture(str_baseTex, m_SkyCubeMap.get());
     221             : 
     222             :     // Translate so the sky center is at the camera space origin.
     223           0 :     CMatrix3D translate;
     224           0 :     translate.SetTranslation(camera.GetOrientation().GetTranslation());
     225             : 
     226             :     // Currently we have a hardcoded near plane in the projection matrix.
     227           0 :     CMatrix3D scale;
     228           0 :     scale.SetScaling(10.0f, 10.0f, 10.0f);
     229             : 
     230             :     // Rotate so that the "left" face, which contains the brightest part of
     231             :     // each skymap, is in the direction of the sun from our light
     232             :     // environment.
     233           0 :     CMatrix3D rotate;
     234           0 :     rotate.SetYRotation(M_PI + g_Renderer.GetSceneRenderer().GetLightEnv().GetRotation());
     235             : 
     236           0 :     shader->Uniform(
     237             :         str_transform,
     238           0 :         camera.GetViewProjection() * translate * rotate * scale);
     239             : 
     240           0 :     m_VertexArray.PrepareForRendering();
     241             : 
     242           0 :     u8* base = m_VertexArray.Bind(deviceCommandContext);
     243           0 :     const GLsizei stride = static_cast<GLsizei>(m_VertexArray.GetStride());
     244             : 
     245           0 :     shader->VertexPointer(
     246           0 :         Renderer::Backend::Format::R32G32B32_SFLOAT, stride, base + m_AttributePosition.offset);
     247           0 :     shader->TexCoordPointer(
     248           0 :         GL_TEXTURE0, Renderer::Backend::Format::R32G32B32_SFLOAT, stride, base + m_AttributeUV.offset);
     249           0 :     shader->AssertPointersBound();
     250             : 
     251           0 :     deviceCommandContext->Draw(0, m_VertexArray.GetNumberOfVertices());
     252             : 
     253           0 :     skytech->EndPass();
     254             : #endif
     255             : }
     256             : 
     257           0 : void SkyManager::CreateSkyCube()
     258             : {
     259           0 :     m_AttributePosition.type = GL_FLOAT;
     260           0 :     m_AttributePosition.elems = 3;
     261           0 :     m_VertexArray.AddAttribute(&m_AttributePosition);
     262             : 
     263           0 :     m_AttributeUV.type = GL_FLOAT;
     264           0 :     m_AttributeUV.elems = 3;
     265           0 :     m_VertexArray.AddAttribute(&m_AttributeUV);
     266             : 
     267             :     // 6 sides of cube with 6 vertices.
     268           0 :     m_VertexArray.SetNumberOfVertices(6 * 6);
     269           0 :     m_VertexArray.Layout();
     270             : 
     271           0 :     VertexArrayIterator<CVector3D> attrPosition = m_AttributePosition.GetIterator<CVector3D>();
     272           0 :     VertexArrayIterator<CVector3D> attrUV = m_AttributeUV.GetIterator<CVector3D>();
     273             : 
     274             : #define ADD_VERTEX(U, V, W, VX, VY, VZ) \
     275             :     STMT( \
     276             :         attrPosition->X = VX; \
     277             :         attrPosition->Y = VY; \
     278             :         attrPosition->Z = VZ; \
     279             :         ++attrPosition; \
     280             :         attrUV->X = U; \
     281             :         attrUV->Y = V; \
     282             :         attrUV->Z = W; \
     283             :         ++attrUV;)
     284             : 
     285             :     // Axis -X
     286           0 :     ADD_VERTEX(+1, +1, +1, -1.0f, -1.0f, -1.0f);
     287           0 :     ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f);
     288           0 :     ADD_VERTEX(+1, -1, -1, -1.0f, +1.0f, +1.0f);
     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             : 
     293             :     // Axis +X
     294           0 :     ADD_VERTEX(-1, +1, -1, +1.0f, -1.0f, +1.0f);
     295           0 :     ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f);
     296           0 :     ADD_VERTEX(-1, -1, +1, +1.0f, +1.0f, -1.0f);
     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             : 
     301             :     // Axis -Y
     302           0 :     ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f);
     303           0 :     ADD_VERTEX(-1, +1, -1, +1.0f, -1.0f, +1.0f);
     304           0 :     ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f);
     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             : 
     309             :     // Axis +Y
     310           0 :     ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f);
     311           0 :     ADD_VERTEX(+1, -1, -1, -1.0f, +1.0f, +1.0f);
     312           0 :     ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f);
     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             : 
     317             :     // Axis -Z
     318           0 :     ADD_VERTEX(-1, +1, +1, +1.0f, -1.0f, -1.0f);
     319           0 :     ADD_VERTEX(+1, +1, +1, -1.0f, -1.0f, -1.0f);
     320           0 :     ADD_VERTEX(+1, -1, +1, -1.0f, +1.0f, -1.0f);
     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             : 
     325             :     // Axis +Z
     326           0 :     ADD_VERTEX(+1, +1, -1, -1.0f, -1.0f, +1.0f);
     327           0 :     ADD_VERTEX(-1, +1, -1, +1.0f, -1.0f, +1.0f);
     328           0 :     ADD_VERTEX(-1, -1, -1, +1.0f, +1.0f, +1.0f);
     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             : #undef ADD_VERTEX
     333             : 
     334           0 :     m_VertexArray.Upload();
     335           0 :     m_VertexArray.FreeBackingStore();
     336           0 : }

Generated by: LCOV version 1.13