2
0

DebugRendererImp.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Renderer/DebugRendererImp.h>
  6. #include <Renderer/Renderer.h>
  7. #include <Renderer/RenderPrimitive.h>
  8. #include <Renderer/Texture.h>
  9. #include <Renderer/Font.h>
  10. #ifndef JPH_DEBUG_RENDERER
  11. // Hack to still compile DebugRenderer inside the test framework when Jolt is compiled without
  12. #define JPH_DEBUG_RENDERER
  13. #include <Jolt/Renderer/DebugRenderer.cpp>
  14. #undef JPH_DEBUG_RENDERER
  15. #endif // !JPH_DEBUG_RENDERER
  16. DebugRendererImp::DebugRendererImp(Renderer *inRenderer, const Font *inFont) :
  17. mRenderer(inRenderer),
  18. mFont(inFont)
  19. {
  20. // Create input layout for lines
  21. const D3D12_INPUT_ELEMENT_DESC line_vertex_desc[] =
  22. {
  23. { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  24. { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  25. };
  26. // Lines
  27. ComPtr<ID3DBlob> vtx_line = mRenderer->CreateVertexShader("Assets/Shaders/LineVertexShader.hlsl");
  28. ComPtr<ID3DBlob> pix_line = mRenderer->CreatePixelShader("Assets/Shaders/LinePixelShader.hlsl");
  29. mLineState = mRenderer->CreatePipelineState(vtx_line.Get(), line_vertex_desc, ARRAYSIZE(line_vertex_desc), pix_line.Get(), D3D12_FILL_MODE_SOLID, D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
  30. // Create input layout for triangles
  31. const D3D12_INPUT_ELEMENT_DESC triangles_vertex_desc[] =
  32. {
  33. { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  34. { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  35. { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  36. { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 32, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  37. { "INSTANCE_TRANSFORM", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
  38. { "INSTANCE_TRANSFORM", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 16, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
  39. { "INSTANCE_TRANSFORM", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 32, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
  40. { "INSTANCE_TRANSFORM", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 48, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
  41. { "INSTANCE_INV_TRANSFORM", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 64, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
  42. { "INSTANCE_INV_TRANSFORM", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 80, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
  43. { "INSTANCE_INV_TRANSFORM", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 96, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
  44. { "INSTANCE_INV_TRANSFORM", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 112, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
  45. { "INSTANCE_COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 128, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
  46. };
  47. // Triangles
  48. ComPtr<ID3DBlob> vtx_triangle = mRenderer->CreateVertexShader("Assets/Shaders/TriangleVertexShader.hlsl");
  49. ComPtr<ID3DBlob> pix_triangle = mRenderer->CreatePixelShader("Assets/Shaders/TrianglePixelShader.hlsl");
  50. mTriangleStateBF = mRenderer->CreatePipelineState(vtx_triangle.Get(), triangles_vertex_desc, ARRAYSIZE(triangles_vertex_desc), pix_triangle.Get(), D3D12_FILL_MODE_SOLID, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
  51. mTriangleStateFF = mRenderer->CreatePipelineState(vtx_triangle.Get(), triangles_vertex_desc, ARRAYSIZE(triangles_vertex_desc), pix_triangle.Get(), D3D12_FILL_MODE_SOLID, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::FrontFace);
  52. mTriangleStateWire = mRenderer->CreatePipelineState(vtx_triangle.Get(), triangles_vertex_desc, ARRAYSIZE(triangles_vertex_desc), pix_triangle.Get(), D3D12_FILL_MODE_WIREFRAME, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
  53. // Shadow pass
  54. ComPtr<ID3DBlob> vtx_shadow = mRenderer->CreateVertexShader("Assets/Shaders/TriangleDepthVertexShader.hlsl");
  55. ComPtr<ID3DBlob> pix_shadow = mRenderer->CreatePixelShader("Assets/Shaders/TriangleDepthPixelShader.hlsl");
  56. mShadowStateBF = mRenderer->CreatePipelineState(vtx_shadow.Get(), triangles_vertex_desc, ARRAYSIZE(triangles_vertex_desc), pix_shadow.Get(), D3D12_FILL_MODE_SOLID, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
  57. mShadowStateFF = mRenderer->CreatePipelineState(vtx_shadow.Get(), triangles_vertex_desc, ARRAYSIZE(triangles_vertex_desc), pix_shadow.Get(), D3D12_FILL_MODE_SOLID, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::FrontFace);
  58. mShadowStateWire = mRenderer->CreatePipelineState(vtx_shadow.Get(), triangles_vertex_desc, ARRAYSIZE(triangles_vertex_desc), pix_shadow.Get(), D3D12_FILL_MODE_WIREFRAME, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, PipelineState::EDepthTest::On, PipelineState::EBlendMode::AlphaBlend, PipelineState::ECullMode::Backface);
  59. // Create depth only texture (no color buffer, as seen from light)
  60. mDepthTexture = mRenderer->CreateRenderTarget(4096, 4096);
  61. // Create instances buffer
  62. for (uint n = 0; n < Renderer::cFrameCount; ++n)
  63. mInstancesBuffer[n] = new RenderInstances(mRenderer);
  64. // Create empty batch
  65. Vertex empty_vertex { Float3(0, 0, 0), Float3(1, 0, 0), Float2(0, 0), Color::sWhite };
  66. uint32 empty_indices[] = { 0, 0, 0 };
  67. mEmptyBatch = CreateTriangleBatch(&empty_vertex, 1, empty_indices, 3);
  68. // Initialize base class
  69. DebugRenderer::Initialize();
  70. }
  71. void DebugRendererImp::DrawLine(RVec3Arg inFrom, RVec3Arg inTo, ColorArg inColor)
  72. {
  73. RVec3 offset = mRenderer->GetBaseOffset();
  74. Line line;
  75. Vec3(inFrom - offset).StoreFloat3(&line.mFrom);
  76. line.mFromColor = inColor;
  77. Vec3(inTo - offset).StoreFloat3(&line.mTo);
  78. line.mToColor = inColor;
  79. lock_guard lock(mLinesLock);
  80. mLines.push_back(line);
  81. }
  82. DebugRenderer::Batch DebugRendererImp::CreateTriangleBatch(const Triangle *inTriangles, int inTriangleCount)
  83. {
  84. if (inTriangles == nullptr || inTriangleCount == 0)
  85. return mEmptyBatch;
  86. BatchImpl *primitive = new BatchImpl(mRenderer, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  87. primitive->CreateVertexBuffer(3 * inTriangleCount, sizeof(Vertex), inTriangles);
  88. return primitive;
  89. }
  90. DebugRenderer::Batch DebugRendererImp::CreateTriangleBatch(const Vertex *inVertices, int inVertexCount, const uint32 *inIndices, int inIndexCount)
  91. {
  92. if (inVertices == nullptr || inVertexCount == 0 || inIndices == nullptr || inIndexCount == 0)
  93. return mEmptyBatch;
  94. BatchImpl *primitive = new BatchImpl(mRenderer, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  95. primitive->CreateVertexBuffer(inVertexCount, sizeof(Vertex), inVertices);
  96. primitive->CreateIndexBuffer(inIndexCount, inIndices);
  97. return primitive;
  98. }
  99. void DebugRendererImp::DrawGeometry(RMat44Arg inModelMatrix, const AABox &inWorldSpaceBounds, float inLODScaleSq, ColorArg inModelColor, const GeometryRef &inGeometry, ECullMode inCullMode, ECastShadow inCastShadow, EDrawMode inDrawMode)
  100. {
  101. lock_guard lock(mPrimitivesLock);
  102. RVec3 offset = mRenderer->GetBaseOffset();
  103. Mat44 model_matrix = inModelMatrix.PostTranslated(-offset).ToMat44();
  104. AABox world_space_bounds = inWorldSpaceBounds;
  105. world_space_bounds.Translate(Vec3(-offset));
  106. // Our pixel shader uses alpha only to turn on/off shadows
  107. Color color = inCastShadow == ECastShadow::On? Color(inModelColor, 255) : Color(inModelColor, 0);
  108. if (inDrawMode == EDrawMode::Wireframe)
  109. {
  110. mWireframePrimitives[inGeometry].mInstances.push_back({ model_matrix, model_matrix.GetDirectionPreservingMatrix(), color, world_space_bounds, inLODScaleSq });
  111. ++mNumInstances;
  112. }
  113. else
  114. {
  115. if (inCullMode != ECullMode::CullFrontFace)
  116. {
  117. mPrimitives[inGeometry].mInstances.push_back({ model_matrix, model_matrix.GetDirectionPreservingMatrix(), color, world_space_bounds, inLODScaleSq });
  118. ++mNumInstances;
  119. }
  120. if (inCullMode != ECullMode::CullBackFace)
  121. {
  122. mPrimitivesBackFacing[inGeometry].mInstances.push_back({ model_matrix, model_matrix.GetDirectionPreservingMatrix(), color, world_space_bounds, inLODScaleSq });
  123. ++mNumInstances;
  124. }
  125. }
  126. }
  127. void DebugRendererImp::FinalizePrimitive()
  128. {
  129. JPH_PROFILE_FUNCTION();
  130. if (mLockedPrimitive != nullptr)
  131. {
  132. BatchImpl *primitive = static_cast<BatchImpl *>(mLockedPrimitive.GetPtr());
  133. // Unlock the primitive
  134. primitive->UnlockVertexBuffer();
  135. // Set number of indices to draw
  136. primitive->SetNumVtxToDraw(int(mLockedVertices - mLockedVerticesStart));
  137. // Add to draw list
  138. mTempPrimitives[new Geometry(mLockedPrimitive, mLockedPrimitiveBounds)].mInstances.push_back({ Mat44::sIdentity(), Mat44::sIdentity(), Color::sWhite, mLockedPrimitiveBounds, 1.0f });
  139. ++mNumInstances;
  140. // Clear pointers
  141. mLockedPrimitive = nullptr;
  142. mLockedVerticesStart = nullptr;
  143. mLockedVertices = nullptr;
  144. mLockedVerticesEnd = nullptr;
  145. mLockedPrimitiveBounds = AABox();
  146. }
  147. }
  148. void DebugRendererImp::EnsurePrimitiveSpace(int inVtxSize)
  149. {
  150. const int cVertexBufferSize = 10240;
  151. if (mLockedPrimitive == nullptr
  152. || mLockedVerticesEnd - mLockedVertices < inVtxSize)
  153. {
  154. FinalizePrimitive();
  155. // Create new
  156. BatchImpl *primitive = new BatchImpl(mRenderer, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  157. primitive->CreateVertexBuffer(cVertexBufferSize, sizeof(Vertex));
  158. mLockedPrimitive = primitive;
  159. // Lock buffers
  160. mLockedVerticesStart = mLockedVertices = (Vertex *)primitive->LockVertexBuffer();
  161. mLockedVerticesEnd = mLockedVertices + cVertexBufferSize;
  162. }
  163. }
  164. void DebugRendererImp::DrawTriangle(RVec3Arg inV1, RVec3Arg inV2, RVec3Arg inV3, ColorArg inColor, ECastShadow inCastShadow)
  165. {
  166. RVec3 offset = mRenderer->GetBaseOffset();
  167. Vec3 v1(inV1 - offset);
  168. Vec3 v2(inV2 - offset);
  169. Vec3 v3(inV3 - offset);
  170. lock_guard lock(mPrimitivesLock);
  171. EnsurePrimitiveSpace(3);
  172. // Set alpha to zero if we don't want to cast shadows to notify the pixel shader
  173. Color color(inColor, inCastShadow == ECastShadow::Off? 0 : 0xff);
  174. // Construct triangle
  175. new ((Triangle *)mLockedVertices) Triangle(v1, v2, v3, color);
  176. mLockedVertices += 3;
  177. // Update bounding box
  178. mLockedPrimitiveBounds.Encapsulate(v1);
  179. mLockedPrimitiveBounds.Encapsulate(v2);
  180. mLockedPrimitiveBounds.Encapsulate(v3);
  181. }
  182. void DebugRendererImp::DrawInstances(const Geometry *inGeometry, const Array<int> &inStartIdx)
  183. {
  184. RenderInstances *instances_buffer = mInstancesBuffer[mRenderer->GetCurrentFrameIndex()];
  185. if (!inStartIdx.empty())
  186. {
  187. // Get LODs
  188. const Array<LOD> &geometry_lods = inGeometry->mLODs;
  189. // Write instances for all LODS
  190. int next_start_idx = inStartIdx.front();
  191. for (size_t lod = 0; lod < geometry_lods.size(); ++lod)
  192. {
  193. int start_idx = next_start_idx;
  194. next_start_idx = inStartIdx[lod + 1];
  195. int num_instances = next_start_idx - start_idx;
  196. instances_buffer->Draw(static_cast<BatchImpl *>(geometry_lods[lod].mTriangleBatch.GetPtr()), start_idx, num_instances);
  197. }
  198. }
  199. }
  200. void DebugRendererImp::DrawText3D(RVec3Arg inPosition, const string_view &inString, ColorArg inColor, float inHeight)
  201. {
  202. RVec3 offset = mRenderer->GetBaseOffset();
  203. Vec3 pos(inPosition - offset);
  204. lock_guard lock(mTextsLock);
  205. mTexts.emplace_back(pos, inString, inColor, inHeight);
  206. }
  207. void DebugRendererImp::DrawLines()
  208. {
  209. JPH_PROFILE_FUNCTION();
  210. lock_guard lock(mLinesLock);
  211. // Draw the lines
  212. if (!mLines.empty())
  213. {
  214. RenderPrimitive primitive(mRenderer, D3D_PRIMITIVE_TOPOLOGY_LINELIST);
  215. primitive.CreateVertexBuffer((int)mLines.size() * 2, sizeof(Line) / 2);
  216. void *data = primitive.LockVertexBuffer();
  217. memcpy(data, &mLines[0], mLines.size() * sizeof(Line));
  218. primitive.UnlockVertexBuffer();
  219. mLineState->Activate();
  220. primitive.Draw();
  221. }
  222. }
  223. void DebugRendererImp::DrawTriangles()
  224. {
  225. JPH_PROFILE_FUNCTION();
  226. lock_guard lock(mPrimitivesLock);
  227. // Finish the last primitive
  228. FinalizePrimitive();
  229. // Render to shadow map texture first
  230. mRenderer->SetRenderTarget(mDepthTexture);
  231. // Clear the shadow map texture to max depth
  232. mDepthTexture->ClearRenderTarget();
  233. // Get the camera and light frustum for culling
  234. Vec3 camera_pos(mRenderer->GetCameraState().mPos - mRenderer->GetBaseOffset());
  235. const Frustum &camera_frustum = mRenderer->GetCameraFrustum();
  236. const Frustum &light_frustum = mRenderer->GetLightFrustum();
  237. // Resize instances buffer and copy all visible instance data into it
  238. if (mNumInstances > 0)
  239. {
  240. // Create instances buffer
  241. RenderInstances *instances_buffer = mInstancesBuffer[mRenderer->GetCurrentFrameIndex()];
  242. instances_buffer->CreateBuffer(2 * mNumInstances, sizeof(Instance));
  243. Instance *dst_instance = reinterpret_cast<Instance *>(instances_buffer->Lock());
  244. // Next write index
  245. int dst_index = 0;
  246. // This keeps track of which instances use which lod, first array: 0 = light pass, 1 = geometry pass
  247. Array<Array<int>> lod_indices[2];
  248. for (InstanceMap *primitive_map : { &mPrimitives, &mTempPrimitives, &mPrimitivesBackFacing, &mWireframePrimitives })
  249. for (InstanceMap::value_type &v : *primitive_map)
  250. {
  251. // Get LODs
  252. const Array<LOD> &geometry_lods = v.first->mLODs;
  253. size_t num_lods = geometry_lods.size();
  254. JPH_ASSERT(num_lods > 0);
  255. // Ensure that our lod index array is big enough (to avoid reallocating memory too often)
  256. if (lod_indices[0].size() < num_lods)
  257. lod_indices[0].resize(num_lods);
  258. if (lod_indices[1].size() < num_lods)
  259. lod_indices[1].resize(num_lods);
  260. // Iterate over all instances
  261. const Array<InstanceWithLODInfo> &instances = v.second.mInstances;
  262. for (size_t i = 0; i < instances.size(); ++i)
  263. {
  264. const InstanceWithLODInfo &src_instance = instances[i];
  265. // Check if it overlaps with the light or camera frustum
  266. bool light_overlaps = light_frustum.Overlaps(src_instance.mWorldSpaceBounds);
  267. bool camera_overlaps = camera_frustum.Overlaps(src_instance.mWorldSpaceBounds);
  268. if (light_overlaps || camera_overlaps)
  269. {
  270. // Figure out which LOD to use
  271. float dist_sq = src_instance.mWorldSpaceBounds.GetSqDistanceTo(camera_pos);
  272. for (size_t lod = 0; lod < num_lods; ++lod)
  273. if (dist_sq <= src_instance.mLODScaleSq * Square(geometry_lods[lod].mDistance))
  274. {
  275. // Store which index goes in which LOD
  276. if (light_overlaps)
  277. lod_indices[0][lod].push_back((int)i);
  278. if (camera_overlaps)
  279. lod_indices[1][lod].push_back((int)i);
  280. break;
  281. }
  282. }
  283. }
  284. // Loop over both passes: 0 = light, 1 = geometry
  285. Array<int> *start_idx[] = { &v.second.mLightStartIdx, &v.second.mGeometryStartIdx };
  286. for (int type = 0; type < 2; ++type)
  287. {
  288. // Reserve space for instance indices
  289. Array<int> &type_start_idx = *start_idx[type];
  290. type_start_idx.resize(num_lods + 1);
  291. // Write out geometry pass instances
  292. for (size_t lod = 0; lod < num_lods; ++lod)
  293. {
  294. // Write start index for this LOD
  295. type_start_idx[lod] = dst_index;
  296. // Copy instances
  297. Array<int> &this_lod_indices = lod_indices[type][lod];
  298. for (int i : this_lod_indices)
  299. {
  300. const Instance &src_instance = instances[i];
  301. dst_instance[dst_index++] = src_instance;
  302. }
  303. // Prepare for next iteration (will preserve memory)
  304. this_lod_indices.clear();
  305. }
  306. // Write out end of last LOD
  307. type_start_idx.back() = dst_index;
  308. }
  309. }
  310. instances_buffer->Unlock();
  311. }
  312. if (!mPrimitives.empty() || !mTempPrimitives.empty())
  313. {
  314. // Front face culling, we want to render the back side of the geometry for casting shadows
  315. mShadowStateFF->Activate();
  316. // Draw all primitives as seen from the light
  317. if (mNumInstances > 0)
  318. for (InstanceMap::value_type &v : mPrimitives)
  319. DrawInstances(v.first, v.second.mLightStartIdx);
  320. for (InstanceMap::value_type &v : mTempPrimitives)
  321. DrawInstances(v.first, v.second.mLightStartIdx);
  322. }
  323. if (!mPrimitivesBackFacing.empty())
  324. {
  325. // Back face culling, we want to render the front side of back facing geometry
  326. mShadowStateBF->Activate();
  327. // Draw all primitives as seen from the light
  328. for (InstanceMap::value_type &v : mPrimitivesBackFacing)
  329. DrawInstances(v.first, v.second.mLightStartIdx);
  330. }
  331. if (!mWireframePrimitives.empty())
  332. {
  333. // Switch to wireframe mode
  334. mShadowStateWire->Activate();
  335. // Draw all wireframe primitives as seen from the light
  336. for (InstanceMap::value_type &v : mWireframePrimitives)
  337. DrawInstances(v.first, v.second.mLightStartIdx);
  338. }
  339. // Switch to the main render target
  340. mRenderer->SetRenderTarget(nullptr);
  341. // Bind the shadow map texture
  342. mDepthTexture->Bind(2);
  343. if (!mPrimitives.empty() || !mTempPrimitives.empty())
  344. {
  345. // Bind the normal shader, back face culling
  346. mTriangleStateBF->Activate();
  347. // Draw all primitives
  348. if (mNumInstances > 0)
  349. for (InstanceMap::value_type &v : mPrimitives)
  350. DrawInstances(v.first, v.second.mGeometryStartIdx);
  351. for (InstanceMap::value_type &v : mTempPrimitives)
  352. DrawInstances(v.first, v.second.mGeometryStartIdx);
  353. }
  354. if (!mPrimitivesBackFacing.empty())
  355. {
  356. // Front face culling, the next batch needs to render inside out
  357. mTriangleStateFF->Activate();
  358. // Draw all back primitives
  359. for (InstanceMap::value_type &v : mPrimitivesBackFacing)
  360. DrawInstances(v.first, v.second.mGeometryStartIdx);
  361. }
  362. if (!mWireframePrimitives.empty())
  363. {
  364. // Wire frame mode
  365. mTriangleStateWire->Activate();
  366. // Draw all wireframe primitives
  367. for (InstanceMap::value_type &v : mWireframePrimitives)
  368. DrawInstances(v.first, v.second.mGeometryStartIdx);
  369. }
  370. }
  371. void DebugRendererImp::DrawTexts()
  372. {
  373. lock_guard lock(mTextsLock);
  374. JPH_PROFILE_FUNCTION();
  375. const CameraState &camera_state = mRenderer->GetCameraState();
  376. for (const Text &t : mTexts)
  377. {
  378. Vec3 forward = camera_state.mForward;
  379. Vec3 right = forward.Cross(camera_state.mUp).Normalized();
  380. Vec3 up = right.Cross(forward).Normalized();
  381. Mat44 transform(Vec4(right, 0), Vec4(up, 0), Vec4(forward, 0), Vec4(t.mPosition, 1));
  382. mFont->DrawText3D(transform * Mat44::sScale(t.mHeight), t.mText, t.mColor);
  383. }
  384. }
  385. void DebugRendererImp::Draw()
  386. {
  387. DrawLines();
  388. DrawTriangles();
  389. DrawTexts();
  390. }
  391. void DebugRendererImp::ClearLines()
  392. {
  393. lock_guard lock(mLinesLock);
  394. mLines.clear();
  395. }
  396. void DebugRendererImp::ClearMap(InstanceMap &ioInstances)
  397. {
  398. Array<GeometryRef> to_delete;
  399. for (InstanceMap::value_type &kv : ioInstances)
  400. {
  401. if (kv.second.mInstances.empty())
  402. to_delete.push_back(kv.first);
  403. else
  404. kv.second.mInstances.clear();
  405. }
  406. for (GeometryRef &b : to_delete)
  407. ioInstances.erase(b);
  408. }
  409. void DebugRendererImp::ClearTriangles()
  410. {
  411. lock_guard lock(mPrimitivesLock);
  412. // Close any primitive that's being built
  413. FinalizePrimitive();
  414. // Move primitives to draw back to the free list
  415. ClearMap(mWireframePrimitives);
  416. ClearMap(mPrimitives);
  417. mTempPrimitives.clear(); // These are created by FinalizePrimitive() and need to be cleared every frame
  418. ClearMap(mPrimitivesBackFacing);
  419. mNumInstances = 0;
  420. }
  421. void DebugRendererImp::ClearTexts()
  422. {
  423. lock_guard lock(mTextsLock);
  424. mTexts.clear();
  425. }
  426. void DebugRendererImp::Clear()
  427. {
  428. ClearLines();
  429. ClearTriangles();
  430. ClearTexts();
  431. }