Coverage Report

Created: 2025-11-04 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreTextureUnitState.cpp
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
    (Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
#include "OgreStableHeaders.h"
29
30
#include "OgreTextureUnitState.h"
31
#include "OgreControllerManager.h"
32
#include "OgreTextureManager.h"
33
#include "OgreHardwarePixelBuffer.h"
34
35
namespace Ogre {
36
    // allow operation without hardware support
37
    static SamplerPtr DUMMY_SAMPLER = std::make_shared<Sampler>();
38
39
    Sampler::Sampler()
40
4
        : mBorderColour(ColourValue::Black)
41
4
        , mMaxAniso(1)
42
4
        , mMipmapBias(0)
43
4
        , mMinFilter(FO_LINEAR)
44
4
        , mMagFilter(FO_LINEAR)
45
4
        , mMipFilter(FO_POINT)
46
4
        , mCompareFunc(CMPF_GREATER_EQUAL)
47
4
        , mCompareEnabled(false)
48
4
        , mDirty(true)
49
4
    {
50
4
        setAddressingMode(TAM_WRAP);
51
4
    }
52
0
    Sampler::~Sampler() {}
53
    //-----------------------------------------------------------------------
54
    void Sampler::setAddressingMode(const UVWAddressingMode& uvw)
55
4
    {
56
4
        mAddressMode = uvw;
57
4
        mDirty = true;
58
4
    }
59
60
    //-----------------------------------------------------------------------
61
    void Sampler::setFiltering(TextureFilterOptions filterType)
62
0
    {
63
0
        switch (filterType)
64
0
        {
65
0
        case TFO_NONE:
66
0
            setFiltering(FO_POINT, FO_POINT, FO_NONE);
67
0
            break;
68
0
        case TFO_BILINEAR:
69
0
            setFiltering(FO_LINEAR, FO_LINEAR, FO_POINT);
70
0
            break;
71
0
        case TFO_TRILINEAR:
72
0
            setFiltering(FO_LINEAR, FO_LINEAR, FO_LINEAR);
73
0
            break;
74
0
        case TFO_ANISOTROPIC:
75
0
            setFiltering(FO_ANISOTROPIC, FO_ANISOTROPIC, FO_LINEAR);
76
0
            break;
77
0
        }
78
0
    }
79
    //-----------------------------------------------------------------------
80
    void Sampler::setFiltering(FilterType ft, FilterOptions fo)
81
0
    {
82
0
        switch (ft)
83
0
        {
84
0
        case FT_MIN:
85
0
            mMinFilter = fo;
86
0
            break;
87
0
        case FT_MAG:
88
0
            mMagFilter = fo;
89
0
            break;
90
0
        case FT_MIP:
91
0
            mMipFilter = fo;
92
0
            break;
93
0
        }
94
0
        mDirty = true;
95
0
    }
96
    //-----------------------------------------------------------------------
97
    void Sampler::setFiltering(FilterOptions minFilter, FilterOptions magFilter, FilterOptions mipFilter)
98
0
    {
99
0
        mMinFilter = minFilter;
100
0
        mMagFilter = magFilter;
101
0
        mMipFilter = mipFilter;
102
0
        mDirty = true;
103
0
    }
104
    //-----------------------------------------------------------------------
105
    FilterOptions Sampler::getFiltering(FilterType ft) const
106
0
    {
107
0
        switch (ft)
108
0
        {
109
0
        case FT_MIN:
110
0
            return mMinFilter;
111
0
        case FT_MAG:
112
0
            return mMagFilter;
113
0
        case FT_MIP:
114
0
            return mMipFilter;
115
0
        }
116
        // to keep compiler happy
117
0
        return mMinFilter;
118
0
    }
119
    //-----------------------------------------------------------------------
120
    TextureUnitState::TextureUnitState(Pass* parent)
121
0
        : mCurrentFrame(0)
122
0
        , mAnimDuration(0)
123
0
        , mUnorderedAccessMipLevel(-1)
124
0
        , mGamma(1)
125
0
        , mUMod(0)
126
0
        , mVMod(0)
127
0
        , mUScale(1)
128
0
        , mVScale(1)
129
0
        , mRotate(0)
130
0
        , mTexModMatrix(Matrix4::IDENTITY)
131
0
        , mContentType(CONTENT_NAMED)
132
0
        , mTextureLoadFailed(false)
133
0
        , mRecalcTexMatrix(false)
134
0
        , mTextureCoordSetIndex(0)
135
0
        , mFramePtrs(1)
136
0
        , mSampler(TextureManager::getSingletonPtr() ? TextureManager::getSingleton().getDefaultSampler() : DUMMY_SAMPLER)
137
0
        , mParent(parent)
138
0
        , mAnimController(0)
139
0
    {
140
0
        mColourBlendMode.blendType = LBT_COLOUR;
141
0
        mAlphaBlendMode.operation = LBX_MODULATE;
142
0
        mAlphaBlendMode.blendType = LBT_ALPHA;
143
0
        mAlphaBlendMode.source1 = LBS_TEXTURE;
144
0
        mAlphaBlendMode.source2 = LBS_CURRENT;
145
0
        setColourOperation(LBO_MODULATE);
146
147
0
        if( Pass::getHashFunction() == Pass::getBuiltinHashFunction( Pass::MIN_TEXTURE_CHANGE ) )
148
0
        {
149
0
            mParent->_dirtyHash();
150
0
        }
151
152
0
    }
153
154
    //-----------------------------------------------------------------------
155
    TextureUnitState::TextureUnitState(Pass* parent, const TextureUnitState& oth )
156
0
    {
157
0
        mParent = parent;
158
0
        mAnimController = 0;
159
0
        *this = oth;
160
0
    }
161
162
    //-----------------------------------------------------------------------
163
    TextureUnitState::TextureUnitState( Pass* parent, const String& texName, uint8 texCoordSet)
164
0
        : TextureUnitState(parent)
165
0
    {
166
0
        setTextureName(texName);
167
0
        setTextureCoordSet(texCoordSet);
168
0
    }
169
    //-----------------------------------------------------------------------
170
    TextureUnitState::~TextureUnitState()
171
0
    {
172
        // Unload ensure all controllers destroyed
173
0
        _unload();
174
0
    }
175
    //-----------------------------------------------------------------------
176
    TextureUnitState & TextureUnitState::operator = ( 
177
        const TextureUnitState &oth )
178
0
    {
179
0
        if (this == &oth)
180
0
            return *this;
181
182
0
        assert(mAnimController == 0);
183
0
        removeAllEffects();
184
185
        // copy basic members (int's, real's)
186
0
        memcpy( (uchar*)this, &oth, (const uchar *)(&oth.mFramePtrs) - (const uchar *)(&oth) );
187
        // copy complex members
188
0
        mFramePtrs = oth.mFramePtrs;
189
0
        mSampler = oth.mSampler;
190
0
        mName    = oth.mName;
191
0
        mEffects = oth.mEffects;
192
193
0
        mCompositorRefName = oth.mCompositorRefName;
194
0
        mCompositorRefTexName = oth.mCompositorRefTexName;
195
        // Can't sharing controllers with other TUS, reset to null to avoid potential bug.
196
0
        for (auto & e : mEffects)
197
0
        {
198
0
            e.second.controller = 0;
199
0
        }
200
201
        // Load immediately if Material loaded
202
0
        if (isLoaded())
203
0
        {
204
0
            _load();
205
0
        }
206
207
        // Tell parent to recalculate hash
208
0
        if( Pass::getHashFunction() == Pass::getBuiltinHashFunction( Pass::MIN_TEXTURE_CHANGE ) )
209
0
        {
210
0
            mParent->_dirtyHash();
211
0
        }
212
213
0
        return *this;
214
0
    }
215
    //-----------------------------------------------------------------------
216
    const String& TextureUnitState::getTextureName(void) const
217
0
    {
218
        // Return name of current frame
219
0
        if (mCurrentFrame < mFramePtrs.size() && mFramePtrs[mCurrentFrame])
220
0
            return mFramePtrs[mCurrentFrame]->getName();
221
0
        else
222
0
            return BLANKSTRING;
223
0
    }
224
    //-----------------------------------------------------------------------
225
    void TextureUnitState::setTextureName( const String& name)
226
0
    {
227
0
        if(TexturePtr tex = retrieveTexture(name))
228
0
            setTexture(tex);
229
0
    }
230
231
    void TextureUnitState::setTextureName( const String& name, TextureType texType)
232
0
    {
233
0
        TexturePtr tex = retrieveTexture(name);
234
235
0
        if(!tex)
236
0
            return;
237
238
0
        tex->setTextureType(texType);
239
0
        setTexture(tex);
240
0
    }
241
    //-----------------------------------------------------------------------
242
    void TextureUnitState::setTexture( const TexturePtr& texPtr)
243
0
    {
244
0
        if (!texPtr)
245
0
        {
246
0
            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
247
0
                "Texture Pointer is empty.",
248
0
                "TextureUnitState::setTexture");
249
0
        }
250
251
0
        setContentType(CONTENT_NAMED);
252
0
        mTextureLoadFailed = false;
253
        
254
0
        if (texPtr->getTextureType() == TEX_TYPE_EXTERNAL_OES)
255
0
        {
256
0
            setTextureAddressingMode( TAM_CLAMP );
257
0
            setTextureFiltering(FT_MIP, FO_NONE);
258
0
        }
259
260
0
        mFramePtrs.resize(1);
261
0
        mFramePtrs[0] = texPtr;
262
263
0
        mCurrentFrame = 0;
264
265
        // Load immediately ?
266
0
        if (isLoaded())
267
0
        {
268
0
            _load(); // reload
269
0
        }
270
        // Tell parent to recalculate hash
271
0
        if( Pass::getHashFunction() == Pass::getBuiltinHashFunction( Pass::MIN_TEXTURE_CHANGE ) )
272
0
        {
273
0
            mParent->_dirtyHash();
274
0
        }
275
0
    }
276
    //-----------------------------------------------------------------------
277
    void TextureUnitState::setContentType(TextureUnitState::ContentType ct)
278
0
    {
279
0
        mContentType = ct;
280
0
    }
281
    //-----------------------------------------------------------------------
282
    TextureUnitState::ContentType TextureUnitState::getContentType(void) const
283
0
    {
284
0
        return mContentType;
285
0
    }
286
    //-----------------------------------------------------------------------
287
    TextureType TextureUnitState::getTextureType(void) const
288
0
    {
289
0
        return !mFramePtrs[0] ? TEX_TYPE_2D : mFramePtrs[0]->getTextureType();
290
0
    }
291
292
    //-----------------------------------------------------------------------
293
    void TextureUnitState::setFrameTextureName(const String& name, unsigned int frameNumber)
294
0
    {
295
0
        mTextureLoadFailed = false;
296
0
        OgreAssert(frameNumber < mFramePtrs.size(), "out of range");
297
298
0
        mFramePtrs[frameNumber] = retrieveTexture(name);
299
300
0
        if (isLoaded())
301
0
        {
302
0
            _load(); // reload
303
0
        }
304
        // Tell parent to recalculate hash
305
0
        if( Pass::getHashFunction() == Pass::getBuiltinHashFunction( Pass::MIN_TEXTURE_CHANGE ) )
306
0
        {
307
0
            mParent->_dirtyHash();
308
0
        }
309
0
    }
310
311
    //-----------------------------------------------------------------------
312
    void TextureUnitState::addFrameTextureName(const String& name)
313
0
    {
314
0
        setContentType(CONTENT_NAMED);
315
0
        mTextureLoadFailed = false;
316
317
0
        mFramePtrs.push_back(retrieveTexture(name));
318
319
        // Load immediately if Material loaded
320
0
        if (isLoaded())
321
0
        {
322
0
            _load();
323
0
        }
324
        // Tell parent to recalculate hash
325
0
        if( Pass::getHashFunction() == Pass::getBuiltinHashFunction( Pass::MIN_TEXTURE_CHANGE ) )
326
0
        {
327
0
            mParent->_dirtyHash();
328
0
        }
329
0
    }
330
331
    //-----------------------------------------------------------------------
332
    void TextureUnitState::deleteFrameTextureName(const size_t frameNumber)
333
0
    {
334
0
        mTextureLoadFailed = false;
335
0
        OgreAssert(frameNumber < mFramePtrs.size(), "out of range");
336
0
        mFramePtrs.erase(mFramePtrs.begin() + frameNumber);
337
338
0
        if (isLoaded())
339
0
        {
340
0
            _load();
341
0
        }
342
        // Tell parent to recalculate hash
343
0
        if( Pass::getHashFunction() == Pass::getBuiltinHashFunction( Pass::MIN_TEXTURE_CHANGE ) )
344
0
        {
345
0
            mParent->_dirtyHash();
346
0
        }
347
0
    }
348
349
    void TextureUnitState::setCubicTextureName(const String* const names, bool forUVW)
350
0
    {
351
0
        setLayerArrayNames(TEX_TYPE_CUBE_MAP, std::vector<String>(names, names + 6));
352
0
    }
353
354
    //-----------------------------------------------------------------------
355
    void TextureUnitState::setAnimatedTextureName( const String& name, size_t numFrames, Real duration)
356
0
    {
357
0
        String baseName, ext;
358
0
        StringUtil::splitBaseFilename(name, baseName, ext);
359
360
0
        std::vector<String> names(numFrames);
361
0
        for (uint32 i = 0; i < names.size(); ++i)
362
0
        {
363
0
            names[i] = StringUtil::format("%s_%u.%s", baseName.c_str(), i, ext.c_str());
364
0
        }
365
366
0
        setAnimatedTextureName(names, duration);
367
0
    }
368
    //-----------------------------------------------------------------------
369
    void TextureUnitState::setAnimatedTextureName(const String* const names, size_t numFrames, Real duration)
370
0
    {
371
0
        setContentType(CONTENT_NAMED);
372
0
        mTextureLoadFailed = false;
373
374
        // resize pointers, but don't populate until needed
375
0
        mFramePtrs.resize(numFrames);
376
0
        mAnimDuration = duration;
377
0
        mCurrentFrame = 0;
378
379
0
        for (unsigned int i = 0; i < mFramePtrs.size(); ++i)
380
0
        {
381
0
            mFramePtrs[i] = retrieveTexture(names[i]);
382
0
        }
383
384
        // Load immediately if Material loaded
385
0
        if (isLoaded())
386
0
        {
387
0
            _load();
388
0
        }
389
        // Tell parent to recalculate hash
390
0
        if( Pass::getHashFunction() == Pass::getBuiltinHashFunction( Pass::MIN_TEXTURE_CHANGE ) )
391
0
        {
392
0
            mParent->_dirtyHash();
393
0
        }
394
0
    }
395
    void TextureUnitState::setLayerArrayNames(TextureType type, const std::vector<String>& names)
396
0
    {
397
0
        OgreAssert(!names.empty(), "array layers empty");
398
399
0
        const char* typeName;
400
0
        switch(type)
401
0
        {
402
0
        case TEX_TYPE_CUBE_MAP:
403
0
            typeName = "Cube";
404
0
            break;
405
0
        case TEX_TYPE_2D_ARRAY:
406
0
            typeName = "Array";
407
0
            break;
408
0
        case TEX_TYPE_3D:
409
0
            typeName = "Volume";
410
0
            break;
411
0
        default:
412
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "arrays not possible for this texture type");
413
0
            return;
414
0
        }
415
416
        // use hash to auto-name the texture
417
0
        uint32 hash = 0;
418
0
        for(const String& name : names)
419
0
            hash = FastHash(name.data(), name.size(), hash);
420
421
0
        auto tex = retrieveTexture(StringUtil::format("%sTex_%x", typeName, hash));
422
0
        tex->setTextureType(type);
423
0
        tex->setLayerNames(names);
424
0
        setTexture(tex);
425
0
    }
