Coverage Report

Created: 2025-11-04 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreMaterial.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 "OgreMaterial.h"
31
#include "OgreLodStrategyManager.h"
32
#include "OgreLodStrategy.h"
33
34
namespace Ogre {
35
36
    //-----------------------------------------------------------------------
37
    Material::Material(ResourceManager* creator, const String& name, ResourceHandle handle,
38
        const String& group, bool isManual, ManualResourceLoader* loader)
39
0
        :Resource(creator, name, handle, group, false, NULL),
40
0
         mReceiveShadows(true),
41
0
         mTransparencyCastsShadows(false),
42
0
         mCompilationRequired(true)
43
0
    {
44
        // Override isManual, not applicable for Material (we always want to call loadImpl)
45
0
        if(isManual)
46
0
        {
47
0
            LogManager::getSingleton().logWarning("Material " + name +
48
0
                " was requested with isManual=true, but this is not applicable " 
49
0
                "for materials; the flag has been reset to false");
50
0
        }
51
52
        // Initialise to default strategy
53
0
        mLodStrategy = LodStrategyManager::getSingleton().getDefaultStrategy();
54
55
0
        mLodValues.push_back(0.0f);
56
57
0
        applyDefaults();
58
59
        /* For consistency with StringInterface, but we don't add any parameters here
60
        That's because the Resource implementation of StringInterface is to
61
        list all the options that need to be set before loading, of which 
62
        we have none as such. Full details can be set through scripts.
63
        */ 
64
0
        createParamDictionary("Material");
65
0
    }
66
    //-----------------------------------------------------------------------
67
    Material::~Material()
68
0
    {
69
0
        removeAllTechniques();
70
        // have to call this here reather than in Resource destructor
71
        // since calling virtual methods in base destructors causes crash
72
0
        unload(); 
73
0
    }
74
    //-----------------------------------------------------------------------
75
    Material& Material::operator=(const Material& rhs)
76
0
    {
77
0
        if (this == &rhs)
78
0
            return *this;
79
80
0
        Resource::operator=(rhs);
81
0
        mReceiveShadows = rhs.mReceiveShadows;
82
0
        mTransparencyCastsShadows = rhs.mTransparencyCastsShadows;
83
84
        // Copy Techniques
85
0
        this->removeAllTechniques();
86
0
        for(auto *t : rhs.mTechniques)
87
0
        {
88
0
            Technique* tech = this->createTechnique();
89
0
            *tech = *t;
90
0
            if (t->isSupported())
91
0
            {
92
0
                insertSupportedTechnique(tech);
93
0
            }
94
0
        }
95
96
        // Also copy LOD information
97
0
        mUserLodValues = rhs.mUserLodValues;
98
0
        mLodValues = rhs.mLodValues;
99
0
        mLodStrategy = rhs.mLodStrategy;
100
0
        mCompilationRequired = rhs.mCompilationRequired;
101
        // illumination passes are not compiled right away so
102
        // mIsLoaded state should still be the same as the original material
103
0
        assert(isLoaded() == rhs.isLoaded());
104
105
0
        return *this;
106
0
    }
107
108
109
    //-----------------------------------------------------------------------
110
    void Material::prepareImpl(void)
111
0
    {
112
        // compile if required
113
0
        if (mCompilationRequired)
114
0
            compile();
115
116
        // Load all supported techniques
117
0
        for (auto *t : mSupportedTechniques)
118
0
        {
119
0
            t->_prepare();
120
0
        }
121
0
    }
122
    //-----------------------------------------------------------------------
123
    void Material::unprepareImpl(void)
124
0
    {
125
        // Load all supported techniques
126
0
        for (auto *t : mSupportedTechniques)
127
0
        {
128
0
            t->_unprepare();
129
0
        }
130
0
    }
131
    //-----------------------------------------------------------------------
132
    void Material::loadImpl(void)
133
0
    {
134
        // Load all supported techniques
135
0
        for (auto *t : mSupportedTechniques)
136
0
        {
137
0
            t->_load();
138
0
        }
139
0
    }
140
    //-----------------------------------------------------------------------
141
    void Material::unloadImpl(void)
142
0
    {
143
        // Unload all supported techniques
144
0
        for (auto *t : mSupportedTechniques)
145
0
        {
146
0
            t->_unload();
147
0
        }
148
149
0
        mCompilationRequired = true;
150
0
    }
151
    //-----------------------------------------------------------------------
152
    size_t Material::calculateSize(void) const
153
0
    {
154
0
        size_t memSize = sizeof(*this) + Resource::calculateSize();
155
156
        // Tally up techniques
157
0
        for (auto t : mTechniques)
158
0
        {
159
0
            memSize += t->calculateSize();
160
0
        }
161
162
0
        memSize += mUnsupportedReasons.size() * sizeof(char);
163
164
0
        return memSize;
165
0
    }
166
    //-----------------------------------------------------------------------
167
    MaterialPtr Material::clone(const String& newName, const String& newGroup) const
168
0
    {
169
0
        MaterialPtr newMat =
170
0
            MaterialManager::getSingleton().create(newName, newGroup.empty() ? mGroup : newGroup);
171
172
0
        if(!newMat) // interception by collision handler
173
0
            return newMat;
174
175
        // Keep handle (see below, copy overrides everything)
176
0
        ResourceHandle newHandle = newMat->getHandle();
177
        // Assign values from this
178
0
        *newMat = *this;
179
        // Restore new group if required, will have been overridden by operator
180
0
        if (!newGroup.empty())
181
0
        {
182
0
            newMat->mGroup = newGroup;
183
0
        }
184
        
185
        // Correct the name & handle, they get copied too
186
0
        newMat->mName = newName;
187
0
        newMat->mHandle = newHandle;
188
189
        //if we're cloning from a loaded material, notify the creator or otherwise size won't be right
190
0
        if (newMat->getLoadingState() == LOADSTATE_LOADED)
191
0
        {
192
            // Notify manager
193
0
            if (mCreator)
194
0
                mCreator->_notifyResourceLoaded(newMat.get());
195
0
        }
196
197
0
        return newMat;
198
0
    }
199
    //-----------------------------------------------------------------------
200
    void Material::copyDetailsTo(MaterialPtr& mat) const
201
0
    {
202
        // Keep handle (see below, copy overrides everything)
203
0
        ResourceHandle savedHandle = mat->mHandle;
204
0
        String savedName = mat->mName;
205
0
        String savedGroup = mat->mGroup;
206
        // Assign values from this
207
0
        *mat = *this;
208
        // Correct the name & handle, they get copied too
209
0
        mat->mName = savedName;
210
0
        mat->mHandle = savedHandle;
211
0
        mat->mGroup = savedGroup;
212
0
    }
213
    //-----------------------------------------------------------------------
214
    void Material::applyDefaults(void)
215
0
    {
216
0
        MaterialPtr defaults = MaterialManager::getSingleton().getDefaultSettings();
217
218
0
        if (defaults)
219
0
        {
220
            // save name & handle
221
0
            String savedName = mName;
222
0
            String savedGroup = mGroup;
223
0
            ResourceHandle savedHandle = mHandle;
224
0
            *this = *defaults;
225
            // restore name & handle
226
0
            mName = savedName;
227
0
            mHandle = savedHandle;
228
0
            mGroup = savedGroup;
229
0
        }
230
0
        mCompilationRequired = true;
231
232
0
    }
233
    //-----------------------------------------------------------------------
234
    Technique* Material::createTechnique(void)
235
0
    {
236
0
        Technique *t = OGRE_NEW Technique(this);
237
0
        mTechniques.push_back(t);
238
0
        mCompilationRequired = true;
239
0
        return t;
240
0
    }
241
    //-----------------------------------------------------------------------
242
    Technique* Material::getTechnique(const String& name) const
243
0
    {
244
0
        Technique* foundTechnique = 0;
245
        // iterate through techniques to find a match
246
0
        for (auto *t : mTechniques)
247
0
        {
248
0
            if (t->getName() == name)
249
0
            {
250
0
                foundTechnique = t;
251
0
                break;
252
0
            }
253
0
        }
254
255
0
        return foundTechnique;
256
0
    }
257
    //-----------------------------------------------------------------------
258
    unsigned short Material::getNumLodLevels(unsigned short schemeIndex) const
259
0
    {
260
        // Safety check - empty list?
261
0
        if (mBestTechniquesBySchemeList.empty())
262
0
            return 0;
263
264
0
        BestTechniquesBySchemeList::const_iterator i = 
265
0
            mBestTechniquesBySchemeList.find(schemeIndex);
266
0
        if (i == mBestTechniquesBySchemeList.end())
267
0
        {
268
            // get the first item, will be 0 (the default) if default
269
            // scheme techniques exist, otherwise the earliest defined
270
0
            i = mBestTechniquesBySchemeList.begin();
271
0
        }
272
273
0
        return static_cast<unsigned short>(i->second.size());
274
0
    }
275
    //-----------------------------------------------------------------------
276
    unsigned short Material::getNumLodLevels(const String& schemeName) const
277
0
    {
278
0
        return getNumLodLevels(
279
0
            MaterialManager::getSingleton()._getSchemeIndex(schemeName));
280
0
    }
281
    //-----------------------------------------------------------------------
282
    void Material::insertSupportedTechnique(Technique* t)
283
0
    {
284
0
        mSupportedTechniques.push_back(t);
285
        // get scheme
286
0
        unsigned short schemeIndex = t->_getSchemeIndex();
287
288
        // Insert won't replace if supported technique for this scheme/lod is
289
        // already there, which is what we want
290
0
        mBestTechniquesBySchemeList[schemeIndex].emplace(t->getLodIndex(), t);
291
292
0
    }
293
    //-----------------------------------------------------------------------------
294
    Technique* Material::getBestTechnique(unsigned short lodIndex, const Renderable* rend)
295
0
    {
296
0
        if (mSupportedTechniques.empty())
297
0
        {
298
0
            return NULL;
299
0
        }
300
0
        else
301
0
        {
302
0
            Technique* ret = 0;
303
0
            MaterialManager& matMgr = MaterialManager::getSingleton();
304
            // get scheme
305
0
            auto si = mBestTechniquesBySchemeList.find(matMgr._getActiveSchemeIndex());
306
            // scheme not found?
307
0
            if (si == mBestTechniquesBySchemeList.end())
308
0
            {
309
                // listener specified alternative technique available?
310
0
                ret = matMgr._arbitrateMissingTechniqueForActiveScheme(this, lodIndex, rend);
311
0
                if (ret)
312
0
                    return ret;
313
314
0
                OgreAssert(!mBestTechniquesBySchemeList.empty(), "handleSchemeNotFound() must not remove techniques");
315
                // Nope, use default
316
                // get the first item, will be 0 (the default) if default
317
                // scheme techniques exist, otherwise the earliest defined
318
0
                si = mBestTechniquesBySchemeList.begin();
319
0
            }
320
321
            // get LOD
322
0
            auto li = si->second.find(lodIndex);
323
            // LOD not found? 
324
0
            if (li == si->second.end())
325
0
            {
326
                // Use the next LOD level up
327
0
                for (auto rli = si->second.rbegin(); rli != si->second.rend(); ++rli)
328
0
                {
329
0
                    if (rli->second->getLodIndex() < lodIndex)
330
0
                    {
331
0
                        ret = rli->second;
332
0
                        break;
333
0
                    }
334
335
0
                }
336
0
                if (!ret)
337
0
                {
338
                    // shouldn't ever hit this really, unless user defines no LOD 0
339
                    // pick the first LOD we have (must be at least one to have a scheme entry)
340
0
                    ret = si->second.begin()->second;
341
0
                }
342
343
0
            }
344
0
            else
345
0
            {
346
                // LOD found
347
0
                ret = li->second;
348
0
            }
349
350
0
            return ret;
351
352
0
        }
353
0
    }
354
    //-----------------------------------------------------------------------
355
    void Material::removeTechnique(unsigned short index)
356
0
    {
357
0
        assert (index < mTechniques.size() && "Index out of bounds.");
358
0
        Techniques::iterator i = mTechniques.begin() + index;
359
0
        OGRE_DELETE(*i);
360
0
        mTechniques.erase(i);
361
0
        clearBestTechniqueList();
362
0
    }
363
    //-----------------------------------------------------------------------
364
    void Material::removeAllTechniques(void)
365
0
    {
366
0
        for (auto *t : mTechniques)
367
0
        {
368
0
            OGRE_DELETE t;
369
0
        }
370
0
        mTechniques.clear();
371
0
        clearBestTechniqueList();
372
0
    }
373
    //-----------------------------------------------------------------------
374
    Material::TechniqueIterator Material::getTechniqueIterator(void) 
375
0
    {
376
0
        return TechniqueIterator(mTechniques.begin(), mTechniques.end());
377
0
    }
378
    //-----------------------------------------------------------------------
379
    Material::TechniqueIterator Material::getSupportedTechniqueIterator(void)
380
0
    {
381
0
        return TechniqueIterator(mSupportedTechniques.begin(), mSupportedTechniques.end());
382
0
    }
383
    //-----------------------------------------------------------------------
384
    bool Material::isTransparent(void) const
385
0
    {
386
        // Check each technique
387
0
        for (auto *t : mTechniques)
388
0
        {
389
0
            if (t->isTransparent())
390
0
                return true;
391
0
        }
392
0
        return false;
393
0
    }
394
    //-----------------------------------------------------------------------
395
    void Material::compile(bool autoManageTextureUnits)
396
0
    {
397
        // Compile each technique, then add it to the list of supported techniques
398
0
        clearBestTechniqueList();
399
0
        mUnsupportedReasons.clear();
400
401
0
        size_t techNo = 0;
402
0
        for (auto *t : mTechniques)
403
0
        {
404
0
            String compileMessages = t->_compile(autoManageTextureUnits);
405
0
            if (t->isSupported())
406
0
            {
407
0
                insertSupportedTechnique(t);
408
0
            }
409
0
            else
410
0
            {
411
                // Log informational
412
0
                StringStream str;
413
0
                str << "Material " << mName << " Technique " << techNo;
414
0
                if (!t->getName().empty())
415
0
                    str << "(" << t->getName() << ")";
416
0
                str << " is not supported. " << compileMessages;
417
0
                LogManager::getSingleton().logMessage(str.str(), LML_TRIVIAL);
418
0
                mUnsupportedReasons += compileMessages;
419
0
            }
420
0
            ++techNo;
421
0
        }
422
423
0
        mCompilationRequired = false;
424
425
        // Did we find any?
426
0
        if (mSupportedTechniques.empty())
427
0
        {
428
0
            LogManager::getSingleton().stream(LML_WARNING)
429
0
                << "Warning: material " << mName << " has no supportable "
430
0
                << "Techniques and will be blank. Explanation: \n" << mUnsupportedReasons;
431
0
        }
432
0
    }
433
    //-----------------------------------------------------------------------
434
    void Material::clearBestTechniqueList(void)
435
0
    {
436
0
        mSupportedTechniques.clear();
437
0
        mBestTechniquesBySchemeList.clear();
438
0
        mCompilationRequired = true;
439
0
    }
440
    //-----------------------------------------------------------------------
441
0
    #define ALL_TECHNIQUES(fncall) for(auto t : mTechniques) t->fncall
442
0
    void Material::setPointSize(Real ps) { ALL_TECHNIQUES(setPointSize(ps)); }
443
    //-----------------------------------------------------------------------
444
0
    void Material::setAmbient(float red, float green, float blue) { setAmbient(ColourValue(red, green, blue)); }
445
    //-----------------------------------------------------------------------
446
0
    void Material::setAmbient(const ColourValue& ambient) { ALL_TECHNIQUES(setAmbient(ambient)); }
447
    //-----------------------------------------------------------------------
448
    void Material::setDiffuse(float red, float green, float blue, float alpha)
449
0
    {
450
0
        ALL_TECHNIQUES(setDiffuse(red, green, blue, alpha));
451
0
    }
452
    //-----------------------------------------------------------------------
453
0
    void Material::setDiffuse(const ColourValue& diffuse) { setDiffuse(diffuse.r, diffuse.g, diffuse.b, diffuse.a); }
454
    //-----------------------------------------------------------------------
455
    void Material::setSpecular(float red, float green, float blue, float alpha)
456
0
    {
457
0
        ALL_TECHNIQUES(setSpecular(red, green, blue, alpha));
458
0
    }
459
    //-----------------------------------------------------------------------
460
    void Material::setSpecular(const ColourValue& specular)
461
0
    {
462
0
        setSpecular(specular.r, specular.g, specular.b, specular.a);
463
0
    }
464
    //-----------------------------------------------------------------------
465
0
    void Material::setShininess(Real val) { ALL_TECHNIQUES(setShininess(val)); }
466
    //-----------------------------------------------------------------------
467
    void Material::setSelfIllumination(float red, float green, float blue)
468
0
    {
469
0
        setSelfIllumination(ColourValue(red, green, blue));
470
0
    }
471
    //-----------------------------------------------------------------------
472
0
    void Material::setSelfIllumination(const ColourValue& selfIllum) { ALL_TECHNIQUES(setSelfIllumination(selfIllum)); }
473
    //-----------------------------------------------------------------------
474
0
    void Material::setDepthCheckEnabled(bool enabled) { ALL_TECHNIQUES(setDepthCheckEnabled(enabled)); }
475
    //-----------------------------------------------------------------------
476
0
    void Material::setDepthWriteEnabled(bool enabled) { ALL_TECHNIQUES(setDepthWriteEnabled(enabled)); }
477
    //-----------------------------------------------------------------------
478
0
    void Material::setDepthFunction(CompareFunction func) { ALL_TECHNIQUES(setDepthFunction(func)); }
479
    //-----------------------------------------------------------------------
480
0
    void Material::setColourWriteEnabled(bool enabled) { ALL_TECHNIQUES(setColourWriteEnabled(enabled)); }
481
    //-----------------------------------------------------------------------
482
    void Material::setColourWriteEnabled(bool red, bool green, bool blue, bool alpha)
483
0
    {
484
0
        ALL_TECHNIQUES(setColourWriteEnabled(red, green, blue, alpha));
485
0
    }
486
    //-----------------------------------------------------------------------
487
0
    void Material::setCullingMode(CullingMode mode) { ALL_TECHNIQUES(setCullingMode(mode)); }
488
    //-----------------------------------------------------------------------
489
0
    void Material::setManualCullingMode(ManualCullingMode mode) { ALL_TECHNIQUES(setManualCullingMode(mode)); }
490
    //-----------------------------------------------------------------------
491
0
    void Material::setLightingEnabled(bool enabled) { ALL_TECHNIQUES(setLightingEnabled(enabled)); }
492
    //-----------------------------------------------------------------------
493
0
    void Material::setShadingMode(ShadeOptions mode) { ALL_TECHNIQUES(setShadingMode(mode)); }
494
    //-----------------------------------------------------------------------
495
    void Material::setFog(bool overrideScene, FogMode mode, const ColourValue& colour, Real expDensity,
496
                          Real linearStart, Real linearEnd)
497
0
    {
498
0
        ALL_TECHNIQUES(setFog(overrideScene, mode, colour, expDensity, linearStart, linearEnd));
499
0
    }
500
    //-----------------------------------------------------------------------
501
    void Material::setDepthBias(float constantBias, float slopeScaleBias)
502
0
    {
503
0
        ALL_TECHNIQUES(setDepthBias(constantBias, slopeScaleBias));
504
0
    }
505
    //-----------------------------------------------------------------------
506
    void Material::setTextureFiltering(TextureFilterOptions filterType)
507
0
    {
508
0
        ALL_TECHNIQUES(setTextureFiltering(filterType));
509
0
    }
510
    // --------------------------------------------------------------------
511
0
    void Material::setTextureAnisotropy(int maxAniso) { ALL_TECHNIQUES(setTextureAnisotropy(maxAniso)); }
512
    // --------------------------------------------------------------------
513
0
    void Material::setSceneBlending(const SceneBlendType sbt) { ALL_TECHNIQUES(setSceneBlending(sbt)); }
514
    // --------------------------------------------------------------------
515
    void Material::setSeparateSceneBlending(const SceneBlendType sbt, const SceneBlendType sbta)
516
0
    {
517
0
        ALL_TECHNIQUES(setSeparateSceneBlending(sbt, sbta));
518
0
    }
519
    // --------------------------------------------------------------------
520
    void Material::setSceneBlending(const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor)
521
0
    {
522
0
        ALL_TECHNIQUES(setSceneBlending(sourceFactor, destFactor));
523
0
    }
524
    // --------------------------------------------------------------------
525
    void Material::setSeparateSceneBlending( const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor, const SceneBlendFactor sourceFactorAlpha, const SceneBlendFactor destFactorAlpha)
526
0
    {
527
0
        ALL_TECHNIQUES(setSeparateSceneBlending(sourceFactor, destFactor, sourceFactorAlpha, destFactorAlpha));
528
0
    }
529
    #undef ALL_TECHNIQUES
530
    // --------------------------------------------------------------------
531
    void Material::_notifyNeedsRecompile(void)
532
0
    {
533
0
        mCompilationRequired = true;
534
        // Also need to unload to ensure we loaded any new items
535
0
        if (isLoaded()) // needed to stop this being called in 'loading' state
536
0
            unload();
537
0
    }
538
    // --------------------------------------------------------------------
539
    void Material::setLodLevels(const LodValueList& lodValues)
540
0
    {
541
        // Square the distances for the internal list
542
        // First, clear and add single zero entry
543
0
        mLodValues.clear();
544
0
        mUserLodValues.clear();
545
0
        mUserLodValues.push_back(0);
546
0
        if (mLodStrategy)
547
0
            mLodValues.push_back(mLodStrategy->getBaseValue());
548
0
        for (auto& v : lodValues)
549
0
        {
550
0
            mUserLodValues.push_back(v);
551
0
            if (mLodStrategy)
552
0
                mLodValues.push_back(mLodStrategy->transformUserValue(v));
553
0
        }
554
0
    }
555
    // --------------------------------------------------------------------
556
    ushort Material::getLodIndex(Real value) const
557
0
    {
558
0
        return mLodStrategy->getIndex(value, mLodValues);
559
0
    }
560
    // --------------------------------------------------------------------
561
    Material::LodValueIterator Material::getLodValueIterator(void) const
562
0
    {
563
0
        return LodValueIterator(mLodValues.begin(), mLodValues.end());
564
0
    }
565
    // --------------------------------------------------------------------
566
    Material::LodValueIterator Material::getUserLodValueIterator(void) const
567
0
    {
568
0
        return LodValueIterator(mUserLodValues.begin(), mUserLodValues.end());
569
0
    }
570
    //---------------------------------------------------------------------
571
    const LodStrategy *Material::getLodStrategy() const
572
0
    {
573
0
        return mLodStrategy;
574
0
    }
575
    //---------------------------------------------------------------------
576
    void Material::setLodStrategy(LodStrategy *lodStrategy)
577
0
    {
578
0
        mLodStrategy = lodStrategy;
579
580
0
        assert(mLodValues.size());
581
0
        mLodValues[0] = mLodStrategy->getBaseValue();
582
583
        // Re-transform all user LOD values (starting at index 1, no need to transform base value)
584
0
        for (size_t i = 1; i < mUserLodValues.size(); ++i)
585
0
            mLodValues[i] = mLodStrategy->transformUserValue(mUserLodValues[i]);
586
0
    }
587
    //---------------------------------------------------------------------
588
}