Coverage Report

Created: 2026-09-01 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreDefaultDebugDrawer.cpp
Line
Count
Source
1
// This file is part of the OGRE project.
2
// It is subject to the license terms in the LICENSE file found in the top-level directory
3
// of this distribution and at https://www.ogre3d.org/licensing.
4
5
#include "OgreMatrix3.h"
6
#include "OgreStableHeaders.h"
7
#include "OgreDefaultDebugDrawer.h"
8
#include "OgreTagPoint.h"
9
#include "OgreViewport.h"
10
11
namespace Ogre
12
{
13
14
0
DefaultDebugDrawer::DefaultDebugDrawer() : mCameraNode(nullptr), mLines(""), mAxes(""), mDrawType(0), mStatic(false), mBoneAxesSize(1.0f) {}
15
16
void DefaultDebugDrawer::preFindVisibleObjects(SceneManager* source,
17
                                               SceneManager::IlluminationRenderStage irs, Viewport* v)
18
0
{
19
0
    mDrawType = 0;
20
21
0
    if (source->getDisplaySceneNodes())
22
0
        mDrawType |= DT_AXES;
23
0
    if (source->getShowBoundingBoxes())
24
0
        mDrawType |= DT_WIREBOX;
25
26
0
    mCameraNode = v->getCamera()->getParentSceneNode();
27
0
}
28
void DefaultDebugDrawer::beginLines()
29
0
{
30
0
    if (mLines.getSections().empty())
31
0
    {
32
0
        const char* matName = "Ogre/Debug/LinesMat";
33
0
        auto mat = MaterialManager::getSingleton().getByName(matName, RGN_INTERNAL);
34
0
        if (!mat)
35
0
        {
36
0
            mat = MaterialManager::getSingleton().create(matName, RGN_INTERNAL);
37
0
            Pass* p = mat->getTechnique(0)->getPass(0);
38
0
            p->setLightingEnabled(false);
39
0
            p->setVertexColourTracking(TVC_AMBIENT);
40
0
        }
41
0
        mLines.setBufferUsage(HBU_CPU_TO_GPU);
42
0
        mLines.begin(mat, RenderOperation::OT_LINE_LIST);
43
0
    }
44
0
    else if (mLines.getCurrentVertexCount() == 0)
45
0
        mLines.beginUpdate(0);
46
0
}
47
void DefaultDebugDrawer::beginAxes()
48
0
{
49
0
    if (mAxes.getSections().empty())
50
0
    {
51
0
        const char* matName = "Ogre/Debug/AxesMat";
52
0
        auto mat = MaterialManager::getSingleton().getByName(matName, RGN_INTERNAL);
53
0
        if (!mat)
54
0
        {
55
0
            mat = MaterialManager::getSingleton().create(matName, RGN_INTERNAL);
56
0
            Pass* p = mat->getTechnique(0)->getPass(0);
57
0
            p->setLightingEnabled(false);
58
0
            p->setPolygonModeOverrideable(false);
59
0
            p->setVertexColourTracking(TVC_AMBIENT);
60
0
            p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
61
0
            p->setCullingMode(CULL_NONE);
62
0
            p->setDepthWriteEnabled(false);
63
0
            p->setDepthCheckEnabled(false);
64
0
        }
65
66
0
        mAxes.setBufferUsage(HBU_CPU_TO_GPU);
67
0
        mAxes.begin(mat);
68
0
    }
69
0
    else if (mAxes.getCurrentVertexCount() == 0)
70
0
        mAxes.beginUpdate(0);
71
0
}
72
void DefaultDebugDrawer::drawWireBox(const AxisAlignedBox& aabb, const ColourValue& colour)
73
0
{
74
0
    beginLines();
75
76
0
    int base = mLines.getCurrentVertexCount();
77
0
    for (const auto& corner : aabb.getAllCorners())
78
0
    {
79
0
        mLines.position(corner);
80
0
        mLines.colour(colour);
81
0
    }
82
    // see AxisAlignedBox::getAllCorners
83
0
    int idx[] = {0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 6, 1, 5, 2, 4, 3, 7};
84
0
    for (int i : idx)
85
0
        mLines.index(base + i);
86
0
}
87
void DefaultDebugDrawer::drawFrustum(const Frustum* frust)
88
0
{
89
0
    beginLines();
90
91
0
    int base = mLines.getCurrentVertexCount();
92
0
    for (const auto& corner : frust->getWorldSpaceCorners())
93
0
    {
94
0
        mLines.position(corner);
95
0
        mLines.colour(frust->getDebugColour());
96
0
    }
97
    // see ConvexBody::define
98
0
    int idx[] = {0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 2, 6, 1, 5, 0, 4, 3, 7};
99
0
    for (int i : idx)
100
0
        mLines.index(base + i);
101
0
}
102
void DefaultDebugDrawer::drawSphere(const Sphere & sphere)
103
0
{
104
0
    if (!mCameraNode)
105
0
    {
106
0
        return;
107
0
    }
108
109
0
    const Vector3 & center = sphere.getCenter();
110
0
    float radius = sphere.getRadius();
111
112
0
    const Vector3 & camPos = mCameraNode->_getDerivedPosition();
113
0
    Vector3 axis = camPos - center;
114
0
    float distance = axis.normalise();
115
116
    // Unlike std's, Ogre's ACos tolerates domain errors
117
0
    const Radian facetAngle = 2 * Math::ACos(1.0f - (0.001f * distance / radius));
118
0
    int facetCount = (int)std::ceil(Math::TWO_PI / facetAngle.valueRadians());
119
120
    // TODO: figure out how this works with non-perspective projection and custom matrices
121
    // TODO: only draw visible arcs (very big or close spheres could have very many facets)
122
123
    // Calculate an arbitrary radial orthogonal to the axis
124
0
    Vector3 notParallel = mCameraNode->_getDerivedOrientation().xAxis();
125
0
    Vector3 radial = radius * notParallel.crossProduct(axis).normalisedCopy();
126
127
0
    beginLines();
128
0
    int base = mLines.getCurrentVertexCount();
129
130
0
    for (int i = 0; i < facetCount; ++i)
131
0
    {
132
0
        Radian angle(Math::TWO_PI * i / (float)facetCount);
133
0
        mLines.position(center + Quaternion(angle , axis) * radial);
134
0
        mLines.colour(ColourValue::White);
135
0
        mLines.index(base + i);
136
0
        mLines.index(base + ((i + 1) % facetCount));
137
0
    }
138
0
}
139
void DefaultDebugDrawer::drawAxis2D(const Affine3& pose, const Matrix3& rot, float scale, const ColourValue& col)
140
0
{
141
    /* each made up of 2 of these (base plane = XY)
142
     *   .------------|\
143
     *   '------------|/
144
     */
145
0
     static Vector3 basepos[7] =
146
0
     {
147
         // stalk
148
0
         Vector3(0, 0.05, 0),
149
0
         Vector3(0, -0.05, 0),
150
0
         Vector3(0.7, -0.05, 0),
151
0
         Vector3(0.7, 0.05, 0),
152
         // head
153
0
         Vector3(0.7, -0.15, 0),
154
0
         Vector3(1, 0, 0),
155
0
         Vector3(0.7, 0.15, 0)
156
0
     };
157
158
0
     uint32 base = mAxes.getCurrentVertexCount();
159
     // vertices
160
0
     for (const auto& p : basepos)
161
0
     {
162
0
         mAxes.position(pose * (rot * p * scale));
163
0
         mAxes.colour(col);
164
0
     }
165
166
     // indices
167
0
     mAxes.quad(base + 0, base + 1, base + 2, base + 3);
168
0
     mAxes.triangle(base + 4, base + 5, base + 6);
169
0
}
170
void DefaultDebugDrawer::drawAxes(const Affine3& pose, float size)
171
0
{
172
0
    beginAxes();
173
174
0
    ColourValue col[3] = {ColourValue(1, 0, 0, 0.8), ColourValue(0, 1, 0, 0.8), ColourValue(0, 0, 1, 0.8)};
175
176
0
    Matrix3 rot[6];
177
178
    // x-axis
179
0
    rot[0] = Matrix3::IDENTITY;
180
0
    rot[1].FromAxes(Vector3::UNIT_X, Vector3::NEGATIVE_UNIT_Z, Vector3::UNIT_Y);
181
    // y-axis
182
0
    rot[2].FromAxes(Vector3::UNIT_Y, Vector3::NEGATIVE_UNIT_X, Vector3::UNIT_Z);
183
0
    rot[3].FromAxes(Vector3::UNIT_Y, Vector3::UNIT_Z, Vector3::UNIT_X);
184
    // z-axis
185
0
    rot[4].FromAxes(Vector3::UNIT_Z, Vector3::UNIT_Y, Vector3::NEGATIVE_UNIT_X);
186
0
    rot[5].FromAxes(Vector3::UNIT_Z, Vector3::UNIT_X, Vector3::UNIT_Y);
187
188
    // 6 arrows
189
0
    for (size_t i = 0; i < 6; ++i)
190
0
    {
191
0
        drawAxis2D(pose, rot[i], size, col[i / 2]);
192
0
    }
193
0
}
194
void DefaultDebugDrawer::setBoneAxesSize(float size)
195
0
{
196
0
    mBoneAxesSize = size;
197
0
}
198
void DefaultDebugDrawer::drawBone(const Node* node, const Affine3& transform)
199
0
{
200
0
    beginAxes();
201
202
0
    ColourValue col(0.5, 0, 1, 0.9);
203
0
    Affine3 pose = transform * node->_getFullTransform();
204
205
0
    Matrix3 rot[2];
206
    // x-axis
207
0
    rot[0] = Matrix3::IDENTITY;
208
0
    rot[1].FromAxes(Vector3::UNIT_X, Vector3::NEGATIVE_UNIT_Z, Vector3::UNIT_Y);
209
210
0
    for(const auto* child : node->getChildren())
211
0
    {
212
0
        if(dynamic_cast<const TagPoint*>(child))
213
0
            continue;
214
215
0
        float size = child->getPosition().length(); // we can assume relative to parent position
216
217
0
        Matrix3 crot;
218
0
        Vector3::UNIT_X.getRotationTo(child->getPosition()).ToRotationMatrix(crot);
219
220
0
        for (const auto& r : rot)
221
0
        {
222
0
            drawAxis2D(pose, crot * r, size, col);
223
0
        }
224
0
    }
225
226
0
    if(node->getChildren().empty())
227
0
    {
228
0
        Matrix3 crot;
229
0
        Vector3::UNIT_X.getRotationTo(node->getPosition()).ToRotationMatrix(crot);
230
        // draw the axes of the node itself
231
0
        for (const auto& r : rot)
232
0
        {
233
0
            drawAxis2D(pose, crot * r, mBoneAxesSize, col);
234
0
        }
235
0
    }
236
0
}
237
void DefaultDebugDrawer::drawSceneNode(const SceneNode* node)
238
0
{
239
    // skip drawing root scene node as it contains the camera frustum
240
0
    if(!node->getParent())
241
0
        return;
242
243
0
    const auto& aabb = node->_getWorldAABB();
244
    //Skip all bounding boxes that are infinite.
245
0
    if (aabb.isInfinite()) {
246
0
        return;
247
0
    }
248
0
    if (node->getDisplaySceneNode() || (mDrawType & DT_AXES))
249
0
    {
250
        // remove scale here as it will be in full transform below too
251
0
        Vector3f hs(aabb.getHalfSize() / node->_getDerivedScale());
252
0
        float sz = std::min(hs[0], hs[1]);
253
0
        sz = std::min(sz, hs[2]);
254
0
        sz = std::max(sz, 1.0f);
255
0
        drawAxes(node->_getFullTransform(), sz);
256
0
    }
257
258
0
    if (node->getShowBoundingBox() || (mDrawType & DT_WIREBOX))
259
0
    {
260
0
        drawWireBox(aabb);
261
0
    }
262
0
}
263
void DefaultDebugDrawer::postFindVisibleObjects(SceneManager* source,
264
                                                SceneManager::IlluminationRenderStage irs, Viewport* v)
265
0
{
266
0
    auto queue = source->getRenderQueue();
267
0
    if (mLines.getCurrentVertexCount())
268
0
    {
269
0
        mLines.end();
270
0
        mLines._updateRenderQueue(queue);
271
0
    }
272
0
    if (mAxes.getCurrentVertexCount())
273
0
    {
274
0
        mAxes.end();
275
0
        mAxes._updateRenderQueue(queue);
276
0
    }
277
278
0
    if (mStatic)
279
0
    {
280
0
        mLines._updateRenderQueue(queue);
281
0
        mAxes._updateRenderQueue(queue);
282
0
    }
283
0
}
284
285
} /* namespace Ogre */