426
427
    //-----------------------------------------------------------------------
428
    std::pair<uint32, uint32> TextureUnitState::getTextureDimensions(unsigned int frame) const
429
0
    {
430
        
431
0
        TexturePtr tex = _getTexturePtr(frame);
432
0
        if (!tex)
433
0
            OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, "Could not find texture " + StringConverter::toString(frame),
434
0
            "TextureUnitState::getTextureDimensions" );
435
436
0
        return {tex->getWidth(), tex->getHeight()};
437
0
    }
438
    //-----------------------------------------------------------------------
439
    void TextureUnitState::setCurrentFrame(unsigned int frameNumber)
440
0
    {
441
0
        OgreAssert(frameNumber < mFramePtrs.size(), "out of range");
442
0
        mCurrentFrame = frameNumber;
443
        // this will affect the hash
444
0
        if( Pass::getHashFunction() == Pass::getBuiltinHashFunction( Pass::MIN_TEXTURE_CHANGE ) )
445
0
        {
446
0
            mParent->_dirtyHash();
447
0
        }
448
0
    }
449
    //-----------------------------------------------------------------------
450
    unsigned int TextureUnitState::getCurrentFrame(void) const
451
0
    {
452
0
        return mCurrentFrame;
453
0
    }
454
    //-----------------------------------------------------------------------
