Coverage Report

Created: 2026-02-23 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgrePass.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 <memory>
29
30
#include "OgreStableHeaders.h"
31
32
#include "OgreGpuProgramUsage.h"
33
#include "OgreTextureUnitState.h"
34
35
namespace Ogre {
36
37
    /** Default pass hash function.
38
39
        Tries to minimise the number of texture changes.
40
    */
41
    struct MinTextureStateChangeHashFunc : public Pass::HashFunc
42
    {
43
        uint32 operator()(const Pass* p) const override
44
0
        {
45
0
            OGRE_LOCK_MUTEX(p->mTexUnitChangeMutex);
46
0
            uint32 hash = 0;
47
0
            ushort c = p->getNumTextureUnitStates();
48
49
0
            for (ushort i = 0; i < c; ++i)
50
0
            {
51
0
                const TextureUnitState* tus = 0;
52
0
                tus = p->getTextureUnitState(i);
53
0
                hash = FastHash(tus->getTextureName().c_str(), tus->getTextureName().size(), hash);
54
0
            }
55
56
0
            return hash;
57
0
        }
58
    };
59
    MinTextureStateChangeHashFunc sMinTextureStateChangeHashFunc;
60
    /** Alternate pass hash function.
61
62
        Tries to minimise the number of GPU program changes.
63
    */
64
    struct MinGpuProgramChangeHashFunc : public Pass::HashFunc
65
    {
66
        uint32 operator()(const Pass* p) const override
67
0
        {
68
0
            OGRE_LOCK_MUTEX(p->mGpuProgramChangeMutex);
69
0
            uint32 hash = 0;
70
71
0
            for(int i = 0; i < GPT_COUNT; i++)
72
0
            {
73
0
                const String& name = p->getGpuProgramName(GpuProgramType(i));
74
0
                if(!name.empty()) {
75
0
                    hash = FastHash(name.c_str(), name.size(), hash);
76
0
                }
77
0
            }
78
79
0
            return hash;
80
0
        }
81
    };
82
    MinGpuProgramChangeHashFunc sMinGpuProgramChangeHashFunc;
83
    //-----------------------------------------------------------------------------
84
    Pass::PassSet Pass::msDirtyHashList;
85
    Pass::PassSet Pass::msPassGraveyard;
86
    OGRE_STATIC_MUTEX_INSTANCE(Pass::msDirtyHashListMutex);
87
    OGRE_STATIC_MUTEX_INSTANCE(Pass::msPassGraveyardMutex);
88
89
    Pass::HashFunc* Pass::msHashFunc = &sMinGpuProgramChangeHashFunc;
90
    //-----------------------------------------------------------------------------
91
    Pass::HashFunc* Pass::getBuiltinHashFunction(BuiltinHashFunction builtin)
92
0
    {
93
0
        Pass::HashFunc* hashFunc = NULL;
94
95
0
        switch(builtin)
96
0
        {
97
0
        case MIN_TEXTURE_CHANGE:
98
0
            hashFunc = &sMinTextureStateChangeHashFunc;
99
0
            break;
100
0
        case MIN_GPU_PROGRAM_CHANGE:
101
0
            hashFunc = &sMinGpuProgramChangeHashFunc;
102
0
            break;
103
0
        }
104
105
0
        return hashFunc;
106
0
    }
107
    //-----------------------------------------------------------------------------
108
    void Pass::setHashFunction(BuiltinHashFunction builtin)
109
0
    {
110
0
        switch(builtin)
111
0
        {
112
0
        case MIN_TEXTURE_CHANGE:
113
0
            msHashFunc = &sMinTextureStateChangeHashFunc;
114
0
            break;
115
0
        case MIN_GPU_PROGRAM_CHANGE:
116
0
            msHashFunc = &sMinGpuProgramChangeHashFunc;
117
0
            break;
118
0
        }
119
0
    }
120
    //-----------------------------------------------------------------------------
121
    Pass::Pass(Technique* parent, unsigned short index)
122
0
        : mParent(parent)
123
0
        , mHash(0)
124
0
        , mAmbient(ColourValue::White)
125
0
        , mDiffuse(ColourValue::White)
126
0
        , mSpecular(ColourValue::Black)
127
0
        , mEmissive(ColourValue::Black)
128
0
        , mShininess(0)
129
0
        , mTracking(TVC_NONE)
130
0
        , mHashDirtyQueued(false)
131
0
        , mDepthCheck(true)
132
0
        , mDepthWrite(true)
133
0
        , mAlphaToCoverageEnabled(false)
134
0
        , mTransparentSorting(true)
135
0
        , mTransparentSortingForced(false)
136
0
        , mLightingEnabled(true)
137
0
        , mIteratePerLight(false)
138
0
        , mRunOnlyForOneLightType(false)
139
0
        , mPolygonModeOverrideable(true)
140
0
        , mFogOverride(false)
141
0
        , mQueuedForDeletion(false)
142
0
        , mLightScissoring(false)
143
0
        , mLightClipPlanes(false)
144
0
        , mPointSpritesEnabled(false)
145
0
        , mPointAttenuationEnabled(false)
146
0
        , mContentTypeLookupBuilt(false)
147
0
        , mAlphaRejectVal(0)
148
0
        , mDepthBiasConstant(0.0f)
149
0
        , mDepthBiasSlopeScale(0.0f)
150
0
        , mDepthBiasPerIteration(0.0f)
151
0
        , mDepthFunc(CMPF_LESS_EQUAL)
152
0
        , mAlphaRejectFunc(CMPF_ALWAYS_PASS)
153
0
        , mCullMode(CULL_CLOCKWISE)
154
0
        , mManualCullMode(MANUAL_CULL_BACK)
155
0
        , mMaxSimultaneousLights(OGRE_MAX_SIMULTANEOUS_LIGHTS)
156
0
        , mStartLight(0)
157
0
        , mLightsPerIteration(1)
158
0
        , mIndex(index)
159
0
        , mLightMask(0xFFFFFFFF)
160
0
        , mFogColour(ColourValue::White)
161
0
        , mFogStart(0.0)
162
0
        , mFogEnd(1.0)
163
0
        , mFogDensity(0.001)
164
0
        , mLineWidth(1.0f)
165
0
        , mPassIterationCount(1)
166
0
        , mPointMinSize(0.0f)
167
0
        , mPointMaxSize(0.0f)
168
0
        , mPointAttenution(1.0f, 1.0f, 0.0f, 0.0f)
169
0
        , mShadeOptions(SO_GOURAUD)
170
0
        , mPolygonMode(PM_SOLID)
171
0
        , mIlluminationStage(IS_UNKNOWN)
172
0
        , mOnlyLightType(Light::LT_POINT)
173
0
        , mFogMode(FOG_NONE)
174
0
    {
175
        // init the hash inline
176
0
        _recalculateHash();
177
0
   }
178
179
    //-----------------------------------------------------------------------------
180
    Pass::Pass(Technique *parent, unsigned short index, const Pass& oth)
181
0
        : mParent(parent), mQueuedForDeletion(false), mIndex(index), mPassIterationCount(1)
182
0
    {
183
0
        *this = oth;
184
0
        mParent = parent;
185
0
        mIndex = index;
186
0
        mQueuedForDeletion = false;
187
188
        // init the hash inline
189
0
        _recalculateHash();
190
0
    }
191
0
    Pass::~Pass() = default; // ensure unique_ptr destructors are in cpp
192
    //-----------------------------------------------------------------------------
193
    Pass& Pass::operator=(const Pass& oth)
194
0
    {
195
0
        mName = oth.mName;
196
0
        mHash = oth.mHash;
197
0
        mAmbient = oth.mAmbient;
198
0
        mDiffuse = oth.mDiffuse;
199
0
        mSpecular = oth.mSpecular;
200
0
        mEmissive = oth.mEmissive;
201
0
        mShininess = oth.mShininess;
202
0
        mTracking = oth.mTracking;
203
204
        // Copy fog parameters
205
0
        mFogOverride = oth.mFogOverride;
206
0
        mFogMode = oth.mFogMode;
207
0
        mFogColour = oth.mFogColour;
208
0
        mFogStart = oth.mFogStart;
209
0
        mFogEnd = oth.mFogEnd;
210
0
        mFogDensity = oth.mFogDensity;
211
212
        // Default blending (overwrite)
213
0
        mBlendState = oth.mBlendState;
214
215
0
        mDepthCheck = oth.mDepthCheck;
216
0
        mDepthWrite = oth.mDepthWrite;
217
0
        mAlphaRejectFunc = oth.mAlphaRejectFunc;
218
0
        mAlphaRejectVal = oth.mAlphaRejectVal;
219
0
        mAlphaToCoverageEnabled = oth.mAlphaToCoverageEnabled;
220
0
        mTransparentSorting = oth.mTransparentSorting;
221
0
        mTransparentSortingForced = oth.mTransparentSortingForced;
222
0
        mDepthFunc = oth.mDepthFunc;
223
0
        mDepthBiasConstant = oth.mDepthBiasConstant;
224
0
        mDepthBiasSlopeScale = oth.mDepthBiasSlopeScale;
225
0
        mDepthBiasPerIteration = oth.mDepthBiasPerIteration;
226
0
        mCullMode = oth.mCullMode;
227
0
        mManualCullMode = oth.mManualCullMode;
228
0
        mLightingEnabled = oth.mLightingEnabled;
229
0
        mMaxSimultaneousLights = oth.mMaxSimultaneousLights;
230
0
        mStartLight = oth.mStartLight;
231
0
        mIteratePerLight = oth.mIteratePerLight;
232
0
        mLightsPerIteration = oth.mLightsPerIteration;
233
0
        mRunOnlyForOneLightType = oth.mRunOnlyForOneLightType;
234
0
        mOnlyLightType = oth.mOnlyLightType;
235
0
        mShadeOptions = oth.mShadeOptions;
236
0
        mPolygonMode = oth.mPolygonMode;
237
0
        mPolygonModeOverrideable = oth.mPolygonModeOverrideable;
238
0
        mPassIterationCount = oth.mPassIterationCount;
239
0
        mLineWidth = oth.mLineWidth;
240
0
        mPointAttenution = oth.mPointAttenution;
241
0
        mPointMinSize = oth.mPointMinSize;
242
0
        mPointMaxSize = oth.mPointMaxSize;
243
0
        mPointSpritesEnabled = oth.mPointSpritesEnabled;
244
0
        mPointAttenuationEnabled = oth.mPointAttenuationEnabled;
245
0
        mShadowContentTypeLookup = oth.mShadowContentTypeLookup;
246
0
        mContentTypeLookupBuilt = oth.mContentTypeLookupBuilt;
247
0
        mLightScissoring = oth.mLightScissoring;
248
0
        mLightClipPlanes = oth.mLightClipPlanes;
249
0
        mIlluminationStage = oth.mIlluminationStage;
250
0
        mLightMask = oth.mLightMask;
251
252
0
        for(int i = 0; i < GPT_PIPELINE_COUNT; i++)
253
0
        {
254
0
            auto& programUsage = mProgramUsage[i];
255
0
            auto& othUsage = oth.mProgramUsage[i];
256
0
            programUsage = othUsage ? std::make_unique<GpuProgramUsage>(*othUsage, this) : nullptr;
257
0
        }
258
259
        // Clear texture units but doesn't notify need recompilation in the case
260
        // we are cloning, The parent material will take care of this.
261
0
        for (auto *t : mTextureUnitStates)
262
0
        {
263
0
            OGRE_DELETE t;
264
0
        }
265
266
0
        mTextureUnitStates.clear();
267
268
        // Copy texture units
269
0
        for (auto *s : oth.mTextureUnitStates)
270
0
        {
271
0
            TextureUnitState* t = OGRE_NEW TextureUnitState(this, *s);
272
0
            mTextureUnitStates.push_back(t);
273
0
        }
274
275
0
        _dirtyHash();
276
277
0
        return *this;
278
0
    }
279
    //-----------------------------------------------------------------------------
280
    size_t Pass::calculateSize(void) const
281
0
    {
282
0
        size_t memSize = 0;
283
284
        // Tally up TU states
285
0
        for (auto *t : mTextureUnitStates)
286
0
        {
287
0
            memSize += t->calculateSize();
288
0
        }
289
0
        for(const auto& u : mProgramUsage)
290
0
            memSize += u ? u->calculateSize() : 0;
291
292
0
        return memSize;
293
0
    }
294
    //-----------------------------------------------------------------------
295
    void Pass::setPointAttenuation(bool enabled, float constant, float linear, float quadratic)
296
0
    {
297
0
        mPointAttenuationEnabled = enabled;
298
0
        mPointAttenution[1] = enabled ? constant : 1.0f;
299
0
        mPointAttenution[2] = enabled ? linear : 0.0f;
300
0
        mPointAttenution[3] = enabled ? quadratic : 0.0f;
301
0
    }
302
    //-----------------------------------------------------------------------
303
    void Pass::setPointMinSize(Real min)
304
0
    {
305
0
        mPointMinSize = min;
306
0
    }
307
    //-----------------------------------------------------------------------
308
    Real Pass::getPointMinSize(void) const
309
0
    {
310
0
        return mPointMinSize;
311
0
    }
312
    //-----------------------------------------------------------------------
313
    void Pass::setPointMaxSize(Real max)
314
0
    {
315
0
        mPointMaxSize = max;
316
0
    }
317
    //-----------------------------------------------------------------------
318
    Real Pass::getPointMaxSize(void) const
319
0
    {
320
0
        return mPointMaxSize;
321
0
    }
322
    //-----------------------------------------------------------------------
323
    void Pass::setAmbient(float red, float green, float blue)
324
0
    {
325
0
        mAmbient.r = red;
326
0
        mAmbient.g = green;
327
0
        mAmbient.b = blue;
328
329
0
    }
330
    //-----------------------------------------------------------------------
331
    void Pass::setDiffuse(float red, float green, float blue, float alpha)
332
0
    {
333
0
        mDiffuse.r = red;
334
0
        mDiffuse.g = green;
335
0
        mDiffuse.b = blue;
336
0
        mDiffuse.a = alpha;
337
0
    }
338
    //-----------------------------------------------------------------------
339
    void Pass::setSpecular(float red, float green, float blue, float alpha)
340
0
    {
341
0
        mSpecular.r = red;
342
0
        mSpecular.g = green;
343
0
        mSpecular.b = blue;
344
0
        mSpecular.a = alpha;
345
0
    }
346
    //-----------------------------------------------------------------------
347
    void Pass::setSelfIllumination(float red, float green, float blue)
348
0
    {
349
0
        mEmissive.r = red;
350
0
        mEmissive.g = green;
351
0
        mEmissive.b = blue;
352
0
    }
353
    //-----------------------------------------------------------------------
354
    TextureUnitState* Pass::createTextureUnitState(void)
355
0
    {
356
0
        TextureUnitState *t = OGRE_NEW TextureUnitState(this);
357
0
        addTextureUnitState(t);
358
0
        mContentTypeLookupBuilt = false;
359
0
        return t;
360
0
    }
361
    //-----------------------------------------------------------------------
362
    TextureUnitState* Pass::createTextureUnitState(
363
        const String& textureName, unsigned short texCoordSet)
364
0
    {
365
0
        TextureUnitState *t = OGRE_NEW TextureUnitState(this);
366
0
        t->setTextureName(textureName);
367
0
        t->setTextureCoordSet(texCoordSet);
368
0
        addTextureUnitState(t);
369
0
        mContentTypeLookupBuilt = false;
370
0
        return t;
371
0
    }
372
    //-----------------------------------------------------------------------
373
    void Pass::addTextureUnitState(TextureUnitState* state)
374
0
    {
375
0
        OGRE_LOCK_MUTEX(mTexUnitChangeMutex);
376
377
0
        OgreAssert(state , "TextureUnitState is NULL");
378
379
        // only attach TUS to pass if TUS does not belong to another pass
380
0
        OgreAssert(!state->getParent() || (state->getParent() == this), "TextureUnitState already attached to another pass");
381
382
0
        mTextureUnitStates.push_back(state);
383
        // Notify state
384
0
        state->_notifyParent(this);
385
        // if texture unit state name is empty then give it a default name based on its index
386
0
        if (state->getName().empty())
387
0
        {
388
            // its the last entry in the container so its index is size - 1
389
0
            size_t idx = mTextureUnitStates.size() - 1;
390
391
            // allow 8 digit hex number. there should never be that many texture units.
392
            // This sprintf replaced a call to StringConverter::toString for performance reasons
393
0
            state->setName( StringUtil::format("%lx", static_cast<long>(idx)));
394
0
        }
395
0
        _notifyNeedsRecompile();
396
0
        _dirtyHash();
397
398
0
        mContentTypeLookupBuilt = false;
399
0
    }
400
    //-----------------------------------------------------------------------------
401
    TextureUnitState* Pass::getTextureUnitState(const String& name) const
402
0
    {
403
0
        OGRE_LOCK_MUTEX(mTexUnitChangeMutex);
404
0
        TextureUnitState* foundTUS = 0;
405
406
        // iterate through TUS Container to find a match
407
0
        for (auto *t : mTextureUnitStates)
408
0
        {
409
0
            if (t->getName() == name)
410
0
            {
411
0
                foundTUS = t;
412
0
                break;
413
0
            }
414
0
        }
415
416
0
        return foundTUS;
417
0
    }
418
419
    //-----------------------------------------------------------------------
420
    unsigned short Pass::getTextureUnitStateIndex(const TextureUnitState* state) const
421
0
    {
422
0
        OGRE_LOCK_MUTEX(mTexUnitChangeMutex);
423
0
        assert(state && "state is 0 in Pass::getTextureUnitStateIndex()");
424
425
        // only find index for state attached to this pass
426
0
        OgreAssert(state->getParent() == this, "TextureUnitState is not attached to this pass");
427
0
        auto i = std::find(mTextureUnitStates.begin(), mTextureUnitStates.end(), state);
428
0
        assert(i != mTextureUnitStates.end() && "state is supposed to attached to this pass");
429
0
        return static_cast<unsigned short>(std::distance(mTextureUnitStates.begin(), i));
430
0
    }
431
432
    //-----------------------------------------------------------------------
433
    Pass::TextureUnitStateIterator
434
        Pass::getTextureUnitStateIterator(void)
435
0
    {
436
0
        return TextureUnitStateIterator(mTextureUnitStates.begin(), mTextureUnitStates.end());
437
0
    }
438
    //-----------------------------------------------------------------------
439
    Pass::ConstTextureUnitStateIterator
440
        Pass::getTextureUnitStateIterator(void) const
441
0
    {
442
0
        return ConstTextureUnitStateIterator(mTextureUnitStates.begin(), mTextureUnitStates.end());
443
0
    }
444
    //-----------------------------------------------------------------------
445
    void Pass::removeTextureUnitState(unsigned short index)
446
0
    {
447
0
        OGRE_LOCK_MUTEX(mTexUnitChangeMutex);
448
0
        assert (index < mTextureUnitStates.size() && "Index out of bounds");
449
450
0
        TextureUnitStates::iterator i = mTextureUnitStates.begin() + index;
451
0
        OGRE_DELETE *i;
452
0
        mTextureUnitStates.erase(i);
453
0
        _notifyNeedsRecompile();
454
0
        _dirtyHash();
455
0
        mContentTypeLookupBuilt = false;
456
0
    }
457
    //-----------------------------------------------------------------------
458
    void Pass::removeAllTextureUnitStates(void)
459
0
    {
460
0
        OGRE_LOCK_MUTEX(mTexUnitChangeMutex);
461
0
        TextureUnitStates::iterator i, iend;
462
0
        iend = mTextureUnitStates.end();
463
0
        for (i = mTextureUnitStates.begin(); i != iend; ++i)
464
0
        {
465
0
            OGRE_DELETE *i;
466
0
        }
467
0
        mTextureUnitStates.clear();
468
0
        _notifyNeedsRecompile();
469
0
        _dirtyHash();
470
0
        mContentTypeLookupBuilt = false;
471
0
    }
472
    //-----------------------------------------------------------------------
473
    static void _getBlendFlags(SceneBlendType type, SceneBlendFactor& source, SceneBlendFactor& dest)
474
0
    {
475
0
        switch ( type )
476
0
        {
477
0
        case SBT_TRANSPARENT_ALPHA:
478
0
            source = SBF_SOURCE_ALPHA;
479
0
            dest = SBF_ONE_MINUS_SOURCE_ALPHA;
480
0
            return;
481
0
        case SBT_TRANSPARENT_COLOUR:
482
0
            source = SBF_SOURCE_COLOUR;
483
0
            dest = SBF_ONE_MINUS_SOURCE_COLOUR;
484
0
            return;
485
0
        case SBT_MODULATE:
486
0
            source = SBF_DEST_COLOUR;
487
0
            dest = SBF_ZERO;
488
0
            return;
489
0
        case SBT_ADD:
490
0
            source = SBF_ONE;
491
0
            dest = SBF_ONE;
492
0
            return;
493
0
        default:
494
0
        case SBT_REPLACE:
495
0
            source = SBF_ONE;
496
0
            dest = SBF_ZERO;
497
0
            return;
498
0
        }
499
0
    }
500
    //-----------------------------------------------------------------------
501
    void Pass::setSceneBlending(SceneBlendType sbt)
502
0
    {
503
        // Convert type into blend factors
504
505
0
        SceneBlendFactor source;
506
0
        SceneBlendFactor dest;
507
0
        _getBlendFlags(sbt, source, dest);
508
509
        // Set blend factors
510
511
0
        setSceneBlending(source, dest);
512
0
    }
513
    //-----------------------------------------------------------------------
514
    void Pass::setSeparateSceneBlending( const SceneBlendType sbt, const SceneBlendType sbta )
515
0
    {
516
        // Convert types into blend factors
517
518
0
        SceneBlendFactor source;
519
0
        SceneBlendFactor dest;
520
0
        _getBlendFlags(sbt, source, dest);
521
522
0
        SceneBlendFactor sourceAlpha;
523
0
        SceneBlendFactor destAlpha;
524
0
        _getBlendFlags(sbta, sourceAlpha, destAlpha);
525
526
        // Set blend factors
527
528
0
        setSeparateSceneBlending(source, dest, sourceAlpha, destAlpha);
529
0
    }
530
531
    //-----------------------------------------------------------------------
532
    void Pass::setSceneBlending(SceneBlendFactor sourceFactor, SceneBlendFactor destFactor)
533
0
    {
534
0
        mBlendState.sourceFactor = sourceFactor;
535
0
        mBlendState.sourceFactorAlpha = sourceFactor;
536
0
        mBlendState.destFactor = destFactor;
537
0
        mBlendState.destFactorAlpha = destFactor;
538
0
    }
539
    //-----------------------------------------------------------------------
540
    void Pass::setSeparateSceneBlending( const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor, const SceneBlendFactor sourceFactorAlpha, const SceneBlendFactor destFactorAlpha )
541
0
    {
542
0
        mBlendState.sourceFactor = sourceFactor;
543
0
        mBlendState.destFactor = destFactor;
544
0
        mBlendState.sourceFactorAlpha = sourceFactorAlpha;
545
0
        mBlendState.destFactorAlpha = destFactorAlpha;
546
0
    }
547
    //-----------------------------------------------------------------------
548
    void Pass::setSceneBlendingOperation(SceneBlendOperation op)
549
0
    {
550
0
        mBlendState.operation = op;
551
0
        mBlendState.alphaOperation = op;
552
0
    }
553
    //-----------------------------------------------------------------------
554
    void Pass::setSeparateSceneBlendingOperation(SceneBlendOperation op, SceneBlendOperation alphaOp)
555
0
    {
556
0
        mBlendState.operation = op;
557
0
        mBlendState.alphaOperation = alphaOp;
558
0
    }
559
    //-----------------------------------------------------------------------
560
    bool Pass::isTransparent(void) const
561
0
    {
562
        // Transparent if any of the destination colour is taken into account
563
0
        if (mBlendState.destFactor == SBF_ZERO &&
564
0
            mBlendState.sourceFactor != SBF_DEST_COLOUR &&
565
0
            mBlendState.sourceFactor != SBF_ONE_MINUS_DEST_COLOUR &&
566
0
            mBlendState.sourceFactor != SBF_DEST_ALPHA &&
567
0
            mBlendState.sourceFactor != SBF_ONE_MINUS_DEST_ALPHA)
568
0
        {
569
0
            return false;
570
0
        }
571
0
        else
572
0
        {
573
0
            return true;
574
0
        }
575
0
    }
576
    //-----------------------------------------------------------------------
577
    void Pass::setAlphaRejectSettings(CompareFunction func, unsigned char value, bool alphaToCoverage)
578
0
    {
579
0
        mAlphaRejectFunc = func;
580
0
        mAlphaRejectVal = value;
581
0
        mAlphaToCoverageEnabled = alphaToCoverage;
582
0
    }
583
    //-----------------------------------------------------------------------
584
    void Pass::setColourWriteEnabled(bool enabled)
585
0
    {
586
0
        mBlendState.writeR = enabled;
587
0
        mBlendState.writeG = enabled;
588
0
        mBlendState.writeB = enabled;
589
0
        mBlendState.writeA = enabled;
590
0
    }
591
    //-----------------------------------------------------------------------
592
    bool Pass::getColourWriteEnabled() const
593
0
    {
594
0
        return mBlendState.writeR || mBlendState.writeG || mBlendState.writeB ||
595
0
               mBlendState.writeA;
596
0
    }
597
    //-----------------------------------------------------------------------
598
599
    void Pass::setColourWriteEnabled(bool red, bool green, bool blue, bool alpha)
600
0
    {
601
0
        mBlendState.writeR = red;
602
0
        mBlendState.writeG = green;
603
0
        mBlendState.writeB = blue;
604
0
        mBlendState.writeA = alpha;
605
0
    }
606
    //-----------------------------------------------------------------------
607
    void Pass::getColourWriteEnabled(bool& red, bool& green, bool& blue, bool& alpha) const
608
0
    {
609
0
        red = mBlendState.writeR;
610
0
        green = mBlendState.writeG;
611
0
        blue = mBlendState.writeB;
612
0
        alpha = mBlendState.writeA;
613
0
    }
614
    //-----------------------------------------------------------------------
615
    void Pass::setIteratePerLight(bool enabled,
616
            bool onlyForOneLightType, Light::LightTypes lightType)
617
0
    {
618
0
        mIteratePerLight = enabled;
619
0
        mRunOnlyForOneLightType = onlyForOneLightType;
620
0
        mOnlyLightType = lightType;
621
0
    }
622
    //-----------------------------------------------------------------------
623
    void Pass::setManualCullingMode(ManualCullingMode mode)
624
0
    {
625
0
        mManualCullMode = mode;
626
0
    }
627
    //-----------------------------------------------------------------------
628
    ManualCullingMode Pass::getManualCullingMode(void) const
629
0
    {
630
0
        return mManualCullMode;
631
0
    }
632
    //-----------------------------------------------------------------------
633
    void Pass::setFog(bool overrideScene, FogMode mode, const ColourValue& colour, float density, float start, float end)
634
0
    {
635
0
        mFogOverride = overrideScene;
636
0
        if (overrideScene)
637
0
        {
638
0
            mFogMode = mode;
639
0
            mFogColour = colour;
640
0
            mFogStart = start;
641
0
            mFogEnd = end;
642
0
            mFogDensity = density;
643
0
        }
644
0
    }
645
    //-----------------------------------------------------------------------
646
    void Pass::setDepthBias(float constantBias, float slopeScaleBias)
647
0
    {
648
0
       mDepthBiasConstant = constantBias;
649
0
       mDepthBiasSlopeScale = slopeScaleBias;
650
0
    }
651
    //-----------------------------------------------------------------------
652
    Pass* Pass::_split(unsigned short numUnits)
653
0
    {
654
0
        OgreAssert(
655
0
            !isProgrammable(),
656
0
            "Programmable passes cannot be automatically split, define a fallback technique instead");
657
658
0
        if (mTextureUnitStates.size() > numUnits)
659
0
        {
660
0
            size_t start = mTextureUnitStates.size() - numUnits;
661
662
0
            Pass* newPass = mParent->createPass();
663
664
0
            TextureUnitStates::iterator istart, i, iend;
665
0
            iend = mTextureUnitStates.end();
666
0
            i = istart = mTextureUnitStates.begin() + start;
667
            // Set the new pass to fallback using scene blend
668
0
            newPass->setSceneBlending(
669
0
                (*i)->getColourBlendFallbackSrc(), (*i)->getColourBlendFallbackDest());
670
            // Fixup the texture unit 0   of new pass   blending method   to replace
671
            // all colour and alpha   with texture without adjustment, because we
672
            // assume it's detail texture.
673
0
            (*i)->setColourOperationEx(LBX_SOURCE1,   LBS_TEXTURE, LBS_CURRENT);
674
0
            (*i)->setAlphaOperation(LBX_SOURCE1, LBS_TEXTURE, LBS_CURRENT);
675
676
            // Add all the other texture unit states
677
0
            for (; i != iend; ++i)
678
0
            {
679
                // detach from parent first
680
0
                (*i)->_notifyParent(0);
681
0
                newPass->addTextureUnitState(*i);
682
0
            }
683
            // Now remove texture units from this Pass, we don't need to delete since they've
684
            // been transferred
685
0
            mTextureUnitStates.erase(istart, iend);
686
0
            _dirtyHash();
687
0
            mContentTypeLookupBuilt = false;
688
0
            return newPass;
689
0
        }
690
0
        return NULL;
691
0
    }
692
    //-----------------------------------------------------------------------------
693
    void Pass::_notifyIndex(unsigned short index)
694
0
    {
695
0
        if (mIndex != index)
696
0
        {
697
0
            mIndex = index;
698
0
            _dirtyHash();
699
0
        }
700
0
    }
701
    //-----------------------------------------------------------------------
702
    void Pass::_prepare(void)
703
0
    {
704
        // We assume the Technique only calls this when the material is being
705
        // prepared
706
        // prepare each TextureUnitState
707
0
        for (auto *t : mTextureUnitStates)
708
0
        {
709
0
            t->_prepare();
710
0
        }
711
712
0
    }
713
    //-----------------------------------------------------------------------
714
    void Pass::_unprepare(void)
715
0
    {
716
        // unprepare each TextureUnitState
717
0
        for (auto *t : mTextureUnitStates)
718
0
        {
719
0
            t->_unprepare();
720
0
        }
721
722
0
    }
723
    //-----------------------------------------------------------------------
724
    void Pass::_load(void)
725
0
    {
726
        // We assume the Technique only calls this when the material is being
727
        // loaded
728
        // Load each TextureUnitState
729
0
        for (auto *t : mTextureUnitStates)
730
0
        {
731
0
            t->_load();
732
0
        }
733
734
        // Load programs
735
0
        for (const auto& u : mProgramUsage)
736
0
            if(u) u->_load();
737
738
0
        if (mHashDirtyQueued)
739
0
        {
740
0
            _dirtyHash();
741
0
        }
742
743
0
    }
744
    //-----------------------------------------------------------------------
745
    void Pass::_unload(void)
746
0
    {
747
        // Unload each TextureUnitState
748
0
        for (auto *t : mTextureUnitStates)
749
0
        {
750
0
            t->_unload();
751
0
        }
752
753
        // TODO Unload programs
754
0
    }
755
    //-----------------------------------------------------------------------
756
    void Pass::setGpuProgramParameters(GpuProgramType type, const GpuProgramParametersSharedPtr& params)
757
0
    {
758
0
        OGRE_LOCK_MUTEX(mGpuProgramChangeMutex);
759
760
0
        const auto& programUsage = getProgramUsage(type);
761
0
        if (!programUsage)
762
0
        {
763
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
764
0
                "This pass does not have this program type assigned!");
765
0
        }
766
0
        programUsage->setParameters(params);
767
0
    }
