Coverage Report

Created: 2026-10-28 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreTextureShadowRenderer.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
// SPDX-License-Identifier: MIT
5
6
#include "OgreStableHeaders.h"
7
#include "OgreShadowCameraSetup.h"
8
#include "OgreViewport.h"
9
#include "OgreHardwarePixelBuffer.h"
10
#include "OgreCompositorManager.h"
11
#include "OgreCompositor.h"
12
13
namespace Ogre {
14
15
SceneManager::TextureShadowRenderer::TextureShadowRenderer(SceneManager* owner) :
16
0
mSceneManager(owner),
17
0
mShadowCasterPlainBlackPass(0),
18
0
mShadowReceiverPass(0),
19
0
mShadowTextureCustomCasterPass(0),
20
0
mShadowTextureCustomReceiverPass(0),
21
0
mDefaultShadowFarDist(0),
22
0
mDefaultShadowFarDistSquared(0),
23
0
mShadowTextureOffset(0.6),
24
0
mShadowTextureFadeStart(0.7),
25
0
mShadowTextureFadeEnd(0.9),
26
0
mShadowTextureSelfShadow(false),
27
0
mShadowTextureConfigDirty(true),
28
0
mShadowCasterRenderBackFaces(true)
29
0
{
30
    // set up default shadow camera setup
31
0
    mDefaultShadowCameraSetup = DefaultShadowCameraSetup::create();
32
33
0
    mCullCameraSetup = DefaultShadowCameraSetup::create();
34
35
    // init shadow texture count per type.
36
0
    mShadowTextureCountPerType[Light::LT_POINT] = 1;
37
0
    mShadowTextureCountPerType[Light::LT_DIRECTIONAL] = 1;
38
0
    mShadowTextureCountPerType[Light::LT_SPOTLIGHT] = 1;
39
0
}
40
41
0
SceneManager::TextureShadowRenderer::~TextureShadowRenderer() {}
42
43
void SceneManager::TextureShadowRenderer::render(RenderQueueGroup* group,
44
                                          QueuedRenderableCollection::OrganisationMode om)
45
0
{
46
    // Receiver pass(es)
47
0
    if (mSceneManager->isShadowTechniqueAdditive())
48
0
    {
49
        // Auto-additive
50
0
        renderAdditiveTextureShadowedQueueGroupObjects(group, om);
51
0
        return;
52
0
    }
53
54
    // Modulative
55
0
    renderModulativeTextureShadowedQueueGroupObjects(group, om);
56
0
}
57
58
size_t SceneManager::TextureShadowRenderer::getShadowTexIndex(size_t startLightIndex)
59
0
{
60
0
    size_t shadowTexIndex = mShadowTextures.size();
61
0
    if (mShadowTextureIndexLightList.size() > startLightIndex)
62
0
        shadowTexIndex = mShadowTextureIndexLightList[startLightIndex];
63
0
    return shadowTexIndex;
64
0
}
65
//-----------------------------------------------------------------------
66
void SceneManager::TextureShadowRenderer::renderTextureShadowCasterQueueGroupObjects(
67
    RenderQueueGroup* pGroup,
68
    QueuedRenderableCollection::OrganisationMode om)
69
0
{
70
    // This is like the basic group render, except we skip all transparents
71
    // and we also render any non-shadowed objects
72
    // Note that non-shadow casters will have already been eliminated during
73
    // _findVisibleObjects
74
75
    // Iterate through priorities
76
77
    // Override auto param ambient to force vertex programs and fixed function to
78
0
    ColourValue currAmbient = mSceneManager->getAmbientLight();
79
0
    if (mSceneManager->isShadowTechniqueAdditive())
80
0
    {
81
        // Use simple black / white mask if additive
82
0
        mSceneManager->setAmbientLight(ColourValue::Black);
83
0
    }
84
0
    else
85
0
    {
86
        // Use shadow colour as caster colour if modulative
87
0
        mSceneManager->setAmbientLight(mSceneManager->getShadowColour());
88
0
    }
89
90
0
    auto visitor = mSceneManager->getQueuedRenderableVisitor();
91
0
    for (const auto& pg : pGroup->getPriorityGroups())
92
0
    {
93
0
        RenderPriorityGroup* pPriorityGrp = pg.second;
94
95
        // Sort the queue first
96
0
        pPriorityGrp->sort(mSceneManager->mCameraInProgress);
97
98
        // Do solids, override light list incase any vertex programs use them
99
0
        visitor->renderObjects(pPriorityGrp->getSolidsBasic(), om, false, false);
100
0
        visitor->renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, false, false);
101
        // Do unsorted transparents that cast shadows
102
0
        visitor->renderObjects(pPriorityGrp->getTransparentsUnsorted(), om, false, false, nullptr, true);
103
        // Do transparents that cast shadows
104
0
        visitor->renderObjects(pPriorityGrp->getTransparents(), QueuedRenderableCollection::OM_SORT_DESCENDING, false,
105
0
                               false, nullptr, true);
106
107
0
    }// for each priority
108
109
    // reset ambient light
110
0
    mSceneManager->setAmbientLight(currAmbient);
111
0
}
112
//-----------------------------------------------------------------------
113
void SceneManager::TextureShadowRenderer::renderModulativeTextureShadowedQueueGroupObjects(
114
    RenderQueueGroup* pGroup,
115
    QueuedRenderableCollection::OrganisationMode om)
116
0
{
117
    /* For each light, we need to render all the solids from each group,
118
    then do the modulative shadows, then render the transparents from
119
    each group.
120
    Now, this means we are going to reorder things more, but that it required
121
    if the shadows are to look correct. The overall order is preserved anyway,
122
    it's just that all the transparents are at the end instead of them being
123
    interleaved as in the normal rendering loop.
124
    */
125
    // Iterate through priorities
126
0
    auto visitor = mSceneManager->getQueuedRenderableVisitor();
127
0
    for (const auto& pg : pGroup->getPriorityGroups())
128
0
    {
129
0
        RenderPriorityGroup* pPriorityGrp = pg.second;
130
131
        // Sort the queue first
132
0
        pPriorityGrp->sort(mSceneManager->mCameraInProgress);
133
134
        // Do solids
135
0
        visitor->renderObjects(pPriorityGrp->getSolidsBasic(), om, true, true);
136
0
        visitor->renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, true, true);
137
0
    }
138
139
140
    // Iterate over lights, render received shadows
141
    // only perform this if we're in the 'normal' render stage, to avoid
142
    // doing it during the render to texture
143
0
    if (mSceneManager->mIlluminationStage == IRS_NONE)