455
    unsigned int TextureUnitState::getNumFrames(void) const
456
0
    {
457
0
        return (unsigned int)mFramePtrs.size();
458
0
    }
459
    //-----------------------------------------------------------------------
460
    const String& TextureUnitState::getFrameTextureName(unsigned int frameNumber) const
461
0
    {
462
0
        OgreAssert(frameNumber < mFramePtrs.size(), "out of range");
463
464
0
        return mFramePtrs[0] ? mFramePtrs[frameNumber]->getName() : BLANKSTRING;
465
0
    }
466
    //-----------------------------------------------------------------------
467
    void TextureUnitState::setDesiredFormat(PixelFormat desiredFormat)
468
0
    {
469
0
        OgreAssert(mFramePtrs[0], "frame must not be blank");
470
0
        for(auto& frame : mFramePtrs)
471
0
            frame->setFormat(desiredFormat);
472
0
    }
473
    //-----------------------------------------------------------------------
474
    PixelFormat TextureUnitState::getDesiredFormat(void) const
475
0
    {
476
0
        return !mFramePtrs[0] ? PF_UNKNOWN : mFramePtrs[0]->getDesiredFormat();
477
0
    }
478
    //-----------------------------------------------------------------------
479
    void TextureUnitState::setNumMipmaps(int numMipmaps)
480
0
    {
481
0
        OgreAssert(mFramePtrs[0], "frame must not be blank");
482
0
        for (auto& frame : mFramePtrs)
483
0
            frame->setNumMipmaps(numMipmaps == MIP_DEFAULT
484
0
                                     ? TextureManager::getSingleton().getDefaultNumMipmaps()
485
0
                                     : numMipmaps);
486
0
    }