768
    //-----------------------------------------------------------------------
769
    void Pass::setGpuProgram(GpuProgramType type, const GpuProgramPtr& program, bool resetParams)
770
0
    {
771
0
        OGRE_LOCK_MUTEX(mGpuProgramChangeMutex);
772
773
0
        std::unique_ptr<GpuProgramUsage>& programUsage = getProgramUsage(type);
774
775
        // Turn off fragment program if name blank
776
0
        if (!program)
777
0
        {
778
0
            programUsage.reset();
779
0
        }
780
0
        else
781
0
        {
782
0
            if (!programUsage)
783
0
            {
784
0
                programUsage = std::make_unique<GpuProgramUsage>(type, this);
785
0
            }
786
0
            programUsage->setProgram(program, resetParams);
787
0
        }
788
        // Needs recompilation
789
0
        _notifyNeedsRecompile();
790
791
0
        if( Pass::getHashFunction() == Pass::getBuiltinHashFunction( Pass::MIN_GPU_PROGRAM_CHANGE ) )
792
0
        {
793
0
            _dirtyHash();
794
0
        }
795
0
    }
796
797
    void Pass::setGpuProgram(GpuProgramType type, const String& name, bool resetParams)
798
0
    {
799
0
        if (getGpuProgramName(type) == name)
800
0
            return;
801
802
0
        GpuProgramPtr program;
803
0
        if (!name.empty())
804
0
            program = GpuProgramUsage::_getProgramByName(name, getResourceGroup(), type);
805
806
0
        setGpuProgram(type, program, resetParams);
807
0
    }