144
0
    {
145
0
        mSceneManager->mIlluminationStage = IRS_RENDER_RECEIVER_PASS;
146
147
0
        LightList::const_iterator i, iend;
148
0
        iend = mSceneManager->_getLightsAffectingFrustum().end();
149
150
0
        size_t si = 0;
151
0
        for (i = mSceneManager->_getLightsAffectingFrustum().begin();
152
0
             i != iend && si < mShadowTextures.size(); ++i)
153
0
        {
154
0
            Light* l = *i;
155
156
0
            if (!l->getCastShadows())
157
0
                continue;
158
159
            // Get camera for current shadow texture
160
0
            Camera *cam = mShadowTextures[si]->getBuffer()->getRenderTarget()->getViewport(0)->getCamera();
161
            // Hook up receiver texture
162
0
            Pass* targetPass = mShadowTextureCustomReceiverPass ?
163
0
                    mShadowTextureCustomReceiverPass : mShadowReceiverPass;
164
165
            // if this light is a spotlight, we need to add the spot fader layer
166
            // BUT not if using a custom projection matrix, since then it will be
167
            // inappropriately shaped most likely
168
0
            if (l->getType() == Light::LT_SPOTLIGHT && !cam->isCustomProjectionMatrixEnabled())
169
0
            {
170
                // remove all TUs except 0 & 1
171
                // (only an issue if additive shadows have been used)
172
0
                while(targetPass->getNumTextureUnitStates() > 2)
173
0
                    targetPass->removeTextureUnitState(2);
174
175
0
                TextureUnitState* t = NULL;
176
                // Add spot fader if not present already
177
0
                if (targetPass->getNumTextureUnitStates() == 2 &&
178
0
                    targetPass->getTextureUnitState(1)->_getTexturePtr() == mSpotFadeTexture)
179
0
                {
180
                    // Just set
181
0
                    t = targetPass->getTextureUnitState(1);
182
0
                }
183
0
                else
184
0
                {
185
                    // Remove any non-conforming spot layers
186
0
                    while(targetPass->getNumTextureUnitStates() > 1)
187
0
                        targetPass->removeTextureUnitState(1);
188
189
0
                    t = targetPass->createTextureUnitState();
190
0
                    t->setTexture(mSpotFadeTexture);
191
0
                    t->setColourOperation(LBO_ADD);
192
0
                    t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
193
0
                }
194
195
0
                t->setProjectiveTexturing(!targetPass->hasVertexProgram(), cam);
196
0
                mSceneManager->mAutoParamDataSource->setTextureProjector(cam, 1);
197
0
            }
198
0
            else
199
0
            {
200
                // remove all TUs except 0 including spot
201
0
                while(targetPass->getNumTextureUnitStates() > 1)
202
0
                    targetPass->removeTextureUnitState(1);
203
204
0
            }
205
206
            // account for the RTSS
207
0
            if (auto betterTechnique = targetPass->getParent()->getParent()->getBestTechnique())
208
0
            {
209
0
                targetPass = betterTechnique->getPass(0);
210
0
            }
211
212
0
            TextureUnitState* texUnit = targetPass->getTextureUnitState(0);
213
            // clamp to border colour in case this is a custom material
214
0
            texUnit->setSampler(mBorderSampler);
215
0
            resolveShadowTexture(texUnit, si, 0);
216
217
            // Set lighting / blending modes
218
0
            targetPass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO);
219
0
            targetPass->setLightingEnabled(false);
220
221
0
            targetPass->_load();
222
223
            // Fire pre-receiver event
224
0
            fireShadowTexturesPreReceiver(l, cam);
225
226
0
            renderTextureShadowReceiverQueueGroupObjects(pGroup, om);
227
228
0
            ++si;
229
230
0
        } // for each light
231
232
0
        mSceneManager->mIlluminationStage = IRS_NONE;
233
234
0
    }
235
0
}
236
//-----------------------------------------------------------------------
237
void SceneManager::TextureShadowRenderer::renderAdditiveTextureShadowedQueueGroupObjects(
238
    RenderQueueGroup* pGroup,
239
    QueuedRenderableCollection::OrganisationMode om)
240
0
{
241
0
    LightList lightList(1);
242
0
    auto visitor = mSceneManager->getQueuedRenderableVisitor();
243
244
0
    for (const auto& pg : pGroup->getPriorityGroups())
245
0
    {
246
0
        RenderPriorityGroup* pPriorityGrp = pg.second;
247
248
        // Sort the queue first
249
0
        pPriorityGrp->sort(mSceneManager->mCameraInProgress);
250
251
        // Render all the ambient passes first, no light iteration, no lights
252
0
        visitor->renderObjects(pPriorityGrp->getSolidsBasic(), om, false, false);
253
        // Also render any objects which have receive shadows disabled
254
0
        visitor->renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, true, true);
255
256
257
        // only perform this next part if we're in the 'normal' render stage, to avoid
258
        // doing it during the render to texture
259
0
        if (mSceneManager->mIlluminationStage == IRS_NONE)
260
0
        {
261
            // Iterate over lights, render masked
262
0
            size_t si = 0;
263
264
0
            for (Light* l : mSceneManager->_getLightsAffectingFrustum())
265
0
            {
266
0
                if (l->getCastShadows() && si < mShadowTextures.size())
267
0
                {
268
                    // Hook up receiver texture
269
0
                    Pass* targetPass = mShadowTextureCustomReceiverPass ?
270
0
                        mShadowTextureCustomReceiverPass : mShadowReceiverPass;
271
272
                    // account for the RTSS
273
0
                    if (auto betterTechnique = targetPass->getParent()->getParent()->getBestTechnique())
274
0
                    {
275
0
                        targetPass = betterTechnique->getPass(0);
276
0
                    }
277
278
0
                    TextureUnitState* texUnit = targetPass->getTextureUnitState(0);
279
                    // clamp to border colour in case this is a custom material
280
0
                    texUnit->setSampler(mBorderSampler);
281
0
                    resolveShadowTexture(texUnit, si, 0);
282
283
                    // Remove any spot fader layer
284
0
                    if (targetPass->getNumTextureUnitStates() > 1 &&
285
0
                        targetPass->getTextureUnitState(1)->getTextureName() == "spot_shadow_fade.dds")
286
0
                    {
287
                        // remove spot fader layer (should only be there if
288
                        // we previously used modulative shadows)
289
0
                        targetPass->removeTextureUnitState(1);
290
0
                    }
291
                    // Set lighting / blending modes
292
0
                    targetPass->setSceneBlending(SBF_ONE, SBF_ONE);
293
0
                    targetPass->setLightingEnabled(true);
294
0
                    targetPass->_load();
295
296
                    // increment shadow texture since used
297
0
                    ++si;
298
299
0
                    mSceneManager->mIlluminationStage = IRS_RENDER_RECEIVER_PASS;
300
301
0
                }
302
0
                else
303
0
                {
304
0
                    mSceneManager->mIlluminationStage = IRS_NONE;
305
0
                }
306
307
                // render lighting passes for this light
308
0
                lightList[0] = l;
309
310
                // set up light scissoring, always useful in additive modes
311
0
                ClipResult scissored = mSceneManager->buildAndSetScissor(lightList, mSceneManager->mCameraInProgress);
312
0
                ClipResult clipped = CLIPPED_NONE;
313
0
                if(mSceneManager->getShadowUseLightClipPlanes())
314
0
                    clipped = mSceneManager->buildAndSetLightClip(lightList);
315
                // skip if entirely clipped
316
0
                if(scissored == CLIPPED_ALL || clipped == CLIPPED_ALL)
317
0
                    continue;
318
319
0
                visitor->renderObjects(pPriorityGrp->getSolidsDiffuseSpecular(), om, false, false, &lightList);
320
0
                if (scissored == CLIPPED_SOME)
321
0
                    mSceneManager->resetScissor();
322
0
                if (clipped == CLIPPED_SOME)
323
0
                    mSceneManager->resetLightClip();
324
325
0
            }// for each light
326
327
0
            mSceneManager->mIlluminationStage = IRS_NONE;
328
329
            // Now render decal passes, no need to set lights as lighting will be disabled
330
0
            visitor->renderObjects(pPriorityGrp->getSolidsDecal(), om, false, false);
331
332
0
        }
333
334
335
0
    }// for each priority
