Cogs.Core
DebugGeometryRenderers.cpp
1#include <glm/gtc/type_ptr.hpp>
2#include <iterator>
3#include "Rendering/ICapabilities.h"
4#include "Rendering/IGraphicsDevice.h"
5#include "Rendering/IBuffers.h"
6#include "Rendering/IEffects.h"
7
8#include "Foundation/Logging/Logger.h"
9
10#include "Renderer/RenderList.h"
11#include "Renderer/Tasks/RenderTask.h"
12#include "Renderer/RenderStateUpdater.h"
13#include "Renderer/RenderTarget.h"
14#include "Renderer/Renderer.h"
15
16#include "Resources/VertexFormats.h"
17
18#include "Resources/MaterialManager.h"
19
20#include "DebugGeometryRenderers.h"
21
22namespace {
23 using namespace Cogs;
24 using namespace Cogs::Core;
25
26 const Cogs::Logging::Log logger = Cogs::Logging::getLogger("DebugGeometryRenderers");
27
28 struct DebugConstants
29 {
30 glm::mat4 projectionMatrix;
31 glm::mat4 viewMatrix;
32 glm::mat4 worldMatrix;
33 glm::vec4 diffuseColor;
34 };
35
36 Cogs::EffectHandle *effectHandleP;
37 Cogs::InputLayoutHandle *inputLayoutHandleP;
38 Cogs::VertexFormatHandle *vertexFormatP;
39 Cogs::ResourceStatus *effectStatusP;
40 Cogs::BufferHandle *constantBufferP;
41
42 const glm::mat4 identityMatrix = glm::mat4();
43
44 const glm::vec3 coordSysData[] = {
45 glm::vec3(0, 0, 0),
46 glm::vec3(1, 0, 0),
47 glm::vec3(0, 0, 0),
48 glm::vec3(0, 1, 0),
49 glm::vec3(0, 0, 0),
50 glm::vec3(0, 0, 1),
51 };
52 Cogs::VertexBufferHandle *coordSysVerticesP;
53
54 void setupCoordSysVertices(Cogs::IGraphicsDevice* device)
55 {
56 if (HandleIsValid(*coordSysVerticesP)) return;
57 auto * buffers = device->getBuffers();
58 *coordSysVerticesP = buffers->loadVertexBuffer(coordSysData, sizeof(coordSysData) / sizeof(glm::vec3), Cogs::Core::VertexFormats::Pos3f);
59 buffers->annotate(*coordSysVerticesP, "CoordSys vertices");
60 }
61
62 const glm::vec3 unitVerticesData[] = {
63 glm::vec3(0, 0, 0),
64 glm::vec3(1, 0, 0),
65 glm::vec3(0, 1, 0),
66 glm::vec3(1, 1, 0),
67
68 glm::vec3(0, 0, 1),
69 glm::vec3(1, 0, 1),
70 glm::vec3(0, 1, 1),
71 glm::vec3(1, 1, 1),
72 };
73 Cogs::VertexBufferHandle *unitVerticesP;
74
75 void setupUnitVertices(Cogs::IGraphicsDevice* device)
76 {
77 if (HandleIsValid(*unitVerticesP)) return;
78 auto * buffers = device->getBuffers();
79 *unitVerticesP = buffers->loadVertexBuffer(unitVerticesData, sizeof(unitVerticesData) / sizeof(glm::vec3), Cogs::Core::VertexFormats::Pos3f);
80 buffers->annotate(*unitVerticesP, "Unit box vertices");
81 }
82
83
84 const glm::vec3 oneOneVerticesData[] = {
85 glm::vec3(-1, -1, -1),
86 glm::vec3(1, -1, -1),
87 glm::vec3(-1, 1, -1),
88 glm::vec3(1, 1, -1),
89
90 glm::vec3(-1, -1, 1),
91 glm::vec3(1, -1, 1),
92 glm::vec3(-1, 1, 1),
93 glm::vec3(1, 1, 1),
94
95 // Near
96 glm::vec3(-1 + 0.1f, 1 - 0.1f, -1), // 8
97 glm::vec3(-1 + 0.3f, 1 - 0.1f, -1), // 9
98 glm::vec3(-1 + 0.1f, 1 - 0.3f, -1), // 10
99 glm::vec3(-1 + +.3f, 1 - 0.3f, -1), // 11
100
101 // Far
102 glm::vec3(1 - 0.1f, 1 - 0.1f, 1), // 12
103 glm::vec3(1 - 0.1f, 1 - 0.2f, 1), // 13
104 glm::vec3(1 - 0.1f, 1 - 0.3f, 1), // 14
105 glm::vec3(1 - 0.2f, 1 - 0.2f, 1), // 15
106 glm::vec3(1 - 0.3f, 1 - 0.1f, 1), // 16
107
108 // X +
109 glm::vec3(1, 1 - 0.1f, -1 + 0.1f), // 17
110 glm::vec3(1, 1 - 0.3f, -1 + 0.1f), // 18
111 glm::vec3(1, 1 - 0.1f, -1 + 0.3f), // 19
112 glm::vec3(1, 1 - 0.3f, -1 + 0.3f), // 20
113
114 glm::vec3(1, 1 - 0.2, -1 + 0.4f), // 21
115 glm::vec3(1, 1 - 0.2, -1 + 0.6f), // 22
116 glm::vec3(1, 1 - 0.1, -1 + 0.5f), // 23
117 glm::vec3(1, 1 - 0.3, -1 + 0.5f), // 24
118
119 // X -
120 glm::vec3(-1, 1 - 0.1f, 1 - 0.1f), // 25
121 glm::vec3(-1, 1 - 0.3f, 1 - 0.1f), // 26
122 glm::vec3(-1, 1 - 0.1f, 1 - 0.3f), // 27
123 glm::vec3(-1, 1 - 0.3f, 1 - 0.3f), // 28
124 glm::vec3(-1, 1 - 0.2, 1 - 0.4f), // 29
125 glm::vec3(-1, 1 - 0.2, 1 - 0.6f), // 30
126
127 // Y +
128 glm::vec3(1 - 0.1f, 1, -1 + 0.1f), // 31
129 glm::vec3(1 - 0.3f, 1, -1 + 0.1f), // 32
130 glm::vec3(1 - 0.2f, 1, -1 + 0.2f), // 33
131 glm::vec3(1 - 0.2f, 1, -1 + 0.3f), // 34
132
133 glm::vec3(1 - 0.4f, 1, -1 + 0.2f), // 35
134 glm::vec3(1 - 0.6f, 1, -1 + 0.2f), // 36
135 glm::vec3(1 - 0.5f, 1, -1 + 0.1f), // 37
136 glm::vec3(1 - 0.5f, 1, -1 + 0.3f), // 38
137
138 // Y-
139 glm::vec3(-1 + 0.1f, -1, -1 + 0.1f), // 39
140 glm::vec3(-1 + 0.3f, -1, -1 + 0.1f), // 40
141 glm::vec3(-1 + 0.2f, -1, -1 + 0.2f), // 41
142 glm::vec3(-1 + 0.2f, -1, -1 + 0.3f), // 42
143
144 glm::vec3(-1 + 0.4f, -1, -1 + 0.2f), // 43
145 glm::vec3(-1 + 0.6f, -1, -1 + 0.2f), // 44
146
147 };
148 Cogs::VertexBufferHandle *oneOneVerticesP;
149
150 void setupOneOneVertices(Cogs::IGraphicsDevice* device)
151 {
152 if (HandleIsValid(*oneOneVerticesP)) return;
153 auto * buffers = device->getBuffers();
154 *oneOneVerticesP = buffers->loadVertexBuffer(oneOneVerticesData, sizeof(oneOneVerticesData) / sizeof(glm::vec3), Cogs::Core::VertexFormats::Pos3f);
155 buffers->annotate(*oneOneVerticesP, "One-one box vertices");
156 }
157
158
159 const uint16_t edgeIndicesData[] = {
160 0, 1, 0, 2, 0, 4,
161 1, 3, 1, 5,
162 2, 3, 2, 6,
163 3, 7,
164 4, 5, 4, 6,
165 5, 7,
166 6, 7,
167
168 8, 10, 8, 11, 9, 11, // N
169 12, 13, 13, 14, 13, 15, 12, 16, // F
170 17, 20, 18, 19, 21, 22, 23, 24, // X+
171 25, 28, 26, 27, 29, 30, // X-
172 31, 33, 33, 32, 33, 34, 35, 36, 37, 38, // Y+
173 39, 41, 41, 40, 41, 42, 43, 44 // Y-
174 };
175 Cogs::IndexBufferHandle *edgeIndicesP;
176
177 void setupEdgeIndices(Cogs::IGraphicsDevice* device)
178 {
179 if (HandleIsValid(*edgeIndicesP)) return;
180 auto * buffers = device->getBuffers();
181 *edgeIndicesP = buffers->loadIndexBuffer(edgeIndicesData, sizeof(edgeIndicesData) / sizeof(uint16_t), sizeof(uint16_t));
182 buffers->annotate(*edgeIndicesP, "Box edge indices");
183 }
184
185 const glm::vec4 colors[6] =
186 {
187 glm::vec4(1.f, 0.f, 0.f, 1.f), // red
188 glm::vec4(0.f, 1.f, 0.f, 1.f), // green
189 glm::vec4(0.f, 0.f, 1.f, 1.f), // blue
190 glm::vec4(0.f, 1.f, 1.f, 1.f), // cyan
191 glm::vec4(1.f, 1.f, 0.f, 1.f), // yellow
192 glm::vec4(1.f, 0.f, 1.f, 1.f), // magenta
193 };
194
195 void setConstants(RenderTaskContext * taskContext, Cogs::BufferHandle constantBuffer, const glm::mat4 &M, const glm::vec4 &color)
196 {
197 auto * device = taskContext->device;
198 auto * context = device->getImmediateContext();
199
200 if (HandleIsValid(constantBuffer)) {
201 {
202 MappedBuffer<DebugConstants> constants(context, constantBuffer, MapMode::WriteDiscard);
203
204 if (constants) {
205 constants->projectionMatrix = M;
206 constants->viewMatrix = identityMatrix;
207 constants->worldMatrix = identityMatrix;
208 constants->diffuseColor = color;
209 }
210 }
211 context->setConstantBuffer("DebugBuffer", constantBuffer);
212 }
213 else{
214 assert(false);
215 }
216 }
217
218 // Polls effect readiness; lazily builds the input layout on the Pending/Error -> Ready
219 // transition (reflection data isn't valid until then). Returns true if the effect is
220 // ready to be used for drawing this frame.
221 bool checkEffectReady(Cogs::IGraphicsDevice * device)
222 {
223 Cogs::IEffects * effects = device->getEffects();
224 Cogs::ResourceStatus status = HandleIsValid(*effectHandleP) ? effects->checkEffect(*effectHandleP) : Cogs::ResourceStatus::Error;
225
226 if (status == Cogs::ResourceStatus::Ready && *effectStatusP != Cogs::ResourceStatus::Ready) {
227 *inputLayoutHandleP = device->getBuffers()->loadInputLayout(vertexFormatP, 1, *effectHandleP);
228 }
229
230 if (status == Cogs::ResourceStatus::Error && *effectStatusP != Cogs::ResourceStatus::Error) {
231 LOG_ERROR(logger, "DebugGeometryRenderers: Invalid debug effect handle.");
232 }
233
234 *effectStatusP = status;
235 return status == Cogs::ResourceStatus::Ready;
236 }
237
238 void drawWireBox(RenderTaskContext * taskContext, DrawContext * drawContext, Cogs::VertexBufferHandle vertices, Cogs::BufferHandle constantBuffer, const glm::mat4& M, const glm::vec4& color)
239 {
240 auto * renderer = taskContext->renderer;
241 auto * device = taskContext->device;
242 auto * context = device->getImmediateContext();
243 const auto * camData = drawContext->cameraData;
244
245 setupEdgeIndices(device);
246
247 if (!checkEffectReady(device)) return;
248
249 bool useCamData = 2.f < std::min(camData->viewportSize.x, camData->viewportSize.y);
250
251 context->setEffect(*effectHandleP);
252 context->setInputLayout(*inputLayoutHandleP);
253
254 auto w = useCamData ? camData->viewportSize.x : (drawContext->renderTarget ? drawContext->renderTarget->width : renderer->getSize().x);
255 auto h = useCamData ? camData->viewportSize.y : (drawContext->renderTarget ? drawContext->renderTarget->height : renderer->getSize().y);
256 context->setViewport(camData->viewportOrigin.x, camData->viewportOrigin.y, w, h);
257 context->setRasterizerState(taskContext->states->rasterizerStateHandles[drawContext->renderer->getRenderStates().getRasterizerState(Cogs::RasterizerState::DefaultState())]);
258 context->setDepthStencilState(drawContext->renderer->getRenderStates().commonDepthStates[RenderStates::defaultDepthStencilState]);
259 context->setBlendState(drawContext->renderer->getRenderStates().blendStates[size_t(BlendMode::None)].handle);
260 const uint32_t strides[] = { sizeof(glm::vec3) };
261 context->setVertexBuffers(&vertices, 1, strides, nullptr);
262 context->setIndexBuffer(*edgeIndicesP, 2);
263
264 setConstants(taskContext, constantBuffer, M, color);
265
266 context->drawIndexed(Cogs::PrimitiveType::LineList, 0, std::size(edgeIndicesData));
267 }
268
269 MaterialInstanceHandle *defaultMaterialInstanceP;
270}
271
272MaterialInstanceHandle Cogs::Core::getDefaultMaterialInstance(Context* context)
273{
274 if (!HandleIsValid(*defaultMaterialInstanceP)) {
275 *defaultMaterialInstanceP = context->materialInstanceManager->createMaterialInstance(context->materialManager->getDefaultMaterial());
276 }
277 return *defaultMaterialInstanceP;
278}
279
280void Cogs::Core::drawUnitWireBox(RenderTaskContext * taskContext, DrawContext * drawContext, const RenderItem * /*item*/, const glm::mat4& M, unsigned color)
281{
282 setupUnitVertices(taskContext->device);
283 drawWireBox(taskContext, drawContext, *unitVerticesP, *constantBufferP, M, colors[color % 6]);
284}
285
286void Cogs::Core::drawOneOneWireBox(RenderTaskContext * taskContext, DrawContext * drawContext, const RenderItem * /*item*/, const glm::mat4& M, unsigned color)
287{
288 setupOneOneVertices(taskContext->device);
289 drawWireBox(taskContext, drawContext, *oneOneVerticesP, *constantBufferP, M, colors[color % 6]);
290}
291
292void Cogs::Core::drawCoordSys(RenderTaskContext * taskContext, DrawContext * drawContext, const RenderItem * /*item*/, const glm::mat4& M, bool overlay)
293{
294 auto * renderer = taskContext->renderer;
295 auto * device = taskContext->device;
296 auto * context = device->getImmediateContext();
297 const auto * camData = drawContext->cameraData;
298
299 setupCoordSysVertices(taskContext->device);
300
301 if (!checkEffectReady(device)) return;
302
303 context->setEffect(*effectHandleP);
304 context->setInputLayout(*inputLayoutHandleP);
305
306 if (overlay) {
307 context->setDepthStencilState(drawContext->renderer->getRenderStates().commonDepthStates[RenderStates::noTestDepthStencilState]);
308 }
309 else {
310 bool useCamData = 2.f < std::min(camData->viewportSize.x, camData->viewportSize.y);
311 auto w = useCamData ? camData->viewportSize.x : (drawContext->renderTarget ? drawContext->renderTarget->width : renderer->getSize().x);
312 auto h = useCamData ? camData->viewportSize.y : (drawContext->renderTarget ? drawContext->renderTarget->height : renderer->getSize().y);
313 context->setViewport(camData->viewportOrigin.x, camData->viewportOrigin.y, w, h);
314 context->setDepthStencilState(drawContext->renderer->getRenderStates().commonDepthStates[RenderStates::defaultDepthStencilState]);
315 }
316
317 context->setRasterizerState(taskContext->states->rasterizerStateHandles[drawContext->renderer->getRenderStates().getRasterizerState(Cogs::RasterizerState::DefaultState())]);
318 context->setBlendState(drawContext->renderer->getRenderStates().blendStates[size_t(BlendMode::None)].handle);
319 const uint32_t strides[] = { sizeof(glm::vec3) };
320 context->setVertexBuffers(coordSysVerticesP, 1, strides, nullptr);
321
322 glm::vec4 colors3[3] = {
323 glm::vec4(1,0,0,1),
324 glm::vec4(0,1,0,1),
325 glm::vec4(0,0,1,1)
326 };
327 setConstants(taskContext, *constantBufferP, M, colors3[0]);
328 context->draw(Cogs::PrimitiveType::LineList, 0, 2);
329 setConstants(taskContext, *constantBufferP, M, colors3[1]);
330 context->draw(Cogs::PrimitiveType::LineList, 2, 2);
331 setConstants(taskContext, *constantBufferP, M, colors3[2]);
332 context->draw(Cogs::PrimitiveType::LineList, 4, 2);
333}
334
335void DebugGeometryRenderer::initialize(class Renderer* renderer, IGraphicsDevice * device)
336{
337 auto buffers = device->getBuffers();
338 Cogs::EffectDescription desc = {};
339 desc.name = "DebugEffect";
340 desc.flags = renderer->getEffectFlags();
341 desc.type = EffectDescriptionType::File;
342 switch (device->getType()) {
344 desc.vertexShader = "Engine/DebugVS.wgsl";
345 desc.pixelShader = "Engine/DebugPS.wgsl";
346 desc.vsEntryPoint = "vs_main";
347 desc.psEntryPoint = "fs_main";
348 desc.flags = static_cast<EffectFlags::EEffectFlags>(desc.flags | EffectFlags::WGSL);
349 break;
351 desc.vertexShader = "Engine/DebugVS.es30.glsl";
352 desc.pixelShader = "Engine/DebugPS.es30.glsl";
353 desc.flags = static_cast<EffectFlags::EEffectFlags>(desc.flags | EffectFlags::GLSL);
354 break;
355 default:
356 desc.vertexShader = "Engine/DebugVS.hlsl";
357 desc.pixelShader = "Engine/DebugPS.hlsl";
358 break;
359 }
360 effectHandle = device->getEffects()->loadEffect(desc);
361
362 VertexElement elements[] = {
363 { 0, DataFormat::X32Y32Z32_FLOAT, ElementSemantic::Position, 0, InputType::VertexData, 0 }
364 };
365 vertexFormat = buffers->createVertexFormat(elements, 1);
366
367 constantBuffer = device->getBuffers()->loadBuffer(nullptr, sizeof(DebugConstants), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
368 device->getBuffers()->annotate(constantBuffer, "DebugGeometryConstants");
369
370 effectHandleP = &effectHandle;
371 inputLayoutHandleP = &inputLayoutHandle;
372 vertexFormatP = &vertexFormat;
373 effectStatusP = &effectStatus;
374 constantBufferP = &constantBuffer;
375 coordSysVerticesP = &coordSysVertices;
376 unitVerticesP = &unitVertices;
377 oneOneVerticesP = &oneOneVertices;
378 edgeIndicesP = &edgeIndices;
379 defaultMaterialInstanceP = &defaultMaterialInstance;
380}
381void DebugGeometryRenderer::cleanup()
382{
384 inputLayoutHandle = Cogs::InputLayoutHandle::InvalidHandle;
386 effectStatus = Cogs::ResourceStatus::Pending;
387 constantBuffer = Cogs::BufferHandle::InvalidHandle;
392 defaultMaterialInstance = MaterialInstanceHandle::NoHandle;
393 effectHandleP = nullptr;
394 inputLayoutHandleP = nullptr;
395 constantBufferP = nullptr;
396 coordSysVerticesP = nullptr;
397 unitVerticesP = nullptr;
398 oneOneVerticesP = nullptr;
399 edgeIndicesP = nullptr;
400 defaultMaterialInstanceP = nullptr;
401}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
Core renderer system.
Definition: Renderer.h:29
RenderStates & getRenderStates() override
Get the reference to the RenderStates structure.
Definition: Renderer.h:70
EffectFlags::EEffectFlags getEffectFlags() const override
Get the EffectFlags.
Definition: Renderer.h:71
Represents a graphics device used to manage graphics resources and issue drawing commands.
virtual IEffects * getEffects()=0
Get a pointer to the effect management interface.
virtual IContext * getImmediateContext()=0
Get a pointer to the immediate context used to issue commands to the graphics device.
virtual IBuffers * getBuffers()=0
Get a pointer to the buffer management interface.
virtual GraphicsDeviceType getType() const
Get the type of the graphics device.
Log implementation class.
Definition: LogManager.h:140
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ OpenGLES30
Graphics device using the OpenGLES 3.0 API.
@ WebGPU
Graphics device using the WebGPU API Backend.
ResourceStatus
Status of an asynchronously loaded resource, such as an effect or a pipeline.
Definition: Common.h:198
@ Pending
The resource is still loading.
@ Error
The resource failed to load.
@ Ready
The resource has loaded successfully and is ready for use.
@ VertexData
Per vertex data.
@ LineList
List of lines.
@ Position
Position semantic.
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
Contains an effect description used to load a single effect.
Definition: IEffects.h:62
EEffectFlags
Effect source flags.
Definition: IEffects.h:27
@ WGSL
Effect source is WGSL.
Definition: IEffects.h:43
@ GLSL
Effect source is GLSL.
Definition: IEffects.h:33
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:81
virtual void annotate(BufferHandle handle, const StringView &name)
Associate a name with an object for use in graphics debugging.
Definition: IBuffers.h:17
virtual InputLayoutHandle loadInputLayout(const VertexFormatHandle *vertexFormats, const size_t count, EffectHandle effectHandle)=0
Loads a new input layout to map vertex flow between vertex buffers with the given vertexFormats to ef...
virtual BufferHandle loadBuffer(const void *data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride=0)=0
Loads a new buffer using the given data to populate the buffer.
Provides effects and shader management functionality.
Definition: IEffects.h:158
virtual EffectHandle loadEffect(const EffectDescription &description)=0
Load an effect from the given description.
virtual ResourceStatus checkEffect(EffectHandle effectHandle)=0
Check the load status of the effect with the given effectHandle.
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.
Definition: Flags.h:103
Provides RAII style mapping of a buffer resource.
Definition: IBuffers.h:160
static RasterizerState DefaultState()
Constructs a rasterizer state initialized with the default values.
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30
Vertex element structure used to describe a single data element in a vertex for the input assembler.
Definition: VertexFormat.h:38