808
    //-----------------------------------------------------------------------
809
    const GpuProgramParametersSharedPtr& Pass::getGpuProgramParameters(GpuProgramType type) const
810
0
    {
811
0
        OGRE_LOCK_MUTEX(mGpuProgramChangeMutex);
812
0
        const auto& programUsage = getProgramUsage(type);
813
0
        if (!programUsage)
814
0
        {
815
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "This pass has no " + to_string(type) + " program");
816
0
        }
817
0
        return programUsage->getParameters();
818
0
    }
819
820
0
    std::unique_ptr<GpuProgramUsage>& Pass::getProgramUsage(GpuProgramType programType) {
821
0
        return mProgramUsage[programType % GPT_PIPELINE_COUNT];
822
0
    }
823
824
    const std::unique_ptr<GpuProgramUsage>& Pass::getProgramUsage(GpuProgramType programType) const
825
0
    {
826
0
        static std::unique_ptr<GpuProgramUsage> nullUsage;
827
0
        auto& ret = mProgramUsage[programType % GPT_PIPELINE_COUNT];
828
0
        return ret && ret->getType() == programType ? ret : nullUsage;
829
0
    }
830
831
0
    bool Pass::hasGpuProgram(GpuProgramType programType) const {
832
0
        return getProgramUsage(programType) != NULL;
833
0
    }
