source: ps/trunk/source/renderer/DebugRenderer.cpp

Last change on this file was 27965, checked in by Vladislav Belov, 8 months ago

Revert non-ASCII characters from source and configuration files introduced in rP27786.

Fixes #6846

Differential Revision: https://code.wildfiregames.com/D5185

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