487
    //-----------------------------------------------------------------------
488
    int TextureUnitState::getNumMipmaps(void) const
489
0
    {
490
0
        return !mFramePtrs[0] ? int(MIP_DEFAULT) : mFramePtrs[0]->getNumMipmaps();
491
0
    }
492
    //-----------------------------------------------------------------------
493
    void TextureUnitState::setIsAlpha(bool isAlpha)
494
0
    {
495
0
        OgreAssert(mFramePtrs[0], "frame must not be blank");
496
0
        OGRE_IGNORE_DEPRECATED_BEGIN
497
0
        for(auto& frame : mFramePtrs)
498
0
            frame->setTreatLuminanceAsAlpha(isAlpha);
499
0
        OGRE_IGNORE_DEPRECATED_END
500
0
    }
501
    float TextureUnitState::getGamma() const
502
0
    {
503
0
        return !mFramePtrs[0] ? 1.0f : mFramePtrs[0]->getGamma();
504
0
    }
505
    void TextureUnitState::setGamma(float gamma)
506
0
    {
507
0
        OgreAssert(mFramePtrs[0], "frame must not be blank");
508
0
        for(auto& frame : mFramePtrs)
509
0
            frame->setGamma(gamma);
510
0
    }
511
    //-----------------------------------------------------------------------
512
    void TextureUnitState::setHardwareGammaEnabled(bool g)
513
0
    {
514
0
        OgreAssert(mFramePtrs[0], "frame must not be blank");
515
0
        for(auto& frame : mFramePtrs)
516
0
            frame->setHardwareGammaEnabled(g);
517
0
    }
518
    //-----------------------------------------------------------------------
519
    bool TextureUnitState::isHardwareGammaEnabled() const
520
0
    {
521
0
        return mFramePtrs[0] && mFramePtrs[0]->isHardwareGammaEnabled();
522
0
    }
523
    //-----------------------------------------------------------------------
524
    uint8 TextureUnitState::getTextureCoordSet(void) const
525
0
    {
526
0
        return mTextureCoordSetIndex;
527
0
    }
528
    //-----------------------------------------------------------------------
529
    void TextureUnitState::setTextureCoordSet(uint8 set)
530
0
    {
531
0
        mTextureCoordSetIndex = set;
532
0
    }
533
    //-----------------------------------------------------------------------
534
    void TextureUnitState::setColourOperationEx(LayerBlendOperationEx op,
535
        LayerBlendSource source1,
536
        LayerBlendSource source2,
537
        const ColourValue& arg1,
538
        const ColourValue& arg2,
539
        Real manualBlend)
540
0
    {
541
0
        mColourBlendMode.operation = op;
542
0
        mColourBlendMode.source1 = source1;
543
0
        mColourBlendMode.source2 = source2;
544
0
        mColourBlendMode.colourArg1 = arg1;
545
0
        mColourBlendMode.colourArg2 = arg2;
546
0
        mColourBlendMode.factor = manualBlend;
547
0
    }
548
    //-----------------------------------------------------------------------
549
    void TextureUnitState::setColourOperation(LayerBlendOperation op)
550
0
    {
551
        // Set up the multitexture and multipass blending operations
552
0
        switch (op)
553
0
        {
554
0
        case LBO_REPLACE:
555
0
            setColourOperationEx(LBX_SOURCE1, LBS_TEXTURE, LBS_CURRENT);
556
0
            setColourOpMultipassFallback(SBF_ONE, SBF_ZERO);
557
0
            break;
558
0
        case LBO_ADD:
559
0
            setColourOperationEx(LBX_ADD, LBS_TEXTURE, LBS_CURRENT);
560
0
            setColourOpMultipassFallback(SBF_ONE, SBF_ONE);
561
0
            break;
562
0
        case LBO_MODULATE:
563
0
            setColourOperationEx(LBX_MODULATE, LBS_TEXTURE, LBS_CURRENT);
564
0
            setColourOpMultipassFallback(SBF_DEST_COLOUR, SBF_ZERO);
565
0
            break;
566
0
        case LBO_ALPHA_BLEND:
567
0
            setColourOperationEx(LBX_BLEND_TEXTURE_ALPHA, LBS_TEXTURE, LBS_CURRENT);
568
0
            setColourOpMultipassFallback(SBF_SOURCE_ALPHA, SBF_ONE_MINUS_SOURCE_ALPHA);
569
0
            break;
570
0
        }
571
572
573
0
    }
574
    //-----------------------------------------------------------------------
575
    void TextureUnitState::setColourOpMultipassFallback(SceneBlendFactor sourceFactor, SceneBlendFactor destFactor)
576
0
    {
577
0
        mColourBlendFallbackSrc = sourceFactor;
578
0
        mColourBlendFallbackDest = destFactor;
579
0
    }
580
    //-----------------------------------------------------------------------
581
    void TextureUnitState::setAlphaOperation(LayerBlendOperationEx op,
582
        LayerBlendSource source1,
583
        LayerBlendSource source2,
584
        Real arg1,
585
        Real arg2,
586
        Real manualBlend)
587
0
    {
588
0
        mAlphaBlendMode.operation = op;
589
0
        mAlphaBlendMode.source1 = source1;
590
0
        mAlphaBlendMode.source2 = source2;
591
0
        mAlphaBlendMode.alphaArg1 = arg1;
592
0
        mAlphaBlendMode.alphaArg2 = arg2;
593
0
        mAlphaBlendMode.factor = manualBlend;
594
0
    }
595
    //-----------------------------------------------------------------------
596
    void TextureUnitState::addEffect(TextureEffect effect)
597
0
    {
598
        // Ensure controller pointer is null
599
0
        effect.controller = 0;
600
601
0
        if (effect.type != ET_TRANSFORM)
602
0
        {
603
            // Replace - must be unique
604
            // Search for existing effect of this type
605
0
            EffectMap::iterator i = mEffects.find(effect.type);
606
0
            if (i != mEffects.end())
607
0
            {
608
                // Destroy old effect controller if exist
609
0
                if (i->second.controller)
610
0
                {
611
0
                    ControllerManager::getSingleton().destroyController(i->second.controller);
612
0
                }
613
614
0
                mEffects.erase(i);
615
0
            }
616
0
        }
617
618
0
        if (isLoaded())
619
0
        {
620
            // Create controller
621
0
            createEffectController(effect);
622
0
        }
623
624
        // Record new effect
625
0
        mEffects.emplace(effect.type, effect);
626
627
0
    }