834
    const GpuProgramPtr& Pass::getGpuProgram(GpuProgramType programType) const
835
0
  {
836
0
        OGRE_LOCK_MUTEX(mGpuProgramChangeMutex);
837
0
        const auto& programUsage = getProgramUsage(programType);
838
0
        OgreAssert(programUsage, "check whether program is available using hasGpuProgram()");
839
0
        return programUsage->getProgram();
840
0
  }
841
    //-----------------------------------------------------------------------
842
    const String& Pass::getGpuProgramName(GpuProgramType type) const
843
0
    {
844
0
        OGRE_LOCK_MUTEX(mGpuProgramChangeMutex);
845
846
0
        const std::unique_ptr<GpuProgramUsage>& programUsage = getProgramUsage(type);
847
0
        if (!programUsage)
848
0
            return BLANKSTRING;
849
0
        else
850
0
            return programUsage->getProgramName();
851
0
    }
852
    //-----------------------------------------------------------------------
853
    bool Pass::isLoaded(void) const
854
0
    {
855
0
        return mParent->isLoaded();
856
0
    }
857
    //-----------------------------------------------------------------------
858
    void Pass::_recalculateHash(void)
859
0
    {
860
        /* Hash format is 32-bit, divided as follows (high to low bits)
861
           bits   purpose
862
            4     Pass index (i.e. max 16 passes!)
863
           28     Pass contents
864
       */
865
0
        mHash = (*msHashFunc)(this);
866
867
        // overwrite the 4 upper bits with pass index
868
0
        mHash = (uint32(mIndex) << 28) | (mHash >> 4);
869
0
    }
