Coverage Report

Created: 2025-11-04 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreRenderQueue.cpp
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
    (Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
#include "OgreStableHeaders.h"
29
30
#include "OgreRenderQueue.h"
31
32
#include <memory>
33
#include "OgreMaterial.h"
34
#include "OgreRenderQueueSortingGrouping.h"
35
#include "OgreSceneManagerEnumerator.h"
36
37
namespace Ogre {
38
39
    //---------------------------------------------------------------------
40
    RenderQueue::RenderQueue()
41
0
        : mSplitPassesByLightingType(false)
42
0
        , mSplitNoShadowPasses(false)
43
0
        , mShadowCastersCannotBeReceivers(false)
44
0
        , mRenderableListener(0)
45
0
    {
46
        // Create the 'main' queue up-front since we'll always need that
47
0
        mGroups[RENDER_QUEUE_MAIN] = std::make_unique<RenderQueueGroup>(
48
0
            mSplitPassesByLightingType, mSplitNoShadowPasses, mShadowCastersCannotBeReceivers);
49
50
        // set default queue
51
0
        mDefaultQueueGroup = RENDER_QUEUE_MAIN;
52
0
        mDefaultRenderablePriority = Renderable::DEFAULT_PRIORITY;
53
54
0
    }
55
    //---------------------------------------------------------------------
56
    RenderQueue::~RenderQueue()
57
0
    {
58
        
59
        // trigger the pending pass updates, otherwise we could leak
60
0
        Pass::processPendingPassUpdates();
61
0
    }
62
63
    static bool onTransparentQueue(Technique* pTech)
64
0
    {
65
        // Transparent and depth/colour settings mean depth sorting is required?
66
        // Note: colour write disabled with depth check/write enabled means
67
        //       setup depth buffer for other passes use.
68
0
        if (pTech->isTransparentSortingForced() ||
69
0
            (pTech->isTransparent() &&
70
0
             (!pTech->isDepthWriteEnabled() || !pTech->isDepthCheckEnabled() || pTech->hasColourWriteDisabled())))
71
0
        {
72
0
            return true;
73
0
        }
74
75
0
        return false;
76
0
    }
77
78
    //-----------------------------------------------------------------------
79
    void RenderQueue::addRenderable(Renderable* pRend, uint8 groupID, ushort priority)
80
0
    {
81
0
        Technique* pTech;
82
83
        // tell material it's been used
84
0
        if (pRend->getMaterial())
85
0
            pRend->getMaterial()->touch();
86
87
        // Check material & technique supplied (the former since the default implementation
88
        // of getTechnique is based on it for backwards compatibility
89
0
        if(!pRend->getMaterial() || !pRend->getTechnique())
90
0
        {
91
            // Use default base white, with lighting only if vertices has normals
92
0
            RenderOperation op;
93
0
            pRend->getRenderOperation(op);
94
0
            bool useLighting = (NULL != op.vertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL));
95
0
            MaterialPtr defaultMat = MaterialManager::getSingleton().getDefaultMaterial(useLighting);
96
0
            defaultMat->load();
97
0
            pTech = defaultMat->getBestTechnique();
98
0
        }
99
0
        else
100
0
            pTech = pRend->getTechnique();
101
102
0
        if (mRenderableListener)
103
0
        {
104
            // Allow listener to override technique and to abort
105
0
            if (!mRenderableListener->renderableQueued(pRend, groupID, priority, 
106
0
                &pTech, this))
107
0
                return; // rejected
108
109
            // tell material it's been used (incase changed)
110
0
            pTech->getParent()->touch();
111
0
        }
112
113
0
        if(groupID == mDefaultQueueGroup && onTransparentQueue(pTech))
114
0
            groupID = RENDER_QUEUE_TRANSPARENTS;
115
116
        // Find group
117
0
        RenderQueueGroup* pGroup = getQueueGroup(groupID);
118
0
        pGroup->addRenderable(pRend, pTech, priority);
119
120
0
    }
121
    //-----------------------------------------------------------------------
122
    void RenderQueue::clear(bool destroyPassMaps)
123
0
    {
124
        // Note: We clear dirty passes from all RenderQueues in all 
125
        // SceneManagers, because the following recalculation of pass hashes
126
        // also considers all RenderQueues and could become inconsistent, otherwise.
127
0
        for (auto p : SceneManagerEnumerator::getSingleton().getSceneManagers())
128
0
        {
129
0
            RenderQueue* queue = p.second->getRenderQueue();
130
131
0
            for (auto & g : queue->mGroups)
132
0
            {
133
0
                if(g)
134
0
                    g->clear(destroyPassMaps);
135
0
            }
136
0
        }
137
138
        // Now trigger the pending pass updates
139
0
        Pass::processPendingPassUpdates();
140
141
        // NB this leaves the items present (but empty)
142
        // We're assuming that frame-by-frame, the same groups are likely to 
143
        //  be used, so no point destroying the vectors and incurring the overhead
144
        //  that would cause, let them be destroyed in the destructor.
145
0
    }
146
    //-----------------------------------------------------------------------
147
    void RenderQueue::addRenderable(Renderable* pRend, uint8 groupID)
148
0
    {
149
0
        addRenderable(pRend, groupID, mDefaultRenderablePriority);
150
0
    }
151
    //-----------------------------------------------------------------------
152
    void RenderQueue::addRenderable(Renderable* pRend)
153
0
    {
154
0
        addRenderable(pRend, mDefaultQueueGroup, mDefaultRenderablePriority);
155
0
    }
156
    //-----------------------------------------------------------------------
157
    uint8 RenderQueue::getDefaultQueueGroup(void) const
158
0
    {
159
0
        return mDefaultQueueGroup;
160
0
    }
161
    //-----------------------------------------------------------------------
162
    void RenderQueue::setDefaultQueueGroup(uint8 grp)
163
0
    {
164
0
        mDefaultQueueGroup = grp;
165
0
    }
166
    //-----------------------------------------------------------------------
167
    ushort RenderQueue::getDefaultRenderablePriority(void) const
168
0
    {
169
0
        return mDefaultRenderablePriority;
170
0
    }
171
    //-----------------------------------------------------------------------
172
    void RenderQueue::setDefaultRenderablePriority(ushort priority)
173
0
    {
174
0
        mDefaultRenderablePriority = priority;
175
0
    }
176
    
177
    
178
    //-----------------------------------------------------------------------
179
    RenderQueueGroup* RenderQueue::getQueueGroup(uint8 groupID)
180
0
    {
181
0
        if (!mGroups[groupID])
182
0
        {
183
            // Insert new
184
0
            mGroups[groupID] = std::make_unique<RenderQueueGroup>(mSplitPassesByLightingType, mSplitNoShadowPasses,
185
0
                                                        mShadowCastersCannotBeReceivers);
186
0
        }
187
188
0
        return mGroups[groupID].get();
189
190
0
    }
191
    //-----------------------------------------------------------------------
192
    void RenderQueue::setSplitPassesByLightingType(bool split)
193
0
    {
194
0
        mSplitPassesByLightingType = split;
195
196
0
        for (auto & g : mGroups)
197
0
        {
198
0
            if(g)
199
0
                g->setSplitPassesByLightingType(split);
200
0
        }
201
0
    }
202
    //-----------------------------------------------------------------------
203
    bool RenderQueue::getSplitPassesByLightingType(void) const
204
0
    {
205
0
        return mSplitPassesByLightingType;
206
0
    }
207
    //-----------------------------------------------------------------------
208
    void RenderQueue::setSplitNoShadowPasses(bool split)
209
0
    {
210
0
        mSplitNoShadowPasses = split;
211
212
0
        for (auto & g : mGroups)
213
0
        {
214
0
            if(g)
215
0
                g->setSplitNoShadowPasses(split);
216
0
        }
217
0
    }
218
    //-----------------------------------------------------------------------
219
    bool RenderQueue::getSplitNoShadowPasses(void) const
220
0
    {
221
0
        return mSplitNoShadowPasses;
222
0
    }
223
    //-----------------------------------------------------------------------
224
    void RenderQueue::setShadowCastersCannotBeReceivers(bool ind)
225
0
    {
226
0
        mShadowCastersCannotBeReceivers = ind;
227
228
0
        for (auto & g : mGroups)
229
0
        {
230
0
            if(g)
231
0
                g->setShadowCastersCannotBeReceivers(ind);
232
0
        }
233
0
    }
234
    //-----------------------------------------------------------------------
235
    bool RenderQueue::getShadowCastersCannotBeReceivers(void) const
236
0
    {
237
0
        return mShadowCastersCannotBeReceivers;
238
0
    }
239
    //-----------------------------------------------------------------------
240
    void RenderQueue::merge( const RenderQueue* rhs )
241
0
    {
242
0
        for (size_t i = 0; i < RENDER_QUEUE_COUNT; ++i)
243
0
        {
244
0
            if(!rhs->mGroups[i])
245
0
                continue;
246
247
0
            RenderQueueGroup* pDstGroup = getQueueGroup( i );
248
0
            pDstGroup->merge( rhs->mGroups[i].get() );
249
0
        }
250
0
    }
251
252
    //---------------------------------------------------------------------
253
    void RenderQueue::processVisibleObject(MovableObject* mo, 
254
        Camera* cam, 
255
        bool onlyShadowCasters, 
256
        VisibleObjectsBoundsInfo* visibleBounds)
257
0
    {
258
        // receiveShadows is a material property, so we can query it before LOD
259
0
        bool receiveShadows = getQueueGroup(mo->getRenderQueueGroup())->getShadowsEnabled() && mo->getReceivesShadows();
260
261
0
        if(onlyShadowCasters && !mo->getCastShadows() && !receiveShadows)
262
0
            return;
263
264
0
        mo->_notifyCurrentCamera(cam);
265
0
        if (!mo->isVisible())
266
0
            return;
267
268
0
        const auto& bbox = mo->getWorldBoundingBox(true);
269
0
        const auto& bsphere = mo->getWorldBoundingSphere(true);
270
271
0
        if (!onlyShadowCasters || mo->getCastShadows())
272
0
        {
273
0
            mo->_updateRenderQueue(this);
274
0
            if (visibleBounds)
275
0
            {
276
0
                visibleBounds->merge(bbox, bsphere, cam, receiveShadows);
277
0
            }
278
0
        }
279
        // not shadow caster, receiver only?
280
0
        else if (receiveShadows)
281
0
        {
282
0
            visibleBounds->mergeNonRenderedButInFrustum(bbox, bsphere, cam);
283
0
        }
284
0
    }
285
286
}
287