336
0
}
337
//-----------------------------------------------------------------------
338
void SceneManager::TextureShadowRenderer::renderTextureShadowReceiverQueueGroupObjects(
339
    RenderQueueGroup* pGroup,
340
    QueuedRenderableCollection::OrganisationMode om)
341
0
{
342
    // Iterate through priorities
343
344
    // Override auto param ambient to force vertex programs to go full-bright
345
0
    ColourValue currAmbient = mSceneManager->getAmbientLight();
346
0
    mSceneManager->setAmbientLight(ColourValue::White);
347
0
    auto visitor = mSceneManager->getQueuedRenderableVisitor();
348
349
0
    for (const auto& pg : pGroup->getPriorityGroups())
350
0
    {
351
0
        RenderPriorityGroup* pPriorityGrp = pg.second;
352
353
        // Do solids, override light list incase any vertex programs use them
354
0
        visitor->renderObjects(pPriorityGrp->getSolidsBasic(), om, false, false);
355
356
        // Don't render transparents or passes which have shadow receipt disabled
357
358
0
    }// for each priority
359
360
    // reset ambient
361
0
    mSceneManager->setAmbientLight(currAmbient);
362
0
}
363
//---------------------------------------------------------------------
364
void SceneManager::TextureShadowRenderer::setupRenderTarget(const String& camName, RenderTarget* rendTarget,
365
                                                            uint16 depthBufferId)
366
0
{
367
0
    if (rendTarget->getDepthBufferPool() != RBP_NONE)
368
0
    {
369
0
        rendTarget->setDepthBufferPool(depthBufferId);
370
0
    }
371
372
    // Don't update automatically - we'll do it when required
373
0
    rendTarget->setAutoUpdated(false);
374
375
0
    float aspectRatio = (Real)rendTarget->getWidth() / (Real)rendTarget->getHeight();
376
377
    // Create camera for this texture, but note that we have to rebind
378
    // in prepareShadowTextures to coexist with multiple SMs
379
0
    Camera* cam = mSceneManager->createCamera(camName);
380
0
    cam->setAspectRatio(aspectRatio);
381
0
    auto camNode = mSceneManager->getRootSceneNode()->createChildSceneNode();
382
0
    camNode->attachObject(cam);
383
0
    mShadowTextureCameras.push_back(cam);
384
    // insert dummy camera-light combination
385
0
    mShadowCamLightMapping[cam] = NULL;
386
387
    // use separate culling camera, in case a focused shadow setup is used
388
    // in which case we want to keep the original light frustum for culling
389
0
    Camera* cullCam = mSceneManager->createCamera(camName+"/Cull");
390
0
    cullCam->setAspectRatio(aspectRatio);
391
0
    cam->setCullingFrustum(cullCam);
392
0
    camNode->attachObject(cullCam);
393
394
    // Create a viewport, if not there already
395
0
    if (rendTarget->getNumViewports() != 0)
396
0
        return;
397
398
    // Note camera assignment is transient when multiple SMs
399
0
    Viewport *v = rendTarget->addViewport(NULL);
400
0
    v->setClearEveryFrame(true);
401
0
    v->setOverlaysEnabled(false);
402
0
    v->setBackgroundColour(ColourValue::White);
403
0
}
404
405
void SceneManager::TextureShadowRenderer::ensureShadowTexturesCreated()
406
0
{
407
0
    if(!mBorderSampler)
408
0
    {
409
0
        mBorderSampler = TextureManager::getSingleton().createSampler();
410
0
        mBorderSampler->setAddressingMode(TAM_BORDER);
411
0
        mBorderSampler->setBorderColour(ColourValue::White);
412
0
        mBorderSampler->setFiltering(FT_MIP, FO_NONE); // we do not have mips. GLES2 is particularly picky here.
413
0
    }
414
415
0
    if (mShadowTextureConfigDirty)
416
0
    {
417
0
        destroyShadowTextures();
418
0
        ShadowTextureManager::getSingleton().getShadowTextures(mShadowTextureConfigList, mShadowTextures);
419
420
        // clear shadow cam - light mapping
421
0
        mShadowCamLightMapping.clear();
422
423
        //Used to get the depth buffer ID setting for each RTT
424
0
        size_t __i = 0;
425
426
        // Recreate shadow textures
427
0
        for (auto& shadowTex : mShadowTextures)
428
0
        {
429
0
            uint16 depthBufferId = mShadowTextureConfigList[__i].depthBufferPoolId;
430
0
            for(uint32 i = 0; i < shadowTex->getNumLayers(); i++)
431
0
            {
432
0
                String camName = StringUtil::format("%sCam%d", shadowTex->getName().c_str(), i);
433
0
                auto rtidx = shadowTex->getUsage() & TU_TARGET_ALL_LAYERS ? 0 : i;
434
0
                setupRenderTarget(camName, shadowTex->getRenderTarget(rtidx), depthBufferId);
435
0
            }
436
437
0
            ++__i;
438
0
        }
439
440
        // Assume first one is representative
441
0
        if (!mShadowTextureConfigList.empty())
442
0
            mNoShadowTexture =
443
0
                ShadowTextureManager::getSingleton().getNoShadowTexture(mShadowTextureConfigList[0].format);
444
445
0
        mShadowTextureConfigDirty = false;
446
0
    }
447
448
0
}
449
//---------------------------------------------------------------------
450
void SceneManager::TextureShadowRenderer::destroyShadowTextures(void)
451
0
{
452
0
    for (auto cam : mShadowTextureCameras)
453
0
    {
454
0
        mSceneManager->getRootSceneNode()->removeAndDestroyChild(cam->getParentSceneNode());
455
456
        // Always destroy camera since they are local to this SM
457
0
        if(auto cullcam = dynamic_cast<Camera*>(cam->getCullingFrustum()))
458
0
            mSceneManager->destroyCamera(cullcam);
459
460
0
        mSceneManager->destroyCamera(cam);
461
0
    }
462
0
    mShadowTextures.clear();
463
0
    mShadowTextureCameras.clear();
464
465
    // set by render*TextureShadowedQueueGroupObjects
466
0
    mSceneManager->mAutoParamDataSource->setTextureProjector(NULL, 0);
467
468
    // Will destroy if no other scene managers referencing
469
0
    ShadowTextureManager::getSingleton().clearUnused();
470
471
0
    mShadowTextureConfigDirty = true;
472
0
}
473
//---------------------------------------------------------------------
474
void SceneManager::TextureShadowRenderer::prepareTexCam(Camera* texCam, Camera* cam, Viewport* vp, Light* light,
475
                                                        size_t j)