870
    //-----------------------------------------------------------------------
871
    void Pass::_dirtyHash(void)
872
0
    {
873
0
        if (mQueuedForDeletion)
874
0
            return;
875
876
0
        Material* mat = mParent->getParent();
877
0
        if (mat->isLoading() || mat->isLoaded())
878
0
        {
879
0
            OGRE_LOCK_MUTEX(msDirtyHashListMutex);
880
            // Mark this hash as for follow up
881
0
            msDirtyHashList.insert(this);
882
0
            mHashDirtyQueued = false;
883
0
        }
884
0
        else
885
0
        {
886
0
            mHashDirtyQueued = true;
887
0
        }
888
0
    }
889
    //---------------------------------------------------------------------
890
    void Pass::clearDirtyHashList(void) 
891
0
    { 
892
0
            OGRE_LOCK_MUTEX(msDirtyHashListMutex);
893
0
        msDirtyHashList.clear(); 
894
0
    }
895
    //-----------------------------------------------------------------------
896
    void Pass::_notifyNeedsRecompile(void)
897
0
    {
898
0
        if (!mQueuedForDeletion)
899
0
            mParent->_notifyNeedsRecompile();
900
0
    }
901
    //-----------------------------------------------------------------------
902
    void Pass::setTextureFiltering(TextureFilterOptions filterType)
