LCOV - code coverage report
Current view: top level - source/renderer - DebugRenderer.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 5 222 2.3 %
Date: 2023-01-19 00:18:29 Functions: 3 14 21.4 %

          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/DebugRenderer.h"
      21             : 
      22             : #include "graphics/Camera.h"
      23             : #include "graphics/Color.h"
      24             : #include "graphics/ShaderManager.h"
      25             : #include "graphics/ShaderProgram.h"
      26             : #include "lib/hash.h"
      27             : #include "maths/BoundingBoxAligned.h"
      28             : #include "maths/Brush.h"
      29             : #include "maths/Matrix3D.h"
      30             : #include "maths/Vector3D.h"
      31             : #include "ps/CStrInternStatic.h"
      32             : #include "renderer/backend/IDeviceCommandContext.h"
      33             : #include "renderer/Renderer.h"
      34             : #include "renderer/SceneRenderer.h"
      35             : 
      36             : #include <cmath>
      37             : 
      38           6 : void CDebugRenderer::Initialize()
      39             : {
      40           6 :     const std::array<Renderer::Backend::SVertexAttributeFormat, 1> attributes{{
      41             :         {Renderer::Backend::VertexAttributeStream::POSITION,
      42             :             Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3,
      43             :             Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}
      44             :     }};
      45           6 :     m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes);
      46           6 : }
      47             : 
      48           0 : void CDebugRenderer::DrawLine(
      49             :     const CVector3D& from, const CVector3D& to, const CColor& color,
      50             :     const float width, const bool depthTestEnabled)
      51             : {
      52           0 :     if (from == to)
      53           0 :         return;
      54             : 
      55           0 :     DrawLine({from, to}, color, width, depthTestEnabled);
      56             : }
      57             : 
      58           0 : void CDebugRenderer::DrawLine(
      59             :     const std::vector<CVector3D>& line, const CColor& color,
      60             :     const float width, const bool depthTestEnabled)
      61             : {
      62           0 :     if (line.size() <= 1)
      63           0 :         return;
      64             : 
      65             :     Renderer::Backend::IDeviceCommandContext* deviceCommandContext =
      66           0 :         g_Renderer.GetDeviceCommandContext();
      67             : 
      68             :     CShaderTechniquePtr debugLineTech =
      69           0 :         GetShaderTechnique(str_debug_line, color, depthTestEnabled);
      70           0 :     deviceCommandContext->SetGraphicsPipelineState(
      71           0 :         debugLineTech->GetGraphicsPipelineState());
      72           0 :     deviceCommandContext->BeginPass();
      73             : 
      74           0 :     const CCamera& viewCamera = g_Renderer.GetSceneRenderer().GetViewCamera();
      75             : 
      76           0 :     Renderer::Backend::IShaderProgram* debugLineShader = debugLineTech->GetShader();
      77           0 :     const CMatrix3D transform = viewCamera.GetViewProjection();
      78           0 :     deviceCommandContext->SetUniform(
      79           0 :         debugLineShader->GetBindingSlot(str_transform), transform.AsFloatArray());
      80           0 :     deviceCommandContext->SetUniform(
      81           0 :         debugLineShader->GetBindingSlot(str_color), color.AsFloatArray());
      82             : 
      83           0 :     const CVector3D cameraIn = viewCamera.GetOrientation().GetIn();
      84             : 
      85           0 :     std::vector<float> vertices;
      86           0 :     vertices.reserve(line.size() * 6 * 3);
      87             : #define ADD(position) \
      88             :     vertices.emplace_back((position).X); \
      89             :     vertices.emplace_back((position).Y); \
      90             :     vertices.emplace_back((position).Z);
      91             : 
      92           0 :     for (size_t idx = 1; idx < line.size(); ++idx)
      93             :     {
      94           0 :         const CVector3D from = line[idx - 1];
      95           0 :         const CVector3D to = line[idx];
      96           0 :         const CVector3D direction = (to - from).Normalized();
      97           0 :         const CVector3D view = direction.Dot(cameraIn) > 0.9f ?
      98             :             CVector3D(0.0f, 1.0f, 0.0f) :
      99           0 :             cameraIn;
     100           0 :         const CVector3D offset = view.Cross(direction).Normalized() * width;
     101             : 
     102           0 :         ADD(from + offset)
     103           0 :         ADD(to - offset)
     104           0 :         ADD(to + offset)
     105           0 :         ADD(from + offset)
     106           0 :         ADD(from - offset)
     107           0 :         ADD(to - offset)
     108             :     }
     109             : 
     110             : #undef ADD
     111             : 
     112           0 :     deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout);
     113           0 :     deviceCommandContext->SetVertexBufferData(
     114           0 :         0, vertices.data(), vertices.size() * sizeof(vertices[0]));
     115             : 
     116           0 :     deviceCommandContext->Draw(0, vertices.size() / 3);
     117             : 
     118           0 :     deviceCommandContext->EndPass();
     119             : }
     120             : 
     121           0 : void CDebugRenderer::DrawCircle(const CVector3D& origin, const float radius, const CColor& color)
     122             : {
     123             :     CShaderTechniquePtr debugCircleTech =
     124           0 :         GetShaderTechnique(str_debug_line, color);
     125             : 
     126             :     Renderer::Backend::IDeviceCommandContext* deviceCommandContext =
     127           0 :         g_Renderer.GetDeviceCommandContext();
     128             : 
     129           0 :     deviceCommandContext->SetGraphicsPipelineState(
     130           0 :         debugCircleTech->GetGraphicsPipelineState());
     131           0 :     deviceCommandContext->BeginPass();
     132             : 
     133           0 :     const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera();
     134             : 
     135           0 :     Renderer::Backend::IShaderProgram* debugCircleShader = debugCircleTech->GetShader();
     136             : 
     137           0 :     const CMatrix3D transform = camera.GetViewProjection();
     138           0 :     deviceCommandContext->SetUniform(
     139           0 :         debugCircleShader->GetBindingSlot(str_transform), transform.AsFloatArray());
     140           0 :     deviceCommandContext->SetUniform(
     141           0 :         debugCircleShader->GetBindingSlot(str_color), color.AsFloatArray());
     142             : 
     143           0 :     const CVector3D cameraUp = camera.GetOrientation().GetUp();
     144           0 :     const CVector3D cameraLeft = camera.GetOrientation().GetLeft();
     145             : 
     146           0 :     std::vector<float> vertices;
     147             : #define ADD(position) \
     148             :     vertices.emplace_back((position).X); \
     149             :     vertices.emplace_back((position).Y); \
     150             :     vertices.emplace_back((position).Z);
     151             : 
     152           0 :     constexpr size_t segments = 16;
     153           0 :     for (size_t idx = 0; idx <= segments; ++idx)
     154             :     {
     155           0 :         const float angle = M_PI * 2.0f * idx / segments;
     156           0 :         const CVector3D offset = cameraUp * sin(angle) - cameraLeft * cos(angle);
     157           0 :         const float nextAngle = M_PI * 2.0f * (idx + 1) / segments;
     158           0 :         const CVector3D nextOffset = cameraUp * sin(nextAngle) - cameraLeft * cos(nextAngle);
     159           0 :         ADD(origin)
     160           0 :         ADD(origin + offset * radius)
     161           0 :         ADD(origin + nextOffset * radius)
     162             :     }
     163             : 
     164             : #undef ADD
     165             : 
     166           0 :     deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout);
     167           0 :     deviceCommandContext->SetVertexBufferData(
     168           0 :         0, vertices.data(), vertices.size() * sizeof(vertices[0]));
     169             : 
     170           0 :     deviceCommandContext->Draw(0, vertices.size() / 3);
     171             : 
     172           0 :     deviceCommandContext->EndPass();
     173           0 : }
     174             : 
     175           0 : void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, const CColor& color, int intermediates, bool wireframe)
     176             : {
     177           0 :     CCamera::Quad nearPoints;
     178           0 :     CCamera::Quad farPoints;
     179             : 
     180           0 :     camera.GetViewQuad(camera.GetNearPlane(), nearPoints);
     181           0 :     camera.GetViewQuad(camera.GetFarPlane(), farPoints);
     182           0 :     for (int i = 0; i < 4; ++i)
     183             :     {
     184           0 :         nearPoints[i] = camera.m_Orientation.Transform(nearPoints[i]);
     185           0 :         farPoints[i] = camera.m_Orientation.Transform(farPoints[i]);
     186             :     }
     187             : 
     188             :     CShaderTechniquePtr overlayTech =
     189           0 :         GetShaderTechnique(str_debug_line, color, true, wireframe);
     190             : 
     191             :     Renderer::Backend::IDeviceCommandContext* deviceCommandContext =
     192           0 :         g_Renderer.GetDeviceCommandContext();
     193           0 :     deviceCommandContext->SetGraphicsPipelineState(
     194           0 :         overlayTech->GetGraphicsPipelineState());
     195           0 :     deviceCommandContext->BeginPass();
     196             : 
     197           0 :     Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader();
     198             : 
     199           0 :     const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection();
     200           0 :     deviceCommandContext->SetUniform(
     201           0 :         overlayShader->GetBindingSlot(str_transform), transform.AsFloatArray());
     202           0 :     deviceCommandContext->SetUniform(
     203           0 :         overlayShader->GetBindingSlot(str_color), color.AsFloatArray());
     204             : 
     205           0 :     std::vector<float> vertices;
     206             : #define ADD(position) \
     207             :     vertices.emplace_back((position).X); \
     208             :     vertices.emplace_back((position).Y); \
     209             :     vertices.emplace_back((position).Z);
     210             : 
     211             :     // Near plane.
     212           0 :     ADD(nearPoints[0]);
     213           0 :     ADD(nearPoints[1]);
     214           0 :     ADD(nearPoints[2]);
     215           0 :     ADD(nearPoints[0]);
     216           0 :     ADD(nearPoints[2]);
     217           0 :     ADD(nearPoints[3]);
     218             : 
     219             :     // Far plane.
     220           0 :     ADD(farPoints[0]);
     221           0 :     ADD(farPoints[1]);
     222           0 :     ADD(farPoints[2]);
     223           0 :     ADD(farPoints[0]);
     224           0 :     ADD(farPoints[2]);
     225           0 :     ADD(farPoints[3]);
     226             : 
     227             :     // Intermediate planes.
     228           0 :     CVector3D intermediatePoints[4];
     229           0 :     for (int i = 0; i < intermediates; ++i)
     230             :     {
     231           0 :         const float t = (i + 1.0f) / (intermediates + 1.0f);
     232             : 
     233           0 :         for (int j = 0; j < 4; ++j)
     234           0 :             intermediatePoints[j] = nearPoints[j] * t + farPoints[j] * (1.0f - t);
     235             : 
     236           0 :         ADD(intermediatePoints[0]);
     237           0 :         ADD(intermediatePoints[1]);
     238           0 :         ADD(intermediatePoints[2]);
     239           0 :         ADD(intermediatePoints[0]);
     240           0 :         ADD(intermediatePoints[2]);
     241           0 :         ADD(intermediatePoints[3]);
     242             :     }
     243             : 
     244           0 :     deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout);
     245           0 :     deviceCommandContext->SetVertexBufferData(
     246           0 :         0, vertices.data(), vertices.size() * sizeof(vertices[0]));
     247             : 
     248           0 :     deviceCommandContext->Draw(0, vertices.size() / 3);
     249             : 
     250           0 :     vertices.clear();
     251             : 
     252             :     // Connection lines.
     253           0 :     for (int i = 0; i < 4; ++i)
     254             :     {
     255           0 :         const int nextI = (i + 1) % 4;
     256           0 :         ADD(nearPoints[i]);
     257           0 :         ADD(farPoints[nextI]);
     258           0 :         ADD(farPoints[i]);
     259           0 :         ADD(nearPoints[i]);
     260           0 :         ADD(nearPoints[nextI]);
     261           0 :         ADD(farPoints[nextI]);
     262             :     }
     263             : 
     264           0 :     deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout);
     265           0 :     deviceCommandContext->SetVertexBufferData(
     266           0 :         0, vertices.data(), vertices.size() * sizeof(vertices[0]));
     267             : 
     268           0 :     deviceCommandContext->Draw(0, vertices.size() / 3);
     269             : #undef ADD
     270             : 
     271           0 :     deviceCommandContext->EndPass();
     272           0 : }
     273             : 
     274           0 : void CDebugRenderer::DrawBoundingBox(
     275             :     const CBoundingBoxAligned& boundingBox, const CColor& color,
     276             :     bool wireframe)
     277             : {
     278           0 :     DrawBoundingBox(
     279             :         boundingBox, color,
     280           0 :         g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(), wireframe);
     281           0 : }
     282             : 
     283           0 : void CDebugRenderer::DrawBoundingBox(
     284             :     const CBoundingBoxAligned& boundingBox, const CColor& color,
     285             :     const CMatrix3D& transform, bool wireframe)
     286             : {
     287             :     CShaderTechniquePtr shaderTech =
     288           0 :         GetShaderTechnique(str_debug_line, color, true, wireframe);
     289             : 
     290             :     Renderer::Backend::IDeviceCommandContext* deviceCommandContext =
     291           0 :         g_Renderer.GetDeviceCommandContext();
     292           0 :     deviceCommandContext->SetGraphicsPipelineState(
     293           0 :         shaderTech->GetGraphicsPipelineState());
     294           0 :     deviceCommandContext->BeginPass();
     295             : 
     296           0 :     Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader();
     297             : 
     298           0 :     deviceCommandContext->SetUniform(
     299           0 :         shader->GetBindingSlot(str_transform), transform.AsFloatArray());
     300           0 :     deviceCommandContext->SetUniform(
     301           0 :         shader->GetBindingSlot(str_color), color.AsFloatArray());
     302             : 
     303           0 :     std::vector<float> data;
     304             : 
     305             : #define ADD_FACE(x, y, z) \
     306             :     ADD_PT(0, 0, x, y, z); ADD_PT(1, 0, x, y, z); ADD_PT(1, 1, x, y, z); \
     307             :     ADD_PT(1, 1, x, y, z); ADD_PT(0, 1, x, y, z); ADD_PT(0, 0, x, y, z);
     308             : #define ADD_PT(u_, v_, x, y, z) \
     309             :     STMT(int u = u_; int v = v_; \
     310             :         data.push_back(boundingBox[x].X); \
     311             :         data.push_back(boundingBox[y].Y); \
     312             :         data.push_back(boundingBox[z].Z); \
     313             :     )
     314             : 
     315           0 :     ADD_FACE(u, v, 0);
     316           0 :     ADD_FACE(0, u, v);
     317           0 :     ADD_FACE(u, 0, 1-v);
     318           0 :     ADD_FACE(u, 1-v, 1);
     319           0 :     ADD_FACE(1, u, 1-v);
     320           0 :     ADD_FACE(u, 1, v);
     321             : 
     322             : #undef ADD_FACE
     323             : 
     324           0 :     deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout);
     325           0 :     deviceCommandContext->SetVertexBufferData(
     326           0 :         0, data.data(), data.size() * sizeof(data[0]));
     327             : 
     328           0 :     deviceCommandContext->Draw(0, 6 * 6);
     329             : 
     330           0 :     deviceCommandContext->EndPass();
     331           0 : }
     332             : 
     333           0 : void CDebugRenderer::DrawBrush(const CBrush& brush, const CColor& color, bool wireframe)
     334             : {
     335             :     CShaderTechniquePtr shaderTech =
     336           0 :         GetShaderTechnique(str_debug_line, color, true, wireframe);
     337             : 
     338             :     Renderer::Backend::IDeviceCommandContext* deviceCommandContext =
     339           0 :         g_Renderer.GetDeviceCommandContext();
     340           0 :     deviceCommandContext->SetGraphicsPipelineState(
     341           0 :         shaderTech->GetGraphicsPipelineState());
     342           0 :     deviceCommandContext->BeginPass();
     343             : 
     344           0 :     Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader();
     345             : 
     346           0 :     const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection();
     347           0 :     deviceCommandContext->SetUniform(
     348           0 :         shader->GetBindingSlot(str_transform), transform.AsFloatArray());
     349           0 :     deviceCommandContext->SetUniform(
     350           0 :         shader->GetBindingSlot(str_color), color.AsFloatArray());
     351             : 
     352           0 :     std::vector<float> data;
     353             : 
     354           0 :     std::vector<std::vector<size_t>> faces;
     355           0 :     brush.GetFaces(faces);
     356             : 
     357             : #define ADD_VERT(a) \
     358             :     STMT( \
     359             :         data.push_back(brush.GetVertices()[faces[i][a]].X); \
     360             :         data.push_back(brush.GetVertices()[faces[i][a]].Y); \
     361             :         data.push_back(brush.GetVertices()[faces[i][a]].Z); \
     362             :     )
     363             : 
     364           0 :     for (size_t i = 0; i < faces.size(); ++i)
     365             :     {
     366             :         // Triangulate into (0,1,2), (0,2,3), ...
     367           0 :         for (size_t j = 1; j < faces[i].size() - 2; ++j)
     368             :         {
     369           0 :             ADD_VERT(0);
     370           0 :             ADD_VERT(j);
     371           0 :             ADD_VERT(j+1);
     372             :         }
     373             :     }
     374             : 
     375             : #undef ADD_VERT
     376             : 
     377           0 :     deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout);
     378           0 :     deviceCommandContext->SetVertexBufferData(
     379           0 :         0, data.data(), data.size() * sizeof(data[0]));
     380             : 
     381           0 :     deviceCommandContext->Draw(0, data.size() / 5);
     382             : 
     383           0 :     deviceCommandContext->EndPass();
     384           0 : }
     385             : 
     386           0 : size_t CDebugRenderer::ShaderTechniqueKeyHash::operator()(
     387             :     const ShaderTechniqueKey& key) const
     388             : {
     389           0 :     size_t seed = 0;
     390           0 :     hash_combine(seed, key.name.GetHash());
     391           0 :     hash_combine(seed, key.transparent);
     392           0 :     hash_combine(seed, key.depthTestEnabled);
     393           0 :     hash_combine(seed, key.wireframe);
     394           0 :     return seed;
     395             : }
     396             : 
     397           0 : bool CDebugRenderer::ShaderTechniqueKeyEqual::operator()(
     398             :     const ShaderTechniqueKey& lhs, const ShaderTechniqueKey& rhs) const
     399             : {
     400             :     return
     401           0 :         lhs.name == rhs.name && lhs.transparent == rhs.transparent &&
     402           0 :         lhs.depthTestEnabled == rhs.depthTestEnabled &&
     403           0 :         lhs.wireframe == rhs.wireframe;
     404             : }
     405             : 
     406           0 : const CShaderTechniquePtr& CDebugRenderer::GetShaderTechnique(
     407             :     const CStrIntern name, const CColor& color, const bool depthTestEnabled,
     408             :     const bool wireframe)
     409             : {
     410             :     const ShaderTechniqueKey key{
     411           0 :         name, color.a != 1.0f, depthTestEnabled, wireframe};
     412           0 :     CShaderTechniquePtr& shaderTechnique = m_ShaderTechniqueMapping[key];
     413           0 :     if (shaderTechnique)
     414           0 :         return shaderTechnique;
     415             : 
     416           0 :     shaderTechnique = g_Renderer.GetShaderManager().LoadEffect(
     417             :         name, {},
     418           0 :         [key](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc)
     419             :         {
     420           0 :             pipelineStateDesc.depthStencilState.depthTestEnabled = key.depthTestEnabled;
     421           0 :             if (key.transparent)
     422             :             {
     423           0 :                 pipelineStateDesc.blendState.enabled = true;
     424           0 :                 pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor =
     425             :                     Renderer::Backend::BlendFactor::SRC_ALPHA;
     426           0 :                 pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor =
     427             :                     Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA;
     428           0 :                 pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp =
     429             :                     Renderer::Backend::BlendOp::ADD;
     430             :             }
     431             :             else
     432           0 :                 pipelineStateDesc.blendState.enabled = false;
     433           0 :             if (key.wireframe)
     434           0 :                 pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE;
     435           0 :             pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE;
     436           0 :         });
     437           0 :     return shaderTechnique;
     438           3 : }

Generated by: LCOV version 1.13