Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreTechnique.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 36.8 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30
31#include "OgreTechnique.h"
32#include "OgreMaterial.h"
33#include "OgrePass.h"
34#include "OgreRoot.h"
35#include "OgreRenderSystem.h"
36#include "OgreRenderSystemCapabilities.h"
37#include "OgreGpuProgramManager.h"
38#include "OgreMaterialManager.h"
39
40
41namespace Ogre {
42    //-----------------------------------------------------------------------------
43    Technique::Technique(Material* parent)
44        : mParent(parent), mIsSupported(false), mIlluminationPassesCompilationPhase(IPS_NOT_COMPILED), mLodIndex(0), mSchemeIndex(0)
45    {
46        // See above, defaults to unsupported until examined
47    }
48    //-----------------------------------------------------------------------------
49    Technique::Technique(Material* parent, const Technique& oth)
50        : mParent(parent), mLodIndex(0), mSchemeIndex(0)
51    {
52        // Copy using operator=
53        *this = oth;
54    }
55    //-----------------------------------------------------------------------------
56    Technique::~Technique()
57    {
58        removeAllPasses();
59        clearIlluminationPasses();
60    }
61    //-----------------------------------------------------------------------------
62    bool Technique::isSupported(void) const
63    {
64        return mIsSupported;
65    }
66    //-----------------------------------------------------------------------------
67    String Technique::_compile(bool autoManageTextureUnits)
68    {
69                StringUtil::StrStreamType compileErrors;
70
71                // assume not supported
72                mIsSupported = false;
73        // Go through each pass, checking requirements
74        Passes::iterator i;
75                unsigned short passNum = 0;
76                const RenderSystemCapabilities* caps =
77                        Root::getSingleton().getRenderSystem()->getCapabilities();
78                unsigned short numTexUnits = caps->getNumTextureUnits();
79        for (i = mPasses.begin(); i != mPasses.end(); ++i, ++passNum)
80        {
81            Pass* currPass = *i;
82                        // Adjust pass index
83                        currPass->_notifyIndex(passNum);
84            // Check texture unit requirements
85            size_t numTexUnitsRequested = currPass->getNumTextureUnitStates();
86                        // Don't trust getNumTextureUnits for programmable
87                        if(!currPass->hasFragmentProgram())
88                        {
89        #if defined(OGRE_PRETEND_TEXTURE_UNITS) && OGRE_PRETEND_TEXTURE_UNITS > 0
90                                if (numTexUnits > OGRE_PRETEND_TEXTURE_UNITS)
91                                        numTexUnits = OGRE_PRETEND_TEXTURE_UNITS;
92        #endif
93                                if (numTexUnitsRequested > numTexUnits)
94                                {
95                                        if (!autoManageTextureUnits)
96                                        {
97                                                // The user disabled auto pass split
98                                                compileErrors << "Pass " << passNum << 
99                                                        ": Too many texture units for the current hardware and no splitting allowed."
100                                                        << std::endl;
101                                                return compileErrors.str();
102                                        }
103                                        else if (currPass->hasVertexProgram())
104                                        {
105                                                // Can't do this one, and can't split a programmable pass
106                                                compileErrors << "Pass " << passNum << 
107                                                        ": Too many texture units for the current hardware and "
108                                                        "cannot split programmable passes."
109                                                        << std::endl;
110                                                return compileErrors.str();
111                                        }
112                                }
113                        }
114
115                        if (currPass->hasVertexProgram())
116                        {
117                                // Check vertex program version
118                                if (!currPass->getVertexProgram()->isSupported() )
119                                {
120                                        // Can't do this one
121                                        compileErrors << "Pass " << passNum << 
122                                                ": Vertex program " << currPass->getVertexProgram()->getName()
123                                                << " cannot be used - ";
124                                        if (currPass->getVertexProgram()->hasCompileError())
125                                                compileErrors << "compile error.";
126                                        else
127                                                compileErrors << "not supported.";
128
129                                        compileErrors << std::endl;
130                                        return compileErrors.str();
131                                }
132                        }
133            if (currPass->hasFragmentProgram())
134            {
135                // Check fragment program version
136                if (!currPass->getFragmentProgram()->isSupported())
137                {
138                    // Can't do this one
139                                        compileErrors << "Pass " << passNum << 
140                                                ": Fragment program " << currPass->getFragmentProgram()->getName()
141                                                << " cannot be used - ";
142                                        if (currPass->getFragmentProgram()->hasCompileError())
143                                                compileErrors << "compile error.";
144                                        else
145                                                compileErrors << "not supported.";
146
147                                        compileErrors << std::endl;
148                                        return compileErrors.str();
149                }
150            }
151            else
152            {
153                                // Check a few fixed-function options in texture layers
154                Pass::TextureUnitStateIterator texi = currPass->getTextureUnitStateIterator();
155                                size_t texUnit = 0;
156                                while (texi.hasMoreElements())
157                                {
158                                        TextureUnitState* tex = texi.getNext();
159                                        // Any Cube textures? NB we make the assumption that any
160                                        // card capable of running fragment programs can support
161                                        // cubic textures, which has to be true, surely?
162                                        if (tex->is3D() && !caps->hasCapability(RSC_CUBEMAPPING))
163                                        {
164                                                // Fail
165                                                compileErrors << "Pass " << passNum << 
166                                                        " Tex " << texUnit <<
167                                                        ": Cube maps not supported by current environment."
168                                                        << std::endl;
169                                                return compileErrors.str();
170                                        }
171                                        // Any 3D textures? NB we make the assumption that any
172                                        // card capable of running fragment programs can support
173                                        // 3D textures, which has to be true, surely?
174                                        if (tex->getTextureType() == TEX_TYPE_3D && !caps->hasCapability(RSC_TEXTURE_3D))
175                                        {
176                                                // Fail
177                                                compileErrors << "Pass " << passNum << 
178                                                        " Tex " << texUnit <<
179                                                        ": Volume textures not supported by current environment."
180                                                        << std::endl;
181                                                return compileErrors.str();
182                                        }
183                                        // Any Dot3 blending?
184                                        if (tex->getColourBlendMode().operation == LBX_DOTPRODUCT &&
185                                                        !caps->hasCapability(RSC_DOT3))
186                                        {
187                                                // Fail
188                                                compileErrors << "Pass " << passNum << 
189                                                        " Tex " << texUnit <<
190                                                        ": DOT3 blending not supported by current environment."
191                                                        << std::endl;
192                                                return compileErrors.str();
193                                        }
194                                        ++texUnit;
195                                }
196
197                                // We're ok on operations, now we need to check # texture units
198                                if (!currPass->hasFragmentProgram())
199                                {
200                                        // Keep splitting this pass so long as units requested > gpu units
201                                        while (numTexUnitsRequested > numTexUnits)
202                                        {
203                                                // chop this pass into many passes
204                                                currPass = currPass->_split(numTexUnits);
205                                                numTexUnitsRequested = currPass->getNumTextureUnitStates();
206                                                // Advance pass number
207                                                ++passNum;
208                                                // Reset iterator
209                                                i = mPasses.begin() + passNum;
210                                                // Move the new pass to the right place (will have been created
211                                                // at the end, may be other passes in between)
212                                                assert(mPasses.back() == currPass);
213                                                std::copy_backward(i, (mPasses.end()-1), mPasses.end());
214                                                *i = currPass;
215                                                // Adjust pass index
216                                                currPass->_notifyIndex(passNum);
217                                        }
218                                }
219            }
220
221                }
222        // If we got this far, we're ok
223        mIsSupported = true;
224
225        // Compile for categorised illumination on demand
226        clearIlluminationPasses();
227        mIlluminationPassesCompilationPhase = IPS_NOT_COMPILED;
228
229                return StringUtil::BLANK;
230
231    }
232    //-----------------------------------------------------------------------------
233    Pass* Technique::createPass(void)
234    {
235                Pass* newPass = new Pass(this, static_cast<unsigned short>(mPasses.size()));
236                mPasses.push_back(newPass);
237                return newPass;
238    }
239    //-----------------------------------------------------------------------------
240    Pass* Technique::getPass(unsigned short index)
241    {
242                assert(index < mPasses.size() && "Index out of bounds");
243                return mPasses[index];
244    }
245    //-----------------------------------------------------------------------------
246    Pass* Technique::getPass(const String& name)
247    {
248        Passes::iterator i    = mPasses.begin();
249        Passes::iterator iend = mPasses.end();
250        Pass* foundPass = 0;
251
252        // iterate through techniques to find a match
253        while (i != iend)
254        {
255            if ( (*i)->getName() == name )
256            {
257                foundPass = (*i);
258                break;
259            }
260            ++i;
261        }
262
263        return foundPass;
264    }
265    //-----------------------------------------------------------------------------
266    unsigned short Technique::getNumPasses(void) const
267    {
268                return static_cast<unsigned short>(mPasses.size());
269    }
270    //-----------------------------------------------------------------------------
271    void Technique::removePass(unsigned short index)
272    {
273                assert(index < mPasses.size() && "Index out of bounds");
274                Passes::iterator i = mPasses.begin() + index;
275                (*i)->queueForDeletion();
276                i = mPasses.erase(i);
277                // Adjust passes index
278                for (; i != mPasses.end(); ++i, ++index)
279                {
280                        (*i)->_notifyIndex(index);
281                }
282    }
283    //-----------------------------------------------------------------------------
284    void Technique::removeAllPasses(void)
285    {
286        Passes::iterator i, iend;
287        iend = mPasses.end();
288        for (i = mPasses.begin(); i != iend; ++i)
289        {
290            (*i)->queueForDeletion();
291        }
292        mPasses.clear();
293    }
294
295    //-----------------------------------------------------------------------------
296    bool Technique::movePass(const unsigned short sourceIndex, const unsigned short destinationIndex)
297    {
298        bool moveSuccessful = false;
299
300        // don't move the pass if source == destination
301        if (sourceIndex == destinationIndex) return true;
302
303        if( (sourceIndex < mPasses.size()) && (destinationIndex < mPasses.size()))
304        {
305            Passes::iterator i = mPasses.begin() + sourceIndex;
306            //Passes::iterator DestinationIterator = mPasses.begin() + destinationIndex;
307
308            Pass* pass = (*i);
309            mPasses.erase(i);
310
311            i = mPasses.begin() + destinationIndex;
312
313            // compensate for source erase if destination is greater than source
314            if (destinationIndex > sourceIndex) --i;
315
316            mPasses.insert(i, pass);
317
318                        // Adjust passes index
319                        unsigned short beginIndex, endIndex;
320                        if (destinationIndex > sourceIndex)
321                        {
322                                beginIndex = sourceIndex;
323                                endIndex = destinationIndex;
324                        }
325                        else
326                        {
327                                beginIndex = destinationIndex;
328                                endIndex = sourceIndex;
329                        }
330                        for (unsigned short index = beginIndex; index <= endIndex; ++index)
331                        {
332                                mPasses[index]->_notifyIndex(index);
333                        }
334            moveSuccessful = true;
335        }
336
337        return moveSuccessful;
338    }
339
340    //-----------------------------------------------------------------------------
341    const Technique::PassIterator Technique::getPassIterator(void)
342    {
343                return PassIterator(mPasses.begin(), mPasses.end());
344    }
345    //-----------------------------------------------------------------------------
346    Technique& Technique::operator=(const Technique& rhs)
347    {
348        mName = rhs.mName;
349                this->mIsSupported = rhs.mIsSupported;
350        this->mLodIndex = rhs.mLodIndex;
351                this->mSchemeIndex = rhs.mSchemeIndex;
352                // copy passes
353                removeAllPasses();
354                Passes::const_iterator i, iend;
355                iend = rhs.mPasses.end();
356                for (i = rhs.mPasses.begin(); i != iend; ++i)
357                {
358                        Pass* p = new Pass(this, (*i)->getIndex(), *(*i));
359                        mPasses.push_back(p);
360                }
361        // Compile for categorised illumination on demand
362        clearIlluminationPasses();
363        mIlluminationPassesCompilationPhase = IPS_NOT_COMPILED;
364                return *this;
365    }
366    //-----------------------------------------------------------------------------
367    bool Technique::isTransparent(void) const
368    {
369        if (mPasses.empty())
370        {
371            return false;
372        }
373        else
374        {
375            // Base decision on the transparency of the first pass
376            return mPasses[0]->isTransparent();
377        }
378    }
379    //-----------------------------------------------------------------------------
380    bool Technique::isDepthWriteEnabled(void) const
381    {
382        if (mPasses.empty())
383        {
384            return false;
385        }
386        else
387        {
388            // Base decision on the depth settings of the first pass
389            return mPasses[0]->getDepthWriteEnabled();
390        }
391    }
392    //-----------------------------------------------------------------------------
393    bool Technique::isDepthCheckEnabled(void) const
394    {
395        if (mPasses.empty())
396        {
397            return false;
398        }
399        else
400        {
401            // Base decision on the depth settings of the first pass
402            return mPasses[0]->getDepthCheckEnabled();
403        }
404    }
405    //-----------------------------------------------------------------------------
406    bool Technique::hasColourWriteDisabled(void) const
407    {
408        if (mPasses.empty())
409        {
410            return true;
411        }
412        else
413        {
414            // Base decision on the colour write settings of the first pass
415            return !mPasses[0]->getColourWriteEnabled();
416        }
417    }
418    //-----------------------------------------------------------------------------
419    void Technique::_load(void)
420    {
421                assert (mIsSupported && "This technique is not supported");
422                // Load each pass
423                Passes::iterator i, iend;
424                iend = mPasses.end();
425                for (i = mPasses.begin(); i != iend; ++i)
426                {
427                        (*i)->_load();
428                }
429
430                IlluminationPassList::iterator il, ilend;
431                ilend = mIlluminationPasses.end();
432                for (il = mIlluminationPasses.begin(); il != ilend; ++il)
433                {
434                        if((*il)->pass != (*il)->originalPass)
435                            (*il)->pass->_load();
436                }
437    }
438    //-----------------------------------------------------------------------------
439    void Technique::_unload(void)
440    {
441                // Unload each pass
442                Passes::iterator i, iend;
443                iend = mPasses.end();
444                for (i = mPasses.begin(); i != iend; ++i)
445                {
446                        (*i)->_unload();
447                }
448    }
449    //-----------------------------------------------------------------------------
450    bool Technique::isLoaded(void) const
451    {
452        // Only supported technique will be loaded
453        return mParent->isLoaded() && mIsSupported;
454    }
455    //-----------------------------------------------------------------------
456    void Technique::setPointSize(Real ps)
457    {
458        Passes::iterator i, iend;
459        iend = mPasses.end();
460        for (i = mPasses.begin(); i != iend; ++i)
461        {
462            (*i)->setPointSize(ps);
463        }
464
465    }
466    //-----------------------------------------------------------------------
467    void Technique::setAmbient(Real red, Real green, Real blue)
468    {
469        Passes::iterator i, iend;
470        iend = mPasses.end();
471        for (i = mPasses.begin(); i != iend; ++i)
472        {
473            (*i)->setAmbient(red, green, blue);
474        }
475
476    }
477    //-----------------------------------------------------------------------
478    void Technique::setAmbient(const ColourValue& ambient)
479    {
480        setAmbient(ambient.r, ambient.g, ambient.b);
481    }
482    //-----------------------------------------------------------------------
483    void Technique::setDiffuse(Real red, Real green, Real blue, Real alpha)
484    {
485        Passes::iterator i, iend;
486        iend = mPasses.end();
487        for (i = mPasses.begin(); i != iend; ++i)
488        {
489            (*i)->setDiffuse(red, green, blue, alpha);
490        }
491    }
492    //-----------------------------------------------------------------------
493    void Technique::setDiffuse(const ColourValue& diffuse)
494    {
495        setDiffuse(diffuse.r, diffuse.g, diffuse.b, diffuse.a);
496    }
497    //-----------------------------------------------------------------------
498    void Technique::setSpecular(Real red, Real green, Real blue, Real alpha)
499    {
500        Passes::iterator i, iend;
501        iend = mPasses.end();
502        for (i = mPasses.begin(); i != iend; ++i)
503        {
504            (*i)->setSpecular(red, green, blue, alpha);
505        }
506    }
507    //-----------------------------------------------------------------------
508    void Technique::setSpecular(const ColourValue& specular)
509    {
510        setSpecular(specular.r, specular.g, specular.b, specular.a);
511    }
512    //-----------------------------------------------------------------------
513    void Technique::setShininess(Real val)
514    {
515        Passes::iterator i, iend;
516        iend = mPasses.end();
517        for (i = mPasses.begin(); i != iend; ++i)
518        {
519            (*i)->setShininess(val);
520        }
521    }
522    //-----------------------------------------------------------------------
523    void Technique::setSelfIllumination(Real red, Real green, Real blue)
524    {
525        Passes::iterator i, iend;
526        iend = mPasses.end();
527        for (i = mPasses.begin(); i != iend; ++i)
528        {
529            (*i)->setSelfIllumination(red, green, blue);
530        }
531    }
532    //-----------------------------------------------------------------------
533    void Technique::setSelfIllumination(const ColourValue& selfIllum)
534    {
535        setSelfIllumination(selfIllum.r, selfIllum.g, selfIllum.b);
536    }
537    //-----------------------------------------------------------------------
538    void Technique::setDepthCheckEnabled(bool enabled)
539    {
540        Passes::iterator i, iend;
541        iend = mPasses.end();
542        for (i = mPasses.begin(); i != iend; ++i)
543        {
544            (*i)->setDepthCheckEnabled(enabled);
545        }
546    }
547    //-----------------------------------------------------------------------
548    void Technique::setDepthWriteEnabled(bool enabled)
549    {
550        Passes::iterator i, iend;
551        iend = mPasses.end();
552        for (i = mPasses.begin(); i != iend; ++i)
553        {
554            (*i)->setDepthWriteEnabled(enabled);
555        }
556    }
557    //-----------------------------------------------------------------------
558    void Technique::setDepthFunction( CompareFunction func )
559    {
560        Passes::iterator i, iend;
561        iend = mPasses.end();
562        for (i = mPasses.begin(); i != iend; ++i)
563        {
564            (*i)->setDepthFunction(func);
565        }
566    }
567    //-----------------------------------------------------------------------
568        void Technique::setColourWriteEnabled(bool enabled)
569    {
570        Passes::iterator i, iend;
571        iend = mPasses.end();
572        for (i = mPasses.begin(); i != iend; ++i)
573        {
574            (*i)->setColourWriteEnabled(enabled);
575        }
576    }
577    //-----------------------------------------------------------------------
578    void Technique::setCullingMode( CullingMode mode )
579    {
580        Passes::iterator i, iend;
581        iend = mPasses.end();
582        for (i = mPasses.begin(); i != iend; ++i)
583        {
584            (*i)->setCullingMode(mode);
585        }
586    }
587    //-----------------------------------------------------------------------
588    void Technique::setManualCullingMode( ManualCullingMode mode )
589    {
590        Passes::iterator i, iend;
591        iend = mPasses.end();
592        for (i = mPasses.begin(); i != iend; ++i)
593        {
594            (*i)->setManualCullingMode(mode);
595        }
596    }
597    //-----------------------------------------------------------------------
598    void Technique::setLightingEnabled(bool enabled)
599    {
600        Passes::iterator i, iend;
601        iend = mPasses.end();
602        for (i = mPasses.begin(); i != iend; ++i)
603        {
604            (*i)->setLightingEnabled(enabled);
605        }
606    }
607    //-----------------------------------------------------------------------
608    void Technique::setShadingMode( ShadeOptions mode )
609    {
610        Passes::iterator i, iend;
611        iend = mPasses.end();
612        for (i = mPasses.begin(); i != iend; ++i)
613        {
614            (*i)->setShadingMode(mode);
615        }
616    }
617    //-----------------------------------------------------------------------
618    void Technique::setFog(bool overrideScene, FogMode mode, const ColourValue& colour,
619        Real expDensity, Real linearStart, Real linearEnd)
620    {
621        Passes::iterator i, iend;
622        iend = mPasses.end();
623        for (i = mPasses.begin(); i != iend; ++i)
624        {
625            (*i)->setFog(overrideScene, mode, colour, expDensity, linearStart, linearEnd);
626        }
627    }
628    //-----------------------------------------------------------------------
629    void Technique::setDepthBias(float constantBias, float slopeScaleBias)
630    {
631        Passes::iterator i, iend;
632        iend = mPasses.end();
633        for (i = mPasses.begin(); i != iend; ++i)
634        {
635            (*i)->setDepthBias(constantBias, slopeScaleBias);
636        }
637    }
638    //-----------------------------------------------------------------------
639    void Technique::setTextureFiltering(TextureFilterOptions filterType)
640    {
641        Passes::iterator i, iend;
642        iend = mPasses.end();
643        for (i = mPasses.begin(); i != iend; ++i)
644        {
645            (*i)->setTextureFiltering(filterType);
646        }
647    }
648    // --------------------------------------------------------------------
649    void Technique::setTextureAnisotropy(unsigned int maxAniso)
650    {
651        Passes::iterator i, iend;
652        iend = mPasses.end();
653        for (i = mPasses.begin(); i != iend; ++i)
654        {
655            (*i)->setTextureAnisotropy(maxAniso);
656        }
657    }
658    // --------------------------------------------------------------------
659    void Technique::setSceneBlending( const SceneBlendType sbt )
660    {
661        Passes::iterator i, iend;
662        iend = mPasses.end();
663        for (i = mPasses.begin(); i != iend; ++i)
664        {
665            (*i)->setSceneBlending(sbt);
666        }
667    }
668    // --------------------------------------------------------------------
669    void Technique::setSceneBlending( const SceneBlendFactor sourceFactor,
670        const SceneBlendFactor destFactor)
671    {
672        Passes::iterator i, iend;
673        iend = mPasses.end();
674        for (i = mPasses.begin(); i != iend; ++i)
675        {
676            (*i)->setSceneBlending(sourceFactor, destFactor);
677        }
678    }
679
680    // --------------------------------------------------------------------
681    void Technique::setName(const String& name)
682    {
683        mName = name;
684    }
685
686
687    //-----------------------------------------------------------------------
688    void Technique::_notifyNeedsRecompile(void)
689    {
690        // Disable require to recompile when splitting illumination passes
691        if (mIlluminationPassesCompilationPhase != IPS_COMPILE_DISABLED)
692        {
693            mParent->_notifyNeedsRecompile();
694        }
695    }
696    //-----------------------------------------------------------------------
697    void Technique::setLodIndex(unsigned short index)
698    {
699        mLodIndex = index;
700        _notifyNeedsRecompile();
701    }
702    //-----------------------------------------------------------------------
703        void Technique::setSchemeName(const String& schemeName)
704        {
705                mSchemeIndex = MaterialManager::getSingleton()._getSchemeIndex(schemeName);
706        _notifyNeedsRecompile();
707        }
708    //-----------------------------------------------------------------------
709        const String& Technique::getSchemeName(void) const
710        {
711                return MaterialManager::getSingleton()._getSchemeName(mSchemeIndex);
712        }
713    //-----------------------------------------------------------------------
714        unsigned short Technique::_getSchemeIndex(void) const
715        {
716                return mSchemeIndex;
717        }
718    //-----------------------------------------------------------------------
719    void Technique::_compileIlluminationPasses(void)
720    {
721        clearIlluminationPasses();
722
723        Passes::iterator i, iend;
724        iend = mPasses.end();
725        i = mPasses.begin();
726
727        IlluminationStage iStage = IS_AMBIENT;
728
729        bool haveAmbient = false;
730        while (i != iend)
731        {
732            IlluminationPass* iPass;
733            Pass* p = *i;
734            switch(iStage)
735            {
736            case IS_AMBIENT:
737                // Keep looking for ambient only
738                if (p->isAmbientOnly())
739                {
740                    // Add this pass wholesale
741                    iPass = new IlluminationPass();
742                    iPass->destroyOnShutdown = false;
743                    iPass->originalPass = iPass->pass = p;
744                    iPass->stage = iStage;
745                    mIlluminationPasses.push_back(iPass);
746                    haveAmbient = true;
747                    // progress to next pass
748                    ++i;
749                }
750                else
751                {
752                    // Split off any ambient part
753                    if (p->getAmbient() != ColourValue::Black ||
754                        p->getSelfIllumination() != ColourValue::Black ||
755                        p->getAlphaRejectFunction() != CMPF_ALWAYS_PASS)
756                    {
757                        // Copy existing pass
758                        Pass* newPass = new Pass(this, p->getIndex(), *p);
759                        if (newPass->getAlphaRejectFunction() != CMPF_ALWAYS_PASS)
760                        {
761                            // Alpha rejection passes must retain their transparency, so
762                            // we allow the texture units, but override the colour functions
763                            Pass::TextureUnitStateIterator tusi = newPass->getTextureUnitStateIterator();
764                            while (tusi.hasMoreElements())
765                            {
766                                TextureUnitState* tus = tusi.getNext();
767                                tus->setColourOperationEx(LBX_SOURCE1, LBS_CURRENT);
768                            }
769                        }
770                        else
771                        {
772                            // Remove any texture units
773                            newPass->removeAllTextureUnitStates();
774                        }
775                        // Remove any fragment program
776                        if (newPass->hasFragmentProgram())
777                            newPass->setFragmentProgram("");
778                        // We have to leave vertex program alone (if any) and
779                        // just trust that the author is using light bindings, which
780                        // we will ensure there are none in the ambient pass
781                        newPass->setDiffuse(0, 0, 0, newPass->getDiffuse().a);  // Preserving alpha
782                        newPass->setSpecular(ColourValue::Black);
783
784                        // Calculate hash value for new pass, because we are compiling
785                        // illumination passes on demand, which will loss hash calculate
786                        // before it add to render queue first time.
787                        newPass->_recalculateHash();
788
789                        iPass = new IlluminationPass();
790                        iPass->destroyOnShutdown = true;
791                        iPass->originalPass = p;
792                        iPass->pass = newPass;
793                        iPass->stage = iStage;
794
795                        mIlluminationPasses.push_back(iPass);
796                        haveAmbient = true;
797
798                    }
799
800                    if (!haveAmbient)
801                    {
802                        // Make up a new basic pass
803                        Pass* newPass = new Pass(this, p->getIndex());
804                        newPass->setAmbient(ColourValue::Black);
805                        newPass->setDiffuse(ColourValue::Black);
806
807                        // Calculate hash value for new pass, because we are compiling
808                        // illumination passes on demand, which will loss hash calculate
809                        // before it add to render queue first time.
810                        newPass->_recalculateHash();
811
812                        iPass = new IlluminationPass();
813                        iPass->destroyOnShutdown = true;
814                        iPass->originalPass = p;
815                        iPass->pass = newPass;
816                        iPass->stage = iStage;
817                        mIlluminationPasses.push_back(iPass);
818                        haveAmbient = true;
819                    }
820                    // This means we're done with ambients, progress to per-light
821                    iStage = IS_PER_LIGHT;
822                }
823                break;
824            case IS_PER_LIGHT:
825                if (p->getIteratePerLight())
826                {
827                    // If this is per-light already, use it directly
828                    iPass = new IlluminationPass();
829                    iPass->destroyOnShutdown = false;
830                    iPass->originalPass = iPass->pass = p;
831                    iPass->stage = iStage;
832                    mIlluminationPasses.push_back(iPass);
833                    // progress to next pass
834                    ++i;
835                }
836                else
837                {
838                    // Split off per-light details (can only be done for one)
839                    if (p->getLightingEnabled() &&
840                        (p->getDiffuse() != ColourValue::Black ||
841                        p->getSpecular() != ColourValue::Black))
842                    {
843                        // Copy existing pass
844                        Pass* newPass = new Pass(this, p->getIndex(), *p);
845                        if (newPass->getAlphaRejectFunction() != CMPF_ALWAYS_PASS)
846                        {
847                            // Alpha rejection passes must retain their transparency, so
848                            // we allow the texture units, but override the colour functions
849                            Pass::TextureUnitStateIterator tusi = newPass->getTextureUnitStateIterator();
850                            while (tusi.hasMoreElements())
851                            {
852                                TextureUnitState* tus = tusi.getNext();
853                                tus->setColourOperationEx(LBX_SOURCE1, LBS_CURRENT);
854                            }
855                        }
856                        else
857                        {
858                            // remove texture units
859                            newPass->removeAllTextureUnitStates();
860                        }
861                        // remove fragment programs
862                        if (newPass->hasFragmentProgram())
863                            newPass->setFragmentProgram("");
864                        // Cannot remove vertex program, have to assume that
865                        // it will process diffuse lights, ambient will be turned off
866                        newPass->setAmbient(ColourValue::Black);
867                        newPass->setSelfIllumination(ColourValue::Black);
868                        // must be additive
869                        newPass->setSceneBlending(SBF_ONE, SBF_ONE);
870
871                        // Calculate hash value for new pass, because we are compiling
872                        // illumination passes on demand, which will loss hash calculate
873                        // before it add to render queue first time.
874                        newPass->_recalculateHash();
875
876                        iPass = new IlluminationPass();
877                        iPass->destroyOnShutdown = true;
878                        iPass->originalPass = p;
879                        iPass->pass = newPass;
880                        iPass->stage = iStage;
881
882                        mIlluminationPasses.push_back(iPass);
883
884                    }
885                    // This means the end of per-light passes
886                    iStage = IS_DECAL;
887                }
888                break;
889            case IS_DECAL:
890                // We just want a 'lighting off' pass to finish off
891                // and only if there are texture units
892                if (p->getNumTextureUnitStates() > 0)
893                {
894                    if (!p->getLightingEnabled())
895                    {
896                        // we assume this pass already combines as required with the scene
897                        iPass = new IlluminationPass();
898                        iPass->destroyOnShutdown = false;
899                        iPass->originalPass = iPass->pass = p;
900                        iPass->stage = iStage;
901                        mIlluminationPasses.push_back(iPass);
902                    }
903                    else
904                    {
905                        // Copy the pass and tweak away the lighting parts
906                        Pass* newPass = new Pass(this, p->getIndex(), *p);
907                        newPass->setAmbient(ColourValue::Black);
908                        newPass->setDiffuse(0, 0, 0, newPass->getDiffuse().a);  // Preserving alpha
909                        newPass->setSpecular(ColourValue::Black);
910                        newPass->setSelfIllumination(ColourValue::Black);
911                        newPass->setLightingEnabled(false);
912                                                newPass->setIteratePerLight(false, false);
913                        // modulate
914                        newPass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO);
915
916                        // Calculate hash value for new pass, because we are compiling
917                        // illumination passes on demand, which will loss hash calculate
918                        // before it add to render queue first time.
919                        newPass->_recalculateHash();
920
921                        // NB there is nothing we can do about vertex & fragment
922                        // programs here, so people will just have to make their
923                        // programs friendly-like if they want to use this technique
924                        iPass = new IlluminationPass();
925                        iPass->destroyOnShutdown = true;
926                        iPass->originalPass = p;
927                        iPass->pass = newPass;
928                        iPass->stage = iStage;
929                        mIlluminationPasses.push_back(iPass);
930
931                    }
932                }
933                ++i; // always increment on decal, since nothing more to do with this pass
934
935                break;
936            }
937        }
938
939    }
940    //-----------------------------------------------------------------------
941    void Technique::clearIlluminationPasses(void)
942    {
943        IlluminationPassList::iterator i, iend;
944        iend = mIlluminationPasses.end();
945        for (i = mIlluminationPasses.begin(); i != iend; ++i)
946        {
947            if ((*i)->destroyOnShutdown)
948            {
949                (*i)->pass->queueForDeletion();
950            }
951            delete *i;
952        }
953        mIlluminationPasses.clear();
954    }
955    //-----------------------------------------------------------------------
956    const Technique::IlluminationPassIterator
957    Technique::getIlluminationPassIterator(void)
958    {
959        IlluminationPassesState targetState = IPS_COMPILED;
960        if (mIlluminationPassesCompilationPhase != targetState)
961        {
962            // prevents parent->_notifyNeedsRecompile() call during compile
963            mIlluminationPassesCompilationPhase = IPS_COMPILE_DISABLED;
964            // Splitting the passes into illumination passes
965            _compileIlluminationPasses();
966            // Mark that illumination passes compilation finished
967            mIlluminationPassesCompilationPhase = targetState;
968        }
969
970        return IlluminationPassIterator(mIlluminationPasses.begin(),
971            mIlluminationPasses.end());
972    }
973    //-----------------------------------------------------------------------
974        const String& Technique::getResourceGroup(void) const
975        {
976                return mParent->getGroup();
977        }
978
979    //-----------------------------------------------------------------------
980    bool Technique::applyTextureAliases(const AliasTextureNamePairList& aliasList, const bool apply) const
981    {
982        // iterate through passes and apply texture alias
983        Passes::const_iterator i, iend;
984        iend = mPasses.end();
985        bool testResult = false;
986
987        for(i = mPasses.begin(); i != iend; ++i)
988        {
989            if ((*i)->applyTextureAliases(aliasList, apply))
990                testResult = true;
991        }
992
993        return testResult;
994    }
995
996}
Note: See TracBrowser for help on using the repository browser.