628
    //-----------------------------------------------------------------------
629
    void TextureUnitState::removeAllEffects(void)
630
0
    {
631
        // Iterate over effects to remove controllers
632
0
        EffectMap::iterator i, iend;
633
0
        iend = mEffects.end();
634
0
        for (i = mEffects.begin(); i != iend; ++i)
635
0
        {
636
0
            if (i->second.controller)
637
0
            {
638
0
                ControllerManager::getSingleton().destroyController(i->second.controller);
639
0
            }
640
0
        }
641
642
0
        mEffects.clear();
643
0
    }
644
645
    //-----------------------------------------------------------------------
646
    bool TextureUnitState::isBlank(void) const
647
0
    {
648
0
        return !mFramePtrs[0] || mTextureLoadFailed;
649
0
    }
650
651
    //-----------------------------------------------------------------------
652
    SceneBlendFactor TextureUnitState::getColourBlendFallbackSrc(void) const
653
0
    {
654
0
        return mColourBlendFallbackSrc;
655
0
    }
656
    //-----------------------------------------------------------------------
657
    SceneBlendFactor TextureUnitState::getColourBlendFallbackDest(void) const
658
0
    {
659
0
        return mColourBlendFallbackDest;
660
0
    }
661
    //-----------------------------------------------------------------------
662
    const LayerBlendModeEx& TextureUnitState::getColourBlendMode(void) const
663
0
    {
664
0
        return mColourBlendMode;
665
0
    }
666
    //-----------------------------------------------------------------------
667
    const LayerBlendModeEx& TextureUnitState::getAlphaBlendMode(void) const
668
0
    {
669
0
        return mAlphaBlendMode;
670
0
    }
671
    //-----------------------------------------------------------------------
672
    void TextureUnitState::setEnvironmentMap(bool enable, int envMapType)
673
0
    {
674
0
        if (enable)
675
0
        {
676
0
            TextureEffect eff = {ET_ENVIRONMENT_MAP};
677
0
            eff.subtype = envMapType;
678
0
            addEffect(eff);
679
0
        }
680
0
        else
681
0
        {
682
0
            removeEffect(ET_ENVIRONMENT_MAP);
683
0
        }
684
0
    }
685
    //-----------------------------------------------------------------------
686
    void TextureUnitState::removeEffect(TextureEffectType type)
687
0
    {
688
        // Get range of items matching this effect
689
0
        std::pair< EffectMap::iterator, EffectMap::iterator > remPair = 
690
0
            mEffects.equal_range( type );
691
        // Remove controllers
692
0
        for (EffectMap::iterator i = remPair.first; i != remPair.second; ++i)
693
0
        {
694
0
            if (i->second.controller)
695
0
            {
696
0
                ControllerManager::getSingleton().destroyController(i->second.controller);
697
0
            }
698
0
        }
699
        // Erase         
700
0
        mEffects.erase( remPair.first, remPair.second );
701
0
    }
702
    //-----------------------------------------------------------------------
703
    void TextureUnitState::setBlank(void)
704
0
    {
705
0
        mFramePtrs.clear();
706
0
        mFramePtrs.push_back(TexturePtr()); // insert nullptr to show warning tex
707
0
    }
708
    //-----------------------------------------------------------------------
709
    void TextureUnitState::setTextureTransform(const Matrix4& xform)
710
0
    {
711
0
        mTexModMatrix = xform;
712
0
        mRecalcTexMatrix = false;
713
0
    }
714
    //-----------------------------------------------------------------------
715
    void TextureUnitState::setTextureScroll(float u, float v)
716
0
    {
717
0
        mUMod = u;
718
0
        mVMod = v;
719
0
        mRecalcTexMatrix = true;
720
0
    }
721
    //-----------------------------------------------------------------------
722
    void TextureUnitState::setTextureScale(float uScale, float vScale)
723
0
    {
724
0
        mUScale = uScale;
725
0
        mVScale = vScale;
726
0
        mRecalcTexMatrix = true;
727
0
    }
728
    //-----------------------------------------------------------------------
729
    void TextureUnitState::setTextureRotate(const Radian& angle)
730
0
    {
731
0
        mRotate = angle;
732
0
        mRecalcTexMatrix = true;
733
0
    }
734
    //-----------------------------------------------------------------------
735
    const Matrix4& TextureUnitState::getTextureTransform() const
736
0
    {
737
0
        if (mRecalcTexMatrix)
738
0
            recalcTextureMatrix();
739
0
        return mTexModMatrix;
740
741
0
    }
742
    //-----------------------------------------------------------------------
743
    void TextureUnitState::recalcTextureMatrix() const
744
0
    {
745
        // Assumption: 2D texture coords
746
        // that would make this Affine2(Matrix3), but we lack such a class
747
        // Matrix3 is horribly unoptimized ATM
748
0
        Affine3 xform = Affine3::IDENTITY;
749
750
0
        if (mUScale != 1 || mVScale != 1)
751
0
        {
752
            // Offset to center of texture
753
0
            xform[0][0] = 1/mUScale;
754
0
            xform[1][1] = 1/mVScale;
755
            // Skip matrix concat since first matrix update
756
0
            xform[0][3] = (-0.5f * xform[0][0]) + 0.5f;
757
0
            xform[1][3] = (-0.5f * xform[1][1]) + 0.5f;
758
0
        }
759
760
0
        if (mUMod || mVMod)
761
0
        {
762
0
            xform = Affine3::getTrans(mUMod, mVMod, 0) * xform;
763
0
        }
764
765
0
        if (mRotate != Radian(0))
766
0
        {
767
0
            Affine3 rot = Affine3::IDENTITY;
768
0
            Radian theta ( mRotate );
769
0
            Real cosTheta = Math::Cos(theta);
770
0
            Real sinTheta = Math::Sin(theta);
771
772
0
            rot[0][0] = cosTheta;
773
0
            rot[0][1] = -sinTheta;
774
0
            rot[1][0] = sinTheta;
775
0
            rot[1][1] = cosTheta;
776
            // Offset center of rotation to center of texture
777
0
            rot[0][3] = 0.5f + ( (-0.5f * cosTheta) - (-0.5f * sinTheta) );
778
0
            rot[1][3] = 0.5f + ( (-0.5f * sinTheta) + (-0.5f * cosTheta) );
779
780
0
            xform = rot * xform;
781
0
        }
782
783
0
        mTexModMatrix = xform;
784
0
        mRecalcTexMatrix = false;
785
786
0
    }
