source: OGRE/trunk/ogrenew/OgreMain/src/OgreTechnique.cpp @ 692

Revision 692, 33.8 KB checked in by mattausch, 19 years ago (diff)

adding ogre 1.2 and dependencies

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