476
0
{
477
    // Associate main view camera as LOD camera
478
0
    texCam->setLodCamera(cam);
479
    // set base
480
0
    if (light->getType() != Light::LT_POINT)
481
0
    {
482
#ifdef OGRE_NODELESS_POSITIONING
483
        texCam->getParentSceneNode()->setDirection(light->getDerivedDirection(), Node::TS_WORLD);
484
#else
485
0
        texCam->getParentSceneNode()->setOrientation(light->getParentNode()->_getDerivedOrientation());
486
0
#endif
487
0
    }
488
0
    if (light->getType() != Light::LT_DIRECTIONAL)
489
0
        texCam->getParentSceneNode()->setPosition(light->getDerivedPosition());
490
491
    // update shadow cam - light mapping
492
0
    ShadowCamLightMapping::iterator camLightIt = mShadowCamLightMapping.find(texCam);
493
0
    assert(camLightIt != mShadowCamLightMapping.end());
494
0
    camLightIt->second = light;
495
496
0
    if (!light->getCustomShadowCameraSetup())
497
0
        mDefaultShadowCameraSetup->getShadowCamera(mSceneManager, cam, vp, light, texCam, j);
498
0
    else
499
0
        light->getCustomShadowCameraSetup()->getShadowCamera(mSceneManager, cam, vp, light, texCam, j);
500
501
    // Fire shadow caster update, callee can alter camera settings
502
0
    fireShadowTexturesPreCaster(light, texCam, j);
503
0
}
504
void SceneManager::TextureShadowRenderer::updateShadowTextures(Camera* cam, Viewport* vp, const LightList* lightList)
505
0
{
506
    // Determine far shadow distance
507
0
    Real shadowDist = mDefaultShadowFarDist;
508
0
    if (!shadowDist)
509
0
    {
510
        // need a shadow distance, make one up
511
0
        shadowDist = cam->getNearClipDistance() * 300;
512
0
    }
513
0
    Real shadowOffset = shadowDist * mShadowTextureOffset;
514
    // Precalculate fading info
515
0
    Real shadowEnd = shadowDist + shadowOffset;
516
0
    Real fadeStart = shadowEnd * mShadowTextureFadeStart;
517
0
    Real fadeEnd = shadowEnd * mShadowTextureFadeEnd;
518
    // Additive lighting should not use fogging, since it will overbrighten; use border clamp
519
0
    if (!mSceneManager->isShadowTechniqueAdditive())
520
0
    {
521
        // set fogging to hide the shadow edge
522
0
        mShadowReceiverPass->setFog(true, FOG_LINEAR, ColourValue::White, 0, fadeStart, fadeEnd);
523
0
    }
524
0
    else
525
0
    {
526
        // disable fogging explicitly
527
0
        mShadowReceiverPass->setFog(true, FOG_NONE);
528
0
    }
529
530
    // Iterate over the lights we've found, max out at the limit of light textures
531
    // Note that the light sorting must now place shadow casting lights at the
532
    // start of the light list, therefore we do not need to deal with potential
533
    // mismatches in the light<->shadow texture list any more
534
535
0
    LightList::const_iterator i, iend;
536
0
    ShadowTextureList::iterator si, siend;
537
0
    CameraList::iterator ci;
538
0
    iend = lightList->end();
539
0
    siend = mShadowTextures.end();
540
0
    ci = mShadowTextureCameras.begin();
541
0
    mShadowTextureIndexLightList.clear();
542
0
    size_t shadowTextureIndex = 0;
543
544
0
    for (i = lightList->begin(), si = mShadowTextures.begin(); i != iend && si != siend; ++i)
545
0
    {
546
0
        Light* light = *i;
547
548
        // skip light if shadows are disabled
549
0
        if (!light->getCastShadows())
550
0
            continue;
551
552
0
        mDestRenderSystem->_setDepthClamp(light->getType() == Light::LT_DIRECTIONAL);
553
554
        // texture iteration per light.
555
0
        size_t textureCountPerLight = mShadowTextureCountPerType[light->getType()];
556
0
        for (size_t j = 0; j < textureCountPerLight && si != siend; ++j)
557
0
        {
558
0
            TexturePtr &shadowTex = *si;
559
560
0
            size_t layer = j < shadowTex->getDepth() ? j : 0;
561
0
            size_t face = j < shadowTex->getNumFaces() ? j : 0;
562
0
            RenderTarget *shadowRTT = shadowTex->getBuffer(face)->getRenderTarget(layer);
563
0
            Viewport *shadowView = shadowRTT->getViewport(0);
564
0
            Camera *texCam = *ci;
565
            // rebind camera, incase another SM in use which has switched to its cam
566
0
            shadowView->setCamera(texCam);
567
568
            // also update culling camera
569
0
            auto cullCam = dynamic_cast<Camera*>(texCam->getCullingFrustum());
570
0
            cullCam->_notifyViewport(shadowView);
571
0
            mCullCameraSetup->getShadowCamera(mSceneManager, cam, vp, light, cullCam, j);
572
573
            // Use the material scheme of the main viewport
574
            // This is required to pick up the correct shadow_caster_material and similar properties.
575
0
            shadowView->setMaterialScheme(vp->getMaterialScheme());
576
577
            // Set the viewport visibility flags
578
0
            shadowView->setVisibilityMask(light->getLightMask() & vp->getVisibilityMask());
579
580
0
            bool allLayers = shadowTex->getUsage() & TU_TARGET_ALL_LAYERS;
581
0
            size_t layers = std::max(shadowTex->getDepth(), shadowTex->getNumFaces());
582
583
0
            prepareTexCam(texCam, cam, vp, light, j);
584
0
            if(allLayers && layers <= textureCountPerLight)
585
0
            {
586
                // All layers share one viewport and culling camera, so they see
587
                // the same shadow casters. Seed the other split cameras with the
588
                // bounds of the layer that is actually rendered; otherwise their
589
                // focus/LiSPSM setup has no scene bounds and falls back to the
590
                // default shadow projection.
591
0
                std::vector<const Camera*> cams = {texCam};
592
0
                const AxisAlignedBox casterAabb =
593
0
                    mSceneManager->mCamVisibleObjectsMap[cams[0]].aabb;
594
595
0
                j++;
596
0
                for(; j < layers; ++j)
597
0
                {
598
0
                    texCam = *(++ci); // next camera
599
0
                    texCam->_notifyViewport(shadowView);
600
0
                    mSceneManager->mCamVisibleObjectsMap[texCam].aabb = casterAabb;
601
0
                    prepareTexCam(texCam, cam, vp, light, j);
602
0
                    cams.push_back(texCam);
603
0
                }
604
0
                mSceneManager->setVPRTCameras(cams);
605
0
            }
606
607
            // Update target
608
0
            shadowRTT->update();
609
610
0
            if((j + 1) >= layers)
611
0
                ++si; // next shadow texture
612
0
            ++ci; // next camera
613
0
        }
614
615
0
        mDestRenderSystem->_setDepthClamp(false);
616
617
        // set the first shadow texture index for this light.
618
0
        mShadowTextureIndexLightList.push_back(shadowTextureIndex);
619
0
        shadowTextureIndex += textureCountPerLight;
620
0
    }
621
622
0
    fireShadowTexturesUpdated(std::min(lightList->size(), mShadowTextures.size()));
623
624
0
    ShadowTextureManager::getSingleton().clearUnused();
625
0
}
626
627
628
void SceneManager::TextureShadowRenderer::setShadowTextureCasterMaterial(const MaterialPtr& mat)
629
0
{
630
0
    if(!mat) {
631
0
        mShadowTextureCustomCasterPass = 0;
632
0
        return;
633
0
    }
634
635
0
    mat->load();
636
0
    if (!mat->getBestTechnique())
637
0
    {
638
        // unsupported
639
0
        mShadowTextureCustomCasterPass = 0;
640
0
    }
641
0
    else
642
0
    {
643
0
        OgreAssert(!mat->getTechnique(0)->getPasses().empty(), "technique 0 has no passes");
644
0
        mShadowTextureCustomCasterPass = mat->getTechnique(0)->getPass(0);
645
0
    }
646
0
}
647
//---------------------------------------------------------------------
648
void SceneManager::TextureShadowRenderer::setShadowTextureReceiverMaterial(const MaterialPtr& mat)
649
0
{
650
0
    if(!mat) {
651
0
        mShadowTextureCustomReceiverPass = 0;
652
0
        return;
653
0
    }
654
655
0
    mat->load();
656
0
    if (!mat->getBestTechnique())
657
0
    {
658
        // unsupported
659
0
        mShadowTextureCustomReceiverPass = 0;
660
0
    }
661
0
    else
662
0
    {
663
0
        OgreAssert(!mat->getTechnique(0)->getPasses().empty(), "technique 0 has no passes");
664
0
        mShadowTextureCustomReceiverPass = mat->getTechnique(0)->getPass(0);
665
0
    }
666
0
}
667
//---------------------------------------------------------------------
668
void SceneManager::TextureShadowRenderer::setShadowTechnique(ShadowTechnique technique)
669
0
{
670
0
    if (mSceneManager->getShadowTechnique() == SHADOWTYPE_TEXTURE_MODULATIVE && !mSpotFadeTexture)
671
0
        mSpotFadeTexture = TextureManager::getSingleton().load("spot_shadow_fade.dds", RGN_INTERNAL);
672
673
0
    if (!mSceneManager->isShadowTechniqueTextureBased())
674
0
    {
675
        // Destroy shadow textures to optimise resource usage
676
0
        destroyShadowTextures();
677
0
        mSpotFadeTexture.reset();
678
0
    }
679
0
    else
680
0
    {
681
        // assure no custom shadow matrix is used accidentally in case we switch
682
        // from a custom shadow mapping type to a non-custom (uniform shadow mapping)
683
0
        for ( Camera* texCam : mShadowTextureCameras)
684
0
        {
685
0
            texCam->setCustomViewMatrix(false);
686
0
            texCam->setCustomProjectionMatrix(false);
687
0
        }
688
0
    }
689
690
0
    if(!mSceneManager->getShadowTechnique())
691
0
        return;
692
693
    // init shadow caster material for texture shadows
694
0
    if (!mShadowCasterPlainBlackPass)
695
0
    {
696
0
        MaterialPtr matPlainBlack = MaterialManager::getSingleton().getByName("Ogre/TextureShadowCaster");
697
0
        matPlainBlack->load();
698
0
        mShadowCasterPlainBlackPass = matPlainBlack->getTechnique(0)->getPass(0);
699
0
    }
700
701
0
    if (!mShadowReceiverPass)
702
0
    {
703
0
        MaterialPtr matShadRec = MaterialManager::getSingleton().getByName("Ogre/TextureShadowReceiver", RGN_INTERNAL);
704
0
        if (!matShadRec)
705
0
        {
706
0
            matShadRec = MaterialManager::getSingleton().create("Ogre/TextureShadowReceiver", RGN_INTERNAL);
707
0
            mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0);
708
            // Don't set lighting and blending modes here, depends on additive / modulative
709
0
            TextureUnitState* t = mShadowReceiverPass->createTextureUnitState();
710
0
            t->setProjectiveTexturing(true, NULL); // will be set later, but the RTSS needs to know about this
711
0
        }
712
0
        else
713
0
        {
714
0
            mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0);
715
0
        }