787
    //-----------------------------------------------------------------------
788
    void TextureUnitState::setTextureUScroll(float value)
789
0
    {
790
0
        mUMod = value;
791
0
        mRecalcTexMatrix = true;
792
0
    }
793
    //-----------------------------------------------------------------------
794
    void TextureUnitState::setTextureVScroll(float value)
795
0
    {
796
0
        mVMod = value;
797
0
        mRecalcTexMatrix = true;
798
0
    }
799
    //-----------------------------------------------------------------------
800
    void TextureUnitState::setTextureUScale(float value)
801
0
    {
802
0
        mUScale = value;
803
0
        mRecalcTexMatrix = true;
804
0
    }
805
    //-----------------------------------------------------------------------
806
    void TextureUnitState::setTextureVScale(float value)
807
0
    {
808
0
        mVScale = value;
809
0
        mRecalcTexMatrix = true;
810
0
    }
811
    //-----------------------------------------------------------------------
812
    void TextureUnitState::setScrollAnimation(float uSpeed, float vSpeed)
813
0
    {
814
        // Remove existing effects
815
0
        removeEffect(ET_UVSCROLL);
816
0
        removeEffect(ET_USCROLL);
817
0
        removeEffect(ET_VSCROLL);
818
819
        // don't create an effect if the speeds are both 0
820
0
        if (uSpeed == 0.0f && vSpeed == 0.0f)
821
0
        {
822
0
            return;
823
0
        }
824
825
        // Create new effect
826
0
        if (uSpeed == vSpeed)
827
0
        {
828
0
            addEffect({ET_UVSCROLL, uSpeed});
829
0
        }
830
0
        else
831
0
        {
832
0
            if (uSpeed)
833
0
            {
834
0
                addEffect({ET_USCROLL, uSpeed});
835
0
            }
836
0
            if (vSpeed)
837
0
            {
838
0
                addEffect({ET_VSCROLL, vSpeed});
839
0
            }
840
0
        }
841
0
    }
842
    //-----------------------------------------------------------------------
843
    void TextureUnitState::setRotateAnimation(float speed)
844
0
    {
845
        // Remove existing effect
846
0
        removeEffect(ET_ROTATE);
847
        // don't create an effect if the speed is 0
848
0
        if(speed == 0.0f) 
849
0
        {
850
0
          return;
851
0
        }
852
        // Create new effect
853
0
        addEffect({ET_ROTATE, speed});
854
0
    }
855
    //-----------------------------------------------------------------------
856
    void TextureUnitState::setTransformAnimation(TextureTransformType ttype,
857
        WaveformType waveType, float base, float frequency, float phase, float amplitude)
858
0
    {
859
        // Remove existing effect
860
        // note, only remove for subtype, not entire ET_TRANSFORM
861
        // otherwise we won't be able to combine subtypes
862
        // Get range of items matching this effect
863
0
        for (EffectMap::iterator i = mEffects.begin(); i != mEffects.end(); ++i)
864
0
        {
865
0
            if (i->second.type == ET_TRANSFORM && i->second.subtype == ttype)
866
0
            {
867
0
                if (i->second.controller)
868
0
                {
869
0
                    ControllerManager::getSingleton().destroyController(i->second.controller);
870
0
                }
871
0
                mEffects.erase(i);
872
873
                // should only be one, so jump out
874
0
                break;
875
0
            }
876
0
        }
877
878
        // don't create an effect if the given values are all 0
879
0
        if(base == 0.0f && phase == 0.0f && frequency == 0.0f && amplitude == 0.0f)
880
0
        {
881
0
            return;
882
0
        }
883
        // Create new effect
884
0
        TextureEffect eff = {ET_TRANSFORM};
885
0
        eff.subtype = ttype;
886
0
        eff.waveType = waveType;
887
0
        eff.base = base;
888
0
        eff.frequency = frequency;
889
0
        eff.phase = phase;
890
0
        eff.amplitude = amplitude;
891
0
        addEffect(eff);
892
0
    }
893
    //-----------------------------------------------------------------------
894
    void TextureUnitState::_prepare(void)
895
0
    {
896
        // Unload first
897
        //_unload();
898
899
        // Load textures
900
0
        for (unsigned int i = 0; i < mFramePtrs.size(); ++i)
901
0
        {
902
0
            ensurePrepared(i);
903
0
        }
904
0
    }
905
    //-----------------------------------------------------------------------
906
    void TextureUnitState::_load(void)
907
0
    {
908
909
        // Load textures
910
0
        for (unsigned int i = 0; i < mFramePtrs.size(); ++i)
911
0
        {
912
0
            ensureLoaded(i);
913
0
        }
914
        // Animation controller
915
0
        if (mAnimDuration != 0)
916
0
        {
917
0
            createAnimController();
918
0
        }
919
        // Effect controllers
920
0
        for (auto & e : mEffects)
921
0
        {
922
0
            createEffectController(e.second);
923
0
        }
924
925
0
    }
926
    //-----------------------------------------------------------------------
927
    const TexturePtr& TextureUnitState::_getTexturePtr(void) const
928
0
    {
929
0
        return _getTexturePtr(mCurrentFrame);
930
0
    }
931
    //-----------------------------------------------------------------------
932
    const TexturePtr& TextureUnitState::_getTexturePtr(size_t frame) const
933
0
    {
934
0
        if (frame < mFramePtrs.size())
935
0
        {
936
0
            if (mContentType == CONTENT_NAMED)
937
0
            {
938
0
                ensureLoaded(frame);
939
0
            }
940
941
0
            return mFramePtrs[frame];
942
0
        }
943
        
944
        // Silent fail with empty texture for internal method
945
0
        static TexturePtr nullTexPtr;
946
0
        return nullTexPtr;
947
0
    }
948
    //-----------------------------------------------------------------------
949
    void TextureUnitState::_setTexturePtr(const TexturePtr& texptr)