903
0
    {
904
0
        OGRE_LOCK_MUTEX(mTexUnitChangeMutex);
905
0
        for (auto *t : mTextureUnitStates)
906
0
        {
907
0
            t->setTextureFiltering(filterType);
908
0
        }
909
0
    }
910
    // --------------------------------------------------------------------
911
    void Pass::setTextureAnisotropy(unsigned int maxAniso)
912
0
    {
913
0
        OGRE_LOCK_MUTEX(mTexUnitChangeMutex);
914
0
        for (auto *t : mTextureUnitStates)
915
0
        {
916
0
            t->setTextureAnisotropy(maxAniso);
917
0
        }
918
0
    }
919
    //-----------------------------------------------------------------------
920
    void Pass::_updateAutoParams(const AutoParamDataSource* source, uint16 mask) const
921
0
    {
922
0
        for(int i = 0; i < GPT_COUNT; i++)
923
0
        {
924
0
            const auto& programUsage = getProgramUsage(GpuProgramType(i));
925
0
            if (programUsage)
926
0
            {
927
                // Update program auto params
928
0
                programUsage->getParameters()->_updateAutoParams(source, mask);
929
0
            }
930
0
        }
931
0
    }
932
    //-----------------------------------------------------------------------
933
    void Pass::processPendingPassUpdates(void)