716
0
    }
717
0
}
718
719
720
const Pass* SceneManager::TextureShadowRenderer::deriveShadowCasterPass(const Pass* pass)
721
0
{
722
0
    Pass* retPass;
723
0
    if (pass->getParent()->getShadowCasterMaterial())
724
0
    {
725
0
        auto bestTech = pass->getParent()->getShadowCasterMaterial()->getBestTechnique();
726
0
        if (bestTech && bestTech->getNumPasses() > 0) {
727
0
            return bestTech->getPass(0);
728
0
        }
729
0
    }
730
0
    retPass = mShadowTextureCustomCasterPass ?
731
0
        mShadowTextureCustomCasterPass : mShadowCasterPlainBlackPass;
732
733
    // Special case alpha-blended passes
734
0
    if ((pass->getSourceBlendFactor() == SBF_SOURCE_ALPHA &&
735
0
        pass->getDestBlendFactor() == SBF_ONE_MINUS_SOURCE_ALPHA)
736
0
        || pass->getAlphaRejectFunction() != CMPF_ALWAYS_PASS)
737
0
    {
738
        // Alpha blended passes must retain their transparency
739
0
        retPass->setAlphaRejectSettings(pass->getAlphaRejectFunction(),
740
0
            pass->getAlphaRejectValue());
741
0
        retPass->setSceneBlending(pass->getSourceBlendFactor(), pass->getDestBlendFactor());
742
0
        retPass->getParent()->getParent()->setTransparencyCastsShadows(true);
743
744
        // So we allow the texture units, but override the colour functions
745
        // Copy texture state, shift up one since 0 is shadow texture
746
0
        unsigned short origPassTUCount = pass->getNumTextureUnitStates();
747
0
        for (unsigned short t = 0; t < origPassTUCount; ++t)
748
0
        {
749
0
            TextureUnitState* tex;
750
0
            if (retPass->getNumTextureUnitStates() <= t)
751
0
            {
752
0
                tex = retPass->createTextureUnitState();
753
0
            }
754
0
            else
755
0
            {
756
0
                tex = retPass->getTextureUnitState(t);
757
0
            }
758
            // copy base state
759
0
            (*tex) = *(pass->getTextureUnitState(t));
760
            // override colour function
761
0
            tex->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT,
762
0
                                      mSceneManager->isShadowTechniqueAdditive() ? ColourValue::Black : mSceneManager->getShadowColour());
763
0
        }
764
        // Remove any extras
765
0
        while (retPass->getNumTextureUnitStates() > origPassTUCount)
766
0
        {
767
0
            retPass->removeTextureUnitState(origPassTUCount);
768
0
        }
769
770
0
    }
