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.
1008-fix
AbigailBuccaneer 2018-04-29 23:37:41 +01:00
parent fdf67b8217
commit c445d7d9a9
3 changed files with 123 additions and 78 deletions

View File

@ -3147,24 +3147,6 @@ void CEngine::ApplyChange()
} }
} }
void CEngine::ClearDisplayCrashSpheres()
{
m_displayCrashSpheres.clear();
m_debugCrashSpheres = false;
}
void CEngine::AddDisplayCrashSpheres(const std::vector<Math::Sphere>& crashSpheres)
{
for (const auto& crashSphere : crashSpheres)
{
m_displayCrashSpheres.push_back(crashSphere);
}
m_debugCrashSpheres = true;
}
/******************************************************* /*******************************************************
Rendering Rendering
*******************************************************/ *******************************************************/
@ -3483,8 +3465,7 @@ void CEngine::Draw3DScene()
m_device->SetRenderState(RENDER_STATE_LIGHTING, false); m_device->SetRenderState(RENDER_STATE_LIGHTING, false);
if (m_debugCrashSpheres) RenderPendingDebugDraws();
DrawCrashSpheres();
if (m_debugGoto) if (m_debugGoto)
{ {
@ -3651,74 +3632,136 @@ void CEngine::DrawCaptured3DScene()
m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertices, 4); 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; static constexpr int LONGITUDE_DIVISIONS = 16;
worldMatrix.LoadIdentity(); static constexpr int LATITUDE_DIVISIONS = 8;
m_device->SetTransform(TRANSFORM_WORLD, worldMatrix); 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<Math::Vector, NUM_LINE_STRIPS * VERTS_IN_LINE_STRIP> verticesTemplate = []{
std::array<Math::Vector, NUM_LINE_STRIPS * VERTS_IN_LINE_STRIP> vertices;
static const int LINE_SEGMENTS = 32; auto SpherePoint = [&](float latitude, float longitude)
static const int LONGITUDE_DIVISIONS = 16; {
static const int LATITUDE_DIVISIONS = 8; 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<VertexCol> lines((2 + LONGITUDE_DIVISIONS + LATITUDE_DIVISIONS) * LINE_SEGMENTS); auto vert = vertices.begin();
std::vector<int> firsts(2 + LONGITUDE_DIVISIONS + LATITUDE_DIVISIONS);
std::vector<int> 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;
for (int longitudeDivision = 0; longitudeDivision <= LONGITUDE_DIVISIONS; ++longitudeDivision) for (int longitudeDivision = 0; longitudeDivision <= LONGITUDE_DIVISIONS; ++longitudeDivision)
{ {
firsts[primitive] = i; for (int segment = 0; segment < VERTS_IN_LINE_STRIP; ++segment)
counts[primitive] = LINE_SEGMENTS;
for (int segment = 0; segment < LINE_SEGMENTS; ++segment)
{ {
Math::Vector pos = crashSphere.pos; float latitude = static_cast<float>(segment) / VERTS_IN_LINE_STRIP;
float latitude = static_cast<float>(segment) / LINE_SEGMENTS;
float longitude = static_cast<float>(longitudeDivision) / (LONGITUDE_DIVISIONS); float longitude = static_cast<float>(longitudeDivision) / (LONGITUDE_DIVISIONS);
pos += SpherePoint(crashSphere.radius, latitude, longitude); *vert++ = SpherePoint(latitude, longitude);
lines[i++] = VertexCol(pos, color);
} }
primitive++;
} }
for (int latitudeDivision = 0; latitudeDivision <= LATITUDE_DIVISIONS; ++latitudeDivision) for (int latitudeDivision = 0; latitudeDivision <= LATITUDE_DIVISIONS; ++latitudeDivision)
{ {
firsts[primitive] = i; for (int segment = 0; segment < VERTS_IN_LINE_STRIP; ++segment)
counts[primitive] = LINE_SEGMENTS;
for (int segment = 0; segment < LINE_SEGMENTS; ++segment)
{ {
Math::Vector pos = crashSphere.pos;
float latitude = static_cast<float>(latitudeDivision + 1) / (LATITUDE_DIVISIONS + 2); float latitude = static_cast<float>(latitudeDivision + 1) / (LATITUDE_DIVISIONS + 2);
float longitude = static_cast<float>(segment) / LINE_SEGMENTS; float longitude = static_cast<float>(segment) / VERTS_IN_LINE_STRIP;
pos += SpherePoint(crashSphere.radius, latitude, longitude); *vert++ = SpherePoint(latitude, longitude);
lines[i++] = VertexCol(pos, color);
} }
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() void CEngine::RenderShadowMap()

View File

@ -1161,8 +1161,8 @@ public:
//! Updates the scene after a change of parameters //! Updates the scene after a change of parameters
void ApplyChange(); void ApplyChange();
void ClearDisplayCrashSpheres(); void RenderDebugSphere(const Math::Sphere&, const Math::Matrix& transform = Math::Matrix{}, const Color& = Color{0.0f, 0.0f, 1.0f, 1.0f});
void AddDisplayCrashSpheres(const std::vector<Math::Sphere>& crashSpheres); 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); void SetDebugLights(bool debugLights);
bool GetDebugLights(); bool GetDebugLights();
@ -1228,7 +1228,7 @@ protected:
void DrawStats(); void DrawStats();
//! Draw mission timer //! Draw mission timer
void DrawTimer(); void DrawTimer();
void DrawCrashSpheres(); void RenderPendingDebugDraws();
//! Creates a new tier 2 object (texture) //! Creates a new tier 2 object (texture)
EngineBaseObjTexTier& AddLevel2(EngineBaseObject& p1, const std::string& tex1Name, const std::string& tex2Name); EngineBaseObjTexTier& AddLevel2(EngineBaseObject& p1, const std::string& tex1Name, const std::string& tex2Name);
@ -1406,6 +1406,13 @@ protected:
Texture m_shadowMap; Texture m_shadowMap;
struct
{
std::vector<VertexCol> vertices;
std::vector<int> firsts;
std::vector<int> counts;
} m_pendingDebugDraws;
//! Ranks of highlighted objects //! Ranks of highlighted objects
int m_highlightRank[100]; int m_highlightRank[100];
//! Highlight visible? //! Highlight visible?
@ -1479,7 +1486,6 @@ protected:
std::unordered_map<std::string, int> m_staticMeshBaseObjects; std::unordered_map<std::string, int> m_staticMeshBaseObjects;
std::vector<Math::Sphere> m_displayCrashSpheres;
std::vector<std::vector<VertexCol>> m_displayGoto; std::vector<std::vector<VertexCol>> m_displayGoto;
std::unique_ptr<CImage> m_displayGotoImage; std::unique_ptr<CImage> m_displayGotoImage;

View File

@ -5949,18 +5949,14 @@ void CRobotMain::SetCodeBattleSpectatorMode(bool mode)
void CRobotMain::UpdateDebugCrashSpheres() void CRobotMain::UpdateDebugCrashSpheres()
{ {
m_engine->ClearDisplayCrashSpheres();
if (m_debugCrashSpheres) if (m_debugCrashSpheres)
{ {
for (CObject* obj : m_objMan->GetAllObjects()) for (CObject* obj : m_objMan->GetAllObjects())
{ {
auto crashSpheres = obj->GetAllCrashSpheres(); for (const auto& crashSphere : obj->GetAllCrashSpheres())
std::vector<Math::Sphere> displaySpheres;
for (const auto& crashSphere : crashSpheres)
{ {
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);
} }
} }
} }