934
1
    {
935
1
        {
936
1
            OGRE_LOCK_MUTEX(msPassGraveyardMutex);
937
            // Delete items in the graveyard
938
1
            for (auto& i : msPassGraveyard)
939
0
            {
940
0
                OGRE_DELETE i;
941
0
            }
942
1
            msPassGraveyard.clear();
943
1
        }
944
1
        PassSet tempDirtyHashList;
945
1
        {
946
1
            OGRE_LOCK_MUTEX(msDirtyHashListMutex);
947
            // The dirty ones will have been removed from the groups above using the old hash now
948
1
            tempDirtyHashList.swap(msDirtyHashList);
949
1
        }
950
1
        for (auto *p : tempDirtyHashList)
951
0
        {
952
0
            p->_recalculateHash();
953
0
        }
954
1
    }
955
    //-----------------------------------------------------------------------
956
    void Pass::queueForDeletion(void)
957
0
    {
958
0
        mQueuedForDeletion = true;
959
960
0
        removeAllTextureUnitStates();
961
0
        for (auto& u : mProgramUsage)
962
0
            u.reset();
963
964
        // remove from dirty list, if there
965
0
        {
966
0
            OGRE_LOCK_MUTEX(msDirtyHashListMutex);
967
0
            msDirtyHashList.erase(this);
968
0
        }
969
0
        {
970
0
            OGRE_LOCK_MUTEX(msPassGraveyardMutex);
971
0
            msPassGraveyard.insert(this);
972
0
        }
973
0
    }