771
0
    else
772
0
    {
773
        // reset
774
0
        retPass->setSceneBlending(SBT_REPLACE);
775
0
        retPass->setAlphaRejectFunction(CMPF_ALWAYS_PASS);
776
0
        while (retPass->getNumTextureUnitStates() > 0)
777
0
        {
778
0
            retPass->removeTextureUnitState(0);
779
0
        }
780
0
    }
781
782
    // give the RTSS a chance to generate a better technique
783
0
    retPass->getParent()->getParent()->load();
784
785
0
    Technique* btech = retPass->getParent()->getParent()->getBestTechnique();
786
0
    if( btech )
787
0
    {
788
0
        retPass = btech->getPass(0);
789
0
    }
790
791
    // Propagate culling modes
792
0
    retPass->setCullingMode(pass->getCullingMode());
793
0
    retPass->setManualCullingMode(pass->getManualCullingMode());
794
795
0
    return retPass;
796
0
}
797
//---------------------------------------------------------------------
798
const Pass* SceneManager::TextureShadowRenderer::deriveShadowReceiverPass(const Pass* pass)
799
0
{
800
0
    if (pass->getParent()->getShadowReceiverMaterial())
801
0
    {
802
0
        return pass->getParent()->getShadowReceiverMaterial()->getBestTechnique()->getPass(0);
803
0
    }
804
805
0
    Pass* retPass = mShadowTextureCustomReceiverPass ? mShadowTextureCustomReceiverPass : mShadowReceiverPass;
806
807
0
    unsigned short keepTUCount;
808
    // If additive, need lighting parameters & standard programs
809
0
    if (mSceneManager->isShadowTechniqueAdditive())
810
0
    {
811
0
        retPass->setLightingEnabled(true);
812
0
        retPass->setAmbient(pass->getAmbient());
813
0
        retPass->setSelfIllumination(pass->getSelfIllumination());
814
0
        retPass->setDiffuse(pass->getDiffuse());
815
0
        retPass->setSpecular(pass->getSpecular());
816
0
        retPass->setShininess(pass->getShininess());
817
0
        retPass->setLightMask(pass->getLightMask());
818
819
        // We need to keep alpha rejection settings
820
0
        retPass->setAlphaRejectSettings(pass->getAlphaRejectFunction(),
821
0
            pass->getAlphaRejectValue());
822
        // Copy texture state, shift up one since 0 is shadow texture
823
0
        unsigned short origPassTUCount = pass->getNumTextureUnitStates();
824
0
        for (unsigned short t = 0; t < origPassTUCount; ++t)
825
0
        {
826
0
            unsigned short targetIndex = t+1;
827
0
            TextureUnitState* tex;
828
0
            if (retPass->getNumTextureUnitStates() <= targetIndex)
829
0
            {
830
0
                tex = retPass->createTextureUnitState();
831
0
            }
832
0
            else
833
0
            {
834
0
                tex = retPass->getTextureUnitState(targetIndex);
835
0
            }
836
0
            (*tex) = *(pass->getTextureUnitState(t));
837
            // If programmable, have to adjust the texcoord sets too
838
            // D3D insists that texcoordsets match tex unit in programmable mode
839
0
            if (retPass->hasVertexProgram())
840
0
                tex->setTextureCoordSet(targetIndex);
841
0
        }
842
0
        keepTUCount = origPassTUCount + 1;
843
0
    }// additive lighting
844
0
    else
845
0
    {
846
        // need to keep spotlight fade etc
847
0
        keepTUCount = retPass->getNumTextureUnitStates();
848
0
    }
849
850
    // re-/set light iteration settings
851
0
    retPass->setIteratePerLight(pass->getIteratePerLight(), pass->getRunOnlyForOneLightType(),
852
0
                                pass->getOnlyLightType());
853
854
    // Remove any extra texture units
855
0
    while (retPass->getNumTextureUnitStates() > keepTUCount)
856
0
    {
857
0
        retPass->removeTextureUnitState(keepTUCount);
858
0
    }
859
860
    // give the RTSS a chance to generate a better technique
861
0
    retPass->getParent()->getParent()->load();
862
863
0
    Technique* btech = retPass->getParent()->getParent()->getBestTechnique();
864
0
    if( btech )
865
0
    {
866
0
        retPass = btech->getPass(0);
867
0
    }
868
869
0
    return retPass;
870
0
}
871
872
const Pass* SceneManager::TextureShadowRenderer::deriveTextureShadowPass(const Pass* pass)
873
0
{
874
0
    if (mSceneManager->_getCurrentRenderStage() == IRS_RENDER_TO_TEXTURE)
875
0
    {
876
        // Derive a special shadow caster pass from this one
877
0
        return deriveShadowCasterPass(pass);
878
0
    }
879
880
0
    if (mSceneManager->_getCurrentRenderStage() == IRS_RENDER_RECEIVER_PASS)
881
0
    {
882
0
        return deriveShadowReceiverPass(pass);
883
0
    }
884
885
0
    return pass;
886
0
}
887
888
//---------------------------------------------------------------------
889
const VisibleObjectsBoundsInfo&
890
SceneManager::TextureShadowRenderer::getShadowCasterBoundsInfo( const Light* light, size_t iteration ) const
891
0
{
892
0
    static VisibleObjectsBoundsInfo nullBox;
893
894
    // find light
895
0
    unsigned int foundCount = 0;
896
0
    for (auto& m : mShadowCamLightMapping)
897
0
    {
898
0
        if (m.second == light )
899
0
        {
900
0
            if (foundCount == iteration)
901
0
            {
902
                // search the camera-aab list for the texture cam
903
0
                auto camIt = mSceneManager->mCamVisibleObjectsMap.find(m.first);
904
905
0
                if (camIt == mSceneManager->mCamVisibleObjectsMap.end())
906
0
                {
907
0
                    return nullBox;
908
0
                }
909
0
                else
910
0
                {
911
0
                    return camIt->second;
912
0
                }
913
0
            }
914
0
            else
915
0
            {
916
                // multiple shadow textures per light, keep searching
917
0
                ++foundCount;
918
0
            }
919
0
        }
920
0
    }
921
922
    // AAB not available
923
0
    return nullBox;
924
0
}
925
926
927
//---------------------------------------------------------------------
928
void SceneManager::TextureShadowRenderer::setShadowTextureConfig(size_t shadowIndex, unsigned short width,
929
    unsigned short height, PixelFormat format, unsigned short fsaa, uint16 depthBufferPoolId )