950
0
    {
951
0
        _setTexturePtr(texptr, mCurrentFrame);
952
0
    }
953
    //-----------------------------------------------------------------------
954
    void TextureUnitState::_setTexturePtr(const TexturePtr& texptr, size_t frame)
955
0
    {
956
0
        assert(frame < mFramePtrs.size());
957
0
        mFramePtrs[frame] = texptr;
958
0
    }
959
    //-----------------------------------------------------------------------
960
0
    TexturePtr TextureUnitState::retrieveTexture(const String& name) {
961
0
        TextureManager::ResourceCreateOrRetrieveResult res;
962
0
        res = TextureManager::getSingleton().createOrRetrieve(name, mParent->getResourceGroup());
963
0
        return static_pointer_cast<Texture>(res.first);
964
0
    }
965
    //-----------------------------------------------------------------------
966
    bool TextureUnitState::checkTexCalcSettings(const TexturePtr& tex) const
967
0
    {
968
0
        if(mContentType != TextureUnitState::CONTENT_NAMED)
969
0
            return true; // can only check normal textures
970
971
0
        String err;
972
0
        auto texCalc = _deriveTexCoordCalcMethod();
973
0
        if ((texCalc == TEXCALC_ENVIRONMENT_MAP_PLANAR || texCalc == TEXCALC_ENVIRONMENT_MAP) &&
974
0
            getTextureType() != TEX_TYPE_2D)
975
0
        {
976
0
            err = "env_map setting requires a 2d texture";
977
0
        }
978
0
        else if ((texCalc == TEXCALC_ENVIRONMENT_MAP_NORMAL || texCalc == TEXCALC_ENVIRONMENT_MAP_REFLECTION) &&
979
0
                 getTextureType() != TEX_TYPE_CUBE_MAP)
980
0
        {
981
0
            err = "env_map setting requires a cubic texture";
982
0
        }
983
0
        if(err.empty())
984
0
            return true;
985
986
0
        String msg = err+", but '"+tex->getName()+"' is not. Texture layer will be blank";
987
0
        LogManager::getSingleton().logError(msg);
988
0
        mTextureLoadFailed = true;
989
0
        return false;
990
0
    }
991
    void TextureUnitState::ensurePrepared(size_t frame) const
992
0
    {
993
0
        const TexturePtr& tex = mFramePtrs[frame];
994
0
        if (!tex || mTextureLoadFailed || !checkTexCalcSettings(tex))
995
0
            return;
996
997
0
        tex->setGamma(mGamma);
998
999
0
        try {
1000
0
            tex->prepare();
1001
0
        }
1002
0
        catch (Exception& e)
1003
0
        {
1004
0
            String msg = "preparing texture '" + tex->getName() +
1005
0
                         "'. Texture layer will be blank: " + e.getDescription();
1006
0
            LogManager::getSingleton().logError(msg);
1007
0
            mTextureLoadFailed = true;
1008
0
        }
1009
0
    }
1010
    //-----------------------------------------------------------------------
1011
    void TextureUnitState::ensureLoaded(size_t frame) const
1012
0
    {
1013
0
        const TexturePtr& tex = mFramePtrs[frame];
1014
0
        if (!tex || mTextureLoadFailed || !checkTexCalcSettings(tex))
1015
0
            return;
1016
1017
0
        tex->setGamma(mGamma);
1018
1019
0
        if(mUnorderedAccessMipLevel > -1)
1020
0
            tex->setUsage(HBU_GPU_ONLY | TU_UNORDERED_ACCESS);
1021
1022
0
        try {
1023
0
            tex->load();
1024
0
        }
1025
0
        catch (Exception& e)
1026
0
        {
1027
0
            String msg = "loading texture '" + tex->getName() +
1028
0
                         "'. Texture layer will be blank: " + e.getDescription();
1029
0
            LogManager::getSingleton().logError(msg);
1030
0
            mTextureLoadFailed = true;
1031
0
        }
1032
0
    }
1033
    //-----------------------------------------------------------------------
1034
    void TextureUnitState::createAnimController(void)
1035
0
    {
1036
0
        if (mAnimController)
1037
0
        {
1038
0
            ControllerManager::getSingleton().destroyController(mAnimController);
1039
0
            mAnimController = 0;
1040
0
        }
1041
0
        mAnimController = ControllerManager::getSingleton().createTextureAnimator(this, mAnimDuration);
1042
1043
0
    }
1044
    //-----------------------------------------------------------------------
1045
    void TextureUnitState::createEffectController(TextureEffect& effect)
1046
0
    {
1047
0
        if (effect.controller)
1048
0
        {
1049
0
            ControllerManager::getSingleton().destroyController(effect.controller);
1050
0
            effect.controller = 0;
1051
0
        }
1052
0
        ControllerManager& cMgr = ControllerManager::getSingleton();
1053
0
        switch (effect.type)
1054
0
        {
1055
0
        case ET_UVSCROLL:
1056
0
            effect.controller = cMgr.createTextureUVScroller(this, effect.arg1);
1057
0
            break;
1058
0
        case ET_USCROLL:
1059
0
            effect.controller = cMgr.createTextureUScroller(this, effect.arg1);
1060
0
            break;
1061
0
        case ET_VSCROLL:
1062
0
            effect.controller = cMgr.createTextureVScroller(this, effect.arg1);
1063
0
            break;
1064
0
        case ET_ROTATE:
1065
0
            effect.controller = cMgr.createTextureRotater(this, effect.arg1);
1066
0
            break;
1067
0
        case ET_TRANSFORM:
1068
0
            effect.controller = cMgr.createTextureWaveTransformer(this, (TextureUnitState::TextureTransformType)effect.subtype, effect.waveType, effect.base,
1069
0
                effect.frequency, effect.phase, effect.amplitude);
1070
0
            break;
1071
0
        case ET_PROJECTIVE_TEXTURE:
1072
0
        case ET_ENVIRONMENT_MAP:
1073
0
            break;
1074
0
        }
1075
0
    }
1076
    //-----------------------------------------------------------------------
1077
    float TextureUnitState::getTextureUScroll(void) const
1078
0
    {
1079
0
        return mUMod;
1080
0
    }
1081
1082
    //-----------------------------------------------------------------------
1083
    float TextureUnitState::getTextureVScroll(void) const
1084
0
    {
1085
0
        return mVMod;
1086
0
    }