974
    //-----------------------------------------------------------------------
975
    bool Pass::isAmbientOnly(void) const
976
0
    {
977
        // treat as ambient if lighting is off, or colour write is off,
978
        // or all non-ambient (& emissive) colours are black
979
        // NB a vertex program could override this, but passes using vertex
980
        // programs are expected to indicate they are ambient only by
981
        // setting the state so it matches one of the conditions above, even
982
        // though this state is not used in rendering.
983
0
        return (!mLightingEnabled || !getColourWriteEnabled() ||
984
0
            (mDiffuse == ColourValue::Black &&
985
0
             mSpecular == ColourValue::Black));
986
0
    }
987
    //-----------------------------------------------------------------------
988
    const String& Pass::getResourceGroup(void) const
989
0
    {
990
0
        return mParent->getResourceGroup();
991
0
    }
992
    //-----------------------------------------------------------------------
993
    unsigned short Pass::_getTextureUnitWithContentTypeIndex(
994
        TextureUnitState::ContentType contentType, unsigned short index) const
995
0
    {
996
0
        if (!mContentTypeLookupBuilt)
997
0
        {
998
0
            mShadowContentTypeLookup.clear();
999
0
            for (unsigned short i = 0; i < mTextureUnitStates.size(); ++i)
1000
0
            {
1001
0
                if (mTextureUnitStates[i]->getContentType() == TextureUnitState::CONTENT_SHADOW)
1002
0
                {
1003
0
                    mShadowContentTypeLookup.push_back(i);
1004
0
                }
1005
0
            }
1006
0
            mContentTypeLookupBuilt = true;
1007
0
        }
1008
1009
0
        switch(contentType)
1010
0
        {
1011
0
        case TextureUnitState::CONTENT_SHADOW:
1012
0
            if (index < mShadowContentTypeLookup.size())
1013
0
            {
1014
0
                return mShadowContentTypeLookup[index];
1015
0
            }
1016
0
            break;
1017
0
        default:
1018
            // Simple iteration
1019
0
            for (unsigned short i = 0; i < mTextureUnitStates.size(); ++i)
1020
0
            {
1021
0
                if (mTextureUnitStates[i]->getContentType() == TextureUnitState::CONTENT_SHADOW)
1022
0
                {
1023
0
                    if (index == 0)
1024
0
                    {
1025
0
                        return i;
1026
0
                    }
1027
0
                    else
1028
0
                    {
1029
0
                        --index;
1030
0
                    }
1031
0
                }
1032
0
            }
1033
0
            break;
1034
0
        }
1035
1036
        // not found - return out of range
1037
0
        return static_cast<unsigned short>(mTextureUnitStates.size() + 1);
1038
1039
0
    }
1040
}