930
0
{
931
0
    ShadowTextureConfig conf;
932
0
    conf.width = width;
933
0
    conf.height = height;
934
0
    conf.format = format;
935
0
    conf.fsaa = fsaa;
936
0
    conf.depthBufferPoolId = depthBufferPoolId;
937
938
0
    setShadowTextureConfig(shadowIndex, conf);
939
940
941
0
}
942
//---------------------------------------------------------------------
943
void SceneManager::TextureShadowRenderer::setShadowTextureConfig(size_t shadowIndex,
944
    const ShadowTextureConfig& config)
945
0
{
946
0
    if (shadowIndex >= mShadowTextureConfigList.size())
947
0
    {
948
0
        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
949
0
            "shadowIndex out of bounds",
950
0
            "SceneManager::setShadowTextureConfig");
951
0
    }
952
0
    mShadowTextureConfigList[shadowIndex] = config;
953
954
0
    mShadowTextureConfigDirty = true;
955
0
}
956
957
void SceneManager::TextureShadowRenderer::setShadowTextureCompositor(const String& compositorName,
958
                                                                     const String& resourceGroup)
959
0
{
960
0
    auto compositor = CompositorManager::getSingleton().getByName(compositorName, resourceGroup);
961
0
    OgreAssert(compositor, "Compositor not found");
962
0
    OgreAssert(compositor->getNumTechniques() > 0, "Compositor has no techniques");
963
964
0
    auto compositorTech = compositor->getTechnique(0);
965
0
    const auto& textures = compositorTech->getTextureDefinitions();
966
0
    OgreAssert(!textures.empty(), "Compositor technique has no textures");
967
968
0
    mShadowTextureConfigList.clear();
969
0
    mShadowTextureConfigDirty = true;
970
971
0
    for(const auto& texture : textures)
972
0
    {
973
0
        OgreAssert(texture->width && texture->height, "Compositor texture definition must have absolute size");
974
0
        OgreAssert(texture->formatList.size() == 1, "Compositor texture definition must have exactly one format");
975
976
0
        ShadowTextureConfig cfg;
977
0
        cfg.width = texture->width;
978
0
        cfg.height = texture->height;
979
0
        cfg.format = texture->formatList.front();
980
0
        cfg.fsaa = texture->fsaa > 1 ? texture->fsaa : 0;
981
0
        cfg.depthBufferPoolId = texture->depthBufferId;
982
0
        cfg.type = texture->type;
983
0
        cfg.depth = texture->depth;
984
985
0
        mShadowTextureConfigList.push_back(cfg);
986
0
    }
987
0
}
988
989
//---------------------------------------------------------------------
990
void SceneManager::TextureShadowRenderer::setShadowTextureSize(unsigned short size)
991
0
{
992
    // default all current
993
0
    for (auto & i : mShadowTextureConfigList)
994
0
    {
995
0
        if (i.width != size || i.height != size)
996
0
        {
997
0
            i.width = i.height = size;
998
0
            mShadowTextureConfigDirty = true;
999
0
        }
1000
0
    }
1001
1002
0
}
1003
//---------------------------------------------------------------------
1004
void SceneManager::TextureShadowRenderer::setShadowTextureCount(size_t count)
1005
0
{
1006
    // Change size, any new items will need defaults
1007
0
    if (count != mShadowTextureConfigList.size())
1008
0
    {
1009
        // if no entries yet, use the defaults
1010
0
        if (mShadowTextureConfigList.empty())
1011
0
        {
1012
0
            mShadowTextureConfigList.resize(count);
1013
0
        }
1014
0
        else
1015
0
        {
1016
            // create new instances with the same settings as the last item in the list
1017
0
            mShadowTextureConfigList.resize(count, *mShadowTextureConfigList.rbegin());
1018
0
        }
1019
0
        mShadowTextureConfigDirty = true;
1020
0
    }
1021
0
}
1022
//---------------------------------------------------------------------
1023
void SceneManager::TextureShadowRenderer::setShadowTexturePixelFormat(PixelFormat fmt)
1024
0
{
1025
0
    for (auto & i : mShadowTextureConfigList)
1026
0
    {
1027
0
        if (i.format != fmt)
1028
0
        {
1029
0
            i.format = fmt;
1030
0
            mShadowTextureConfigDirty = true;
1031
0
        }
1032
0
    }
1033
0
}
1034
void SceneManager::TextureShadowRenderer::setShadowTextureFSAA(unsigned short fsaa)
1035
0
{
1036
0
    for (auto & i : mShadowTextureConfigList)
1037
0
    {
1038
0
        if (i.fsaa != fsaa)
1039
0
        {
1040
0
            i.fsaa = fsaa;
1041
0
            mShadowTextureConfigDirty = true;
1042
0
        }
1043
0
    }
1044
0
}
1045
//---------------------------------------------------------------------
1046
void SceneManager::TextureShadowRenderer::setShadowTextureSettings(unsigned short size,
1047
    unsigned short count, PixelFormat fmt, unsigned short fsaa, uint16 depthBufferPoolId)