1087
1088
    //-----------------------------------------------------------------------
1089
    float TextureUnitState::getTextureUScale(void) const
1090
0
    {
1091
0
        return mUScale;
1092
0
    }
1093
1094
    //-----------------------------------------------------------------------
1095
    float TextureUnitState::getTextureVScale(void) const
1096
0
    {
1097
0
        return mVScale;
1098
0
    }
1099
1100
    //-----------------------------------------------------------------------
1101
    const Radian& TextureUnitState::getTextureRotate(void) const
1102
0
    {
1103
0
        return mRotate;
1104
0
    }
1105
    
1106
    //-----------------------------------------------------------------------
1107
    Real TextureUnitState::getAnimationDuration(void) const
1108
0
    {
1109
0
        return mAnimDuration;
1110
0
    }
1111
1112
    //-----------------------------------------------------------------------
1113
    const TextureUnitState::EffectMap& TextureUnitState::getEffects(void) const
1114
0
    {
1115
0
        return mEffects;
1116
0
    }
1117
    //-----------------------------------------------------------------------
1118
    void TextureUnitState::_unprepare(void)
1119
0
    {
1120
        // don't unload textures. may be used elsewhere
1121
0
    }
1122
    //-----------------------------------------------------------------------
1123
    void TextureUnitState::_unload(void)
1124
0
    {
1125
        // Destroy animation controller
1126
0
        if (mAnimController)
1127
0
        {
1128
0
            ControllerManager::getSingleton().destroyController(mAnimController);
1129
0
            mAnimController = 0;
1130
0
        }
1131
1132
        // Destroy effect controllers
1133
0
        for (auto & e : mEffects)
1134
0
        {
1135
0
            if (e.second.controller)
1136
0
            {
1137
0
                ControllerManager::getSingleton().destroyController(e.second.controller);
1138
0
                e.second.controller = 0;
1139
0
            }
1140
0
        }
1141
1142
        // don't unload named textures. may be used elsewhere
1143
        // drop references on managed textures, however
1144
0
        if(mContentType != CONTENT_NAMED)
1145
0
            mFramePtrs[0].reset();
1146
0
    }
1147
    //-----------------------------------------------------------------------------
1148
    bool TextureUnitState::isLoaded(void) const
1149
0
    {
1150
0
        return mParent->isLoaded();
1151
0
    }
1152
    //-----------------------------------------------------------------------
1153
    void TextureUnitState::_notifyNeedsRecompile(void)
1154
0
    {
1155
0
        mParent->_notifyNeedsRecompile();
1156
0
    }
1157
    //-----------------------------------------------------------------------
1158
    void TextureUnitState::setProjectiveTexturing(bool enable, 
1159
        const Frustum* projectionSettings)
1160
0
    {
1161
0
        if (enable)
1162
0
        {
1163
0
            TextureEffect eff = {ET_PROJECTIVE_TEXTURE};
1164
0
            eff.frustum = projectionSettings;
1165
0
            addEffect(eff);
1166
0
        }
1167
0
        else
1168
0
        {
1169
0
            removeEffect(ET_PROJECTIVE_TEXTURE);
1170
0
        }
1171
1172
0
    }
1173
    const Frustum* TextureUnitState::getProjectiveTexturingFrustum() const
1174
0
    {
1175
0
        EffectMap::const_iterator i = mEffects.find(ET_PROJECTIVE_TEXTURE);
1176
0
        if (i != mEffects.end())
1177
0
        {
1178
0
            return i->second.frustum;
1179
0
        }
1180
1181
0
        return 0;
1182
0
    }
1183
    //-----------------------------------------------------------------------
1184
    void TextureUnitState::setName(const String& name)
1185
0
    {
1186
0
        mName = name;
1187
0
    }
1188
    //-----------------------------------------------------------------------------
1189
    void TextureUnitState::_notifyParent(Pass* parent)
1190
0
    {
1191
0
        mParent = parent;
1192
0
    }
1193
    //-----------------------------------------------------------------------------
1194
    void TextureUnitState::setCompositorReference(const String& compositorName, const String& textureName, uint32 mrtIndex)
1195
0
    {  
1196
0
        mCompositorRefName = compositorName; 
1197
0
        mCompositorRefTexName = textureName; 
1198
0
        mCompositorRefMrtIndex = mrtIndex; 
1199
0
    }
1200
    //-----------------------------------------------------------------------
1201
    size_t TextureUnitState::calculateSize(void) const
1202
0
    {
1203
0
        size_t memSize = sizeof(*this);
1204
0
        memSize += mFramePtrs.size() * sizeof(TexturePtr);
1205
0
        memSize += mEffects.size() * sizeof(TextureEffect);
1206
0
        return memSize;
1207
0
    }
1208
1209
0
    bool TextureUnitState::isDefaultFiltering() const {
1210
0
        return mSampler == TextureManager::getSingleton().getDefaultSampler();
1211
0
    }
1212
1213
    const SamplerPtr& TextureUnitState::_getLocalSampler()
1214
0
    {
1215
0
        if(isDefaultFiltering())
1216
0
            mSampler = TextureManager::getSingleton().createSampler();
1217
1218
0
        return mSampler;
1219
0
    }
1220
1221
    TexCoordCalcMethod TextureUnitState::_deriveTexCoordCalcMethod() const
1222
0
    {
1223
0
        TexCoordCalcMethod texCoordCalcMethod = TEXCALC_NONE;
1224
0
        for (const auto& effi : mEffects)
1225
0
        {
1226
0
            switch (effi.second.type)
1227
0
            {
1228
0
            case ET_ENVIRONMENT_MAP:
1229
0
                texCoordCalcMethod = (TexCoordCalcMethod)effi.second.subtype;
1230
0
                break;
1231
0
            case ET_UVSCROLL:
1232
0
            case ET_USCROLL:
1233
0
            case ET_VSCROLL:
1234
0
            case ET_ROTATE:
1235
0
            case ET_TRANSFORM:
1236
0
                break;
1237
0
            case ET_PROJECTIVE_TEXTURE:
1238
0
                texCoordCalcMethod = TEXCALC_PROJECTIVE_TEXTURE;
1239
0
                break;
1240
0
            }
1241
0
        }
1242
1243
0
        return texCoordCalcMethod;
1244
0
    }
1245
}