From c445d7d9a9d2708d5c2c359899d6f37a20be286c Mon Sep 17 00:00:00 2001 From: AbigailBuccaneer Date: Sun, 29 Apr 2018 23:37:41 +0100 Subject: [PATCH] Add generic debug rendering functions Currently the engine can draw debug spheres to show crash sphere positions. This extends this to draw arbitrary spheres and cuboids, transformed arbitrarily. With these in place it's now very quick and easy to create a debug visualisation - for example, it's a one-line code change to render the bounding box or sphere of every EngineObject. --- src/graphics/engine/engine.cpp | 179 ++++++++++++++++++++------------- src/graphics/engine/engine.h | 14 ++- src/level/robotmain.cpp | 8 +- 3 files changed, 123 insertions(+), 78 deletions(-) diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 23ed2108..8722f1af 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -3147,24 +3147,6 @@ void CEngine::ApplyChange() } } -void CEngine::ClearDisplayCrashSpheres() -{ - m_displayCrashSpheres.clear(); - - m_debugCrashSpheres = false; -} - -void CEngine::AddDisplayCrashSpheres(const std::vector& crashSpheres) -{ - for (const auto& crashSphere : crashSpheres) - { - m_displayCrashSpheres.push_back(crashSphere); - } - - m_debugCrashSpheres = true; -} - - /******************************************************* Rendering *******************************************************/ @@ -3483,8 +3465,7 @@ void CEngine::Draw3DScene() m_device->SetRenderState(RENDER_STATE_LIGHTING, false); - if (m_debugCrashSpheres) - DrawCrashSpheres(); + RenderPendingDebugDraws(); if (m_debugGoto) { @@ -3651,74 +3632,136 @@ void CEngine::DrawCaptured3DScene() m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertices, 4); } -void CEngine::DrawCrashSpheres() +void CEngine::RenderDebugSphere(const Math::Sphere& sphere, const Math::Matrix& transform, const Gfx::Color& color) { - Math::Matrix worldMatrix; - worldMatrix.LoadIdentity(); - m_device->SetTransform(TRANSFORM_WORLD, worldMatrix); + static constexpr int LONGITUDE_DIVISIONS = 16; + static constexpr int LATITUDE_DIVISIONS = 8; + static constexpr int NUM_LINE_STRIPS = 2 + LONGITUDE_DIVISIONS + LATITUDE_DIVISIONS; + static constexpr int VERTS_IN_LINE_STRIP = 32; - SetState(ENG_RSTATE_OPAQUE_COLOR); + static std::array verticesTemplate = []{ + std::array vertices; - static const int LINE_SEGMENTS = 32; - static const int LONGITUDE_DIVISIONS = 16; - static const int LATITUDE_DIVISIONS = 8; + auto SpherePoint = [&](float latitude, float longitude) + { + float latitudeAngle = (latitude - 0.5f) * 2.0f * Math::PI; + float longitudeAngle = longitude * 2.0f * Math::PI; + return Math::Vector(sinf(latitudeAngle) * cosf(longitudeAngle), + cosf(latitudeAngle), + sinf(latitudeAngle) * sinf(longitudeAngle)); + }; - std::vector lines((2 + LONGITUDE_DIVISIONS + LATITUDE_DIVISIONS) * LINE_SEGMENTS); - std::vector firsts(2 + LONGITUDE_DIVISIONS + LATITUDE_DIVISIONS); - std::vector counts(2 + LONGITUDE_DIVISIONS + LATITUDE_DIVISIONS); - - Color color(0.0f, 0.0f, 1.0f); - - auto SpherePoint = [&](float sphereRadius, float latitude, float longitude) - { - float latitudeAngle = (latitude - 0.5f) * 2.0f * Math::PI; - float longitudeAngle = longitude * 2.0f * Math::PI; - return Math::Vector(sphereRadius * sinf(latitudeAngle) * cosf(longitudeAngle), - sphereRadius * cosf(latitudeAngle), - sphereRadius * sinf(latitudeAngle) * sinf(longitudeAngle)); - }; - - for (const auto& crashSphere : m_displayCrashSpheres) - { - int i = 0; - int primitive = 0; + auto vert = vertices.begin(); for (int longitudeDivision = 0; longitudeDivision <= LONGITUDE_DIVISIONS; ++longitudeDivision) { - firsts[primitive] = i; - counts[primitive] = LINE_SEGMENTS; - - for (int segment = 0; segment < LINE_SEGMENTS; ++segment) + for (int segment = 0; segment < VERTS_IN_LINE_STRIP; ++segment) { - Math::Vector pos = crashSphere.pos; - float latitude = static_cast(segment) / LINE_SEGMENTS; + float latitude = static_cast(segment) / VERTS_IN_LINE_STRIP; float longitude = static_cast(longitudeDivision) / (LONGITUDE_DIVISIONS); - pos += SpherePoint(crashSphere.radius, latitude, longitude); - lines[i++] = VertexCol(pos, color); + *vert++ = SpherePoint(latitude, longitude); } - - primitive++; } for (int latitudeDivision = 0; latitudeDivision <= LATITUDE_DIVISIONS; ++latitudeDivision) { - firsts[primitive] = i; - counts[primitive] = LINE_SEGMENTS; - - for (int segment = 0; segment < LINE_SEGMENTS; ++segment) + for (int segment = 0; segment < VERTS_IN_LINE_STRIP; ++segment) { - Math::Vector pos = crashSphere.pos; float latitude = static_cast(latitudeDivision + 1) / (LATITUDE_DIVISIONS + 2); - float longitude = static_cast(segment) / LINE_SEGMENTS; - pos += SpherePoint(crashSphere.radius, latitude, longitude); - lines[i++] = VertexCol(pos, color); + float longitude = static_cast(segment) / VERTS_IN_LINE_STRIP; + *vert++ = SpherePoint(latitude, longitude); } - - primitive++; } + return vertices; + }(); - m_device->DrawPrimitives(PRIMITIVE_LINE_STRIP, lines.data(), firsts.data(), counts.data(), primitive); + + const int firstDraw = m_pendingDebugDraws.firsts.size(); + const int firstVert = m_pendingDebugDraws.vertices.size(); + + m_pendingDebugDraws.firsts.resize(m_pendingDebugDraws.firsts.size() + NUM_LINE_STRIPS); + m_pendingDebugDraws.counts.resize(m_pendingDebugDraws.counts.size() + NUM_LINE_STRIPS); + m_pendingDebugDraws.vertices.resize(m_pendingDebugDraws.vertices.size() + verticesTemplate.size()); + + for (int i = 0; i < NUM_LINE_STRIPS; ++i) + { + m_pendingDebugDraws.firsts[i + firstDraw] = firstVert + i * VERTS_IN_LINE_STRIP; } + + for (int i = 0; i < NUM_LINE_STRIPS; ++i) + { + m_pendingDebugDraws.counts[i + firstDraw] = VERTS_IN_LINE_STRIP; + } + + for (std::size_t i = 0; i < verticesTemplate.size(); ++i) + { + auto pos = Math::MatrixVectorMultiply(transform, sphere.pos + verticesTemplate[i] * sphere.radius); + m_pendingDebugDraws.vertices[i + firstVert] = VertexCol{pos, color}; + } +} + +void CEngine::RenderDebugBox(const Math::Vector& mins, const Math::Vector& maxs, const Math::Matrix& transform, const Gfx::Color& color) +{ + static constexpr int NUM_LINE_STRIPS = 4; + static constexpr int VERTS_IN_LINE_STRIP = 4; + + const int firstDraw = m_pendingDebugDraws.firsts.size(); + const int firstVert = m_pendingDebugDraws.vertices.size(); + + m_pendingDebugDraws.firsts.resize(m_pendingDebugDraws.firsts.size() + NUM_LINE_STRIPS); + m_pendingDebugDraws.counts.resize(m_pendingDebugDraws.counts.size() + NUM_LINE_STRIPS); + m_pendingDebugDraws.vertices.resize(m_pendingDebugDraws.vertices.size() + NUM_LINE_STRIPS * VERTS_IN_LINE_STRIP); + + for (int i = 0; i < NUM_LINE_STRIPS; ++i) + { + m_pendingDebugDraws.firsts[i + firstDraw] = firstVert + (i * VERTS_IN_LINE_STRIP); + } + + for (int i = 0; i < NUM_LINE_STRIPS; ++i) + { + m_pendingDebugDraws.counts[i + firstDraw] = NUM_LINE_STRIPS; + } + + auto vert = m_pendingDebugDraws.vertices.begin() + firstVert; + + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{mins.x, mins.y, mins.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{maxs.x, mins.y, mins.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{maxs.x, maxs.y, mins.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{maxs.x, maxs.y, maxs.z}), color}; + + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{mins.x, mins.y, maxs.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{mins.x, mins.y, mins.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{mins.x, maxs.y, mins.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{maxs.x, maxs.y, mins.z}), color}; + + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{maxs.x, mins.y, maxs.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{mins.x, mins.y, maxs.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{mins.x, maxs.y, maxs.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{mins.x, maxs.y, mins.z}), color}; + + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{maxs.x, mins.y, mins.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{maxs.x, mins.y, maxs.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{maxs.x, maxs.y, maxs.z}), color}; + *vert++ = VertexCol{Math::MatrixVectorMultiply(transform, Math::Vector{mins.x, maxs.y, maxs.z}), color}; +} + +void CEngine::RenderPendingDebugDraws() +{ + if (m_pendingDebugDraws.firsts.empty()) return; + + m_device->SetTransform(TRANSFORM_WORLD, Math::Matrix{}); + + SetState(ENG_RSTATE_OPAQUE_COLOR); + + m_device->DrawPrimitives(PRIMITIVE_LINE_STRIP, + m_pendingDebugDraws.vertices.data(), + m_pendingDebugDraws.firsts.data(), + m_pendingDebugDraws.counts.data(), + m_pendingDebugDraws.firsts.size()); + + m_pendingDebugDraws.firsts.clear(); + m_pendingDebugDraws.counts.clear(); + m_pendingDebugDraws.vertices.clear(); } void CEngine::RenderShadowMap() diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index 27f01585..f7f4db49 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -1161,8 +1161,8 @@ public: //! Updates the scene after a change of parameters void ApplyChange(); - void ClearDisplayCrashSpheres(); - void AddDisplayCrashSpheres(const std::vector& crashSpheres); + void RenderDebugSphere(const Math::Sphere&, const Math::Matrix& transform = Math::Matrix{}, const Color& = Color{0.0f, 0.0f, 1.0f, 1.0f}); + void RenderDebugBox(const Math::Vector& mins, const Math::Vector& maxs, const Math::Matrix& transform = Math::Matrix{}, const Color& = Color{0.0f, 0.0f, 1.0f, 1.0f}); void SetDebugLights(bool debugLights); bool GetDebugLights(); @@ -1228,7 +1228,7 @@ protected: void DrawStats(); //! Draw mission timer void DrawTimer(); - void DrawCrashSpheres(); + void RenderPendingDebugDraws(); //! Creates a new tier 2 object (texture) EngineBaseObjTexTier& AddLevel2(EngineBaseObject& p1, const std::string& tex1Name, const std::string& tex2Name); @@ -1406,6 +1406,13 @@ protected: Texture m_shadowMap; + struct + { + std::vector vertices; + std::vector firsts; + std::vector counts; + } m_pendingDebugDraws; + //! Ranks of highlighted objects int m_highlightRank[100]; //! Highlight visible? @@ -1479,7 +1486,6 @@ protected: std::unordered_map m_staticMeshBaseObjects; - std::vector m_displayCrashSpheres; std::vector> m_displayGoto; std::unique_ptr m_displayGotoImage; diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 5e49cc68..24e944c7 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -5949,18 +5949,14 @@ void CRobotMain::SetCodeBattleSpectatorMode(bool mode) void CRobotMain::UpdateDebugCrashSpheres() { - m_engine->ClearDisplayCrashSpheres(); if (m_debugCrashSpheres) { for (CObject* obj : m_objMan->GetAllObjects()) { - auto crashSpheres = obj->GetAllCrashSpheres(); - std::vector displaySpheres; - for (const auto& crashSphere : crashSpheres) + for (const auto& crashSphere : obj->GetAllCrashSpheres()) { - displaySpheres.push_back(crashSphere.sphere); + m_engine->RenderDebugSphere(crashSphere.sphere, Math::Matrix{}, Gfx::Color{0.0f, 0.0f, 1.0f, 1.0f}); } - m_engine->AddDisplayCrashSpheres(displaySpheres); } } }