1048
0
{
1049
0
    setShadowTextureCount(count);
1050
0
    for (auto & i : mShadowTextureConfigList)
1051
0
    {
1052
0
        if (i.width != size || i.height != size || i.format != fmt || i.fsaa != fsaa)
1053
0
        {
1054
0
            i.width = i.height = size;
1055
0
            i.format = fmt;
1056
0
            i.fsaa = fsaa;
1057
0
            i.depthBufferPoolId = depthBufferPoolId;
1058
0
            mShadowTextureConfigDirty = true;
1059
0
        }
1060
0
    }
1061
0
}
1062
//---------------------------------------------------------------------
1063
const TexturePtr& SceneManager::TextureShadowRenderer::getShadowTexture(size_t shadowIndex)
1064
0
{
1065
0
    mSceneManager->ensureShadowTexturesCreated();
1066
1067
0
    OgreAssert(shadowIndex < mShadowTextures.size(), "");
1068
0
    return mShadowTextures[shadowIndex];
1069
0
}
1070
1071
void SceneManager::TextureShadowRenderer::resolveShadowTexture(TextureUnitState* tu, size_t shadowIndex, size_t shadowTexUnitIndex) const
1072
0
{
1073
0
    if (shadowIndex >= mShadowTextures.size())
1074
0
    {
1075
0
        tu->_setTexturePtr(mNoShadowTexture);
1076
0
        tu->setProjectiveTexturing(false);
1077
0
        return;
1078
0
    }
1079
1080
0
    auto& shadowTex = mShadowTextures[shadowIndex];
1081
    // Enable projective texturing if fixed-function, but also need to
1082
    // disable it explicitly for program pipeline.
1083
0
    tu->setProjectiveTexturing(!tu->getParent()->hasVertexProgram(), mShadowTextureCameras[shadowIndex]);
1084
0
    tu->_setTexturePtr(shadowTex);
1085
1086
    // set up projectors for all layers, fixed function does not support layered textures anyway
1087
0
    size_t layers = std::max(shadowTex->getDepth(), shadowTex->getNumFaces());
1088
0
    layers = std::min(layers, mShadowTextureCameras.size() - shadowIndex); // clamp
1089
0
    for (size_t l = 0; l < layers; ++l)
1090
0
        mSceneManager->mAutoParamDataSource->setTextureProjector(mShadowTextureCameras[shadowIndex + l],
1091
0
                                                                 shadowTexUnitIndex + l);
1092
0
}
1093
1094
namespace
1095
{
1096
/** Default sorting routine which sorts lights which cast shadows
1097
to the front of a list, sub-sorting by distance.
1098
1099
Since shadow textures are generated from lights based on the
1100
frustum rather than individual objects, a shadow and camera-wise sort is
1101
required to pick the best lights near the start of the list. Up to
1102
the number of shadow textures will be generated from this.
1103
*/
1104
struct lightsForShadowTextureLess
1105
{
1106
    bool operator()(const Light* l1, const Light* l2) const
1107
0
    {
1108
0
        if (l1 == l2)
1109
0
            return false;
1110
1111
        // sort shadow casting lights ahead of non-shadow casting
1112
0
        if (l1->getCastShadows() != l2->getCastShadows())
1113
0
        {
1114
0
            return l1->getCastShadows();
1115
0
        }
1116
1117
        // otherwise sort by distance (directional lights will have 0 here)
1118
0
        return l1->tempSquareDist < l2->tempSquareDist;
1119
0
    }
1120
};
1121
} // namespace
1122
1123
void SceneManager::TextureShadowRenderer::sortLightsAffectingFrustum(LightList& lightList) const
1124
0
{
1125
    // Sort the lights if using texture shadows, since the first 'n' will be
1126
    // used to generate shadow textures and we should pick the most appropriate
1127
1128
0
    ListenerList listenersCopy = mListeners; // copy in case of listeners removing themselves
1129
1130
    // Allow a Listener to override light sorting
1131
    // Reverse iterate so last takes precedence
1132
0
    for (auto ri = listenersCopy.rbegin(); ri != listenersCopy.rend(); ++ri)
1133
0
    {
1134
0
        if((*ri)->sortLightsAffectingFrustum(lightList))
1135
0
            return;
1136
0
    }
1137
1138
    // default sort (stable to preserve directional light ordering
1139
0
    std::stable_sort(lightList.begin(), lightList.end(), lightsForShadowTextureLess());
1140
0
}
1141
//---------------------------------------------------------------------
1142
void SceneManager::TextureShadowRenderer::fireShadowTexturesUpdated(size_t numberOfShadowTextures)
1143
0
{
1144
0
    ListenerList listenersCopy = mListeners;
1145
1146
0
    for (auto *l : listenersCopy)
1147
0
    {
1148
0
        l->shadowTexturesUpdated(numberOfShadowTextures);
1149
0
    }
1150
0
}
1151
//---------------------------------------------------------------------
1152
void SceneManager::TextureShadowRenderer::fireShadowTexturesPreCaster(Light* light, Camera* camera, size_t iteration)
1153
0
{
1154
0
    auto listenersCopy = mListeners;
1155
0
    for (auto l : listenersCopy)
1156
0
    {
1157
0
        l->shadowTextureCasterPreViewProj(light, camera, iteration);
1158
0
    }
1159
0
}
1160
//---------------------------------------------------------------------
1161
void SceneManager::TextureShadowRenderer::fireShadowTexturesPreReceiver(Light* light, Frustum* f)
1162
0
{
1163
0
    ListenerList listenersCopy = mListeners;
1164
0
    for (auto *l : listenersCopy)
1165
0
    {
1166
0
        l->shadowTextureReceiverPreViewProj(light, f);
1167
0
    }
1168
0
}
1169
}