Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreTechnique.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 
00027 #include "OgreTechnique.h"
00028 #include "OgreMaterial.h"
00029 #include "OgrePass.h"
00030 #include "OgreRoot.h"
00031 #include "OgreRenderSystem.h"
00032 #include "OgreRenderSystemCapabilities.h"
00033 #include "OgreGpuProgramManager.h"
00034 
00035 
00036 namespace Ogre {
00037     //-----------------------------------------------------------------------------
00038     Technique::Technique(Material* parent)
00039         : mParent(parent), mIsSupported(false), mLodIndex(0)
00040     {
00041         // See above, defaults to unsupported until examined
00042     }
00043     //-----------------------------------------------------------------------------
00044     Technique::Technique(Material* parent, const Technique& oth)
00045         : mParent(parent), mLodIndex(0)
00046     {
00047         // Copy using operator=
00048         *this = oth;
00049     }
00050     //-----------------------------------------------------------------------------
00051     Technique::~Technique()
00052     {
00053         removeAllPasses();
00054         clearIlluminationPasses();
00055     }
00056     //-----------------------------------------------------------------------------
00057     bool Technique::isSupported(void) const
00058     {
00059         return mIsSupported;
00060     }
00061     //-----------------------------------------------------------------------------
00062     void Technique::_compile(bool autoManageTextureUnits)
00063     {
00064         // assume not supported
00065         mIsSupported = false;
00066         // Go through each pass, checking requirements
00067         Passes::iterator i, iend;
00068         iend = mPasses.end();
00069         for (i = mPasses.begin(); i != iend; ++i)
00070         {
00071             Pass* currPass = *i;
00072             // Check texture unit requirements
00073             size_t numTexUnitsRequested = currPass->getNumTextureUnitStates();
00074             const RenderSystemCapabilities* caps = 
00075                 Root::getSingleton().getRenderSystem()->getCapabilities();
00076             unsigned short numTexUnits = caps->getNumTextureUnits();
00077 
00078             if (currPass->hasFragmentProgram())
00079             {
00080                 // Check texture units
00081                 if (numTexUnitsRequested > numTexUnits)
00082                 {
00083                     // Can't do this one, and can't split a fragment pass
00084                     return;
00085                 }
00086                 // Check fragment program version
00087                 if (!currPass->getFragmentProgram()->isSupported())
00088                 {
00089                     // Can't do this one
00090                     return;
00091                 }
00092             }
00093             else
00094             {
00095                 // Check a few fixed-function options in texture layers
00096                 Pass::TextureUnitStateIterator texi = currPass->getTextureUnitStateIterator();
00097                 while (texi.hasMoreElements())
00098                 {
00099                     TextureUnitState* tex = texi.getNext();
00100                     // Any Cube textures? NB we make the assumption that any 
00101                     // card capable of running fragment programs can support
00102                     // cubic textures, which has to be true, surely?
00103                     if (tex->is3D() && !caps->hasCapability(RSC_CUBEMAPPING))
00104                     {
00105                         // Fail
00106                         return;
00107                     }
00108                     // Any Dot3 blending?
00109                     if (tex->getColourBlendMode().operation == LBX_DOTPRODUCT &&
00110                             !caps->hasCapability(RSC_DOT3))
00111                     {
00112                         // Fail
00113                         return;
00114                     }
00115                 }
00116                 
00117                 // We're ok on operations, now we need to check # texture units
00118                 // Keep splitting this pass so long as units requested > gpu units
00119                 while (numTexUnitsRequested > numTexUnits)
00120                 {
00121                     // chop this pass into many passes
00122                     currPass = currPass->_split(numTexUnits);
00123                     numTexUnitsRequested = currPass->getNumTextureUnitStates();
00124                 }
00125             }
00126 
00127             if (currPass->hasVertexProgram())
00128             {
00129                 // Check vertex program version
00130                 if (!currPass->getVertexProgram()->isSupported() )
00131                 {
00132                     // Can't do this one
00133                     return;
00134                 }
00135             }
00136         
00137         }
00138         // If we got this far, we're ok
00139         mIsSupported = true;
00140 
00141         // Now compile for categorised illumination, incase we need it
00142         _compileIlluminationPasses();
00143 
00144     }
00145     //-----------------------------------------------------------------------------
00146     Pass* Technique::createPass(void)
00147     {
00148         Pass* newPass = new Pass(this, static_cast<unsigned short>(mPasses.size()));
00149         mPasses.push_back(newPass);
00150         return newPass;
00151     }
00152     //-----------------------------------------------------------------------------
00153     Pass* Technique::getPass(unsigned short index)
00154     {
00155         assert(index < mPasses.size() && "Index out of bounds");
00156         return mPasses[index];
00157     }
00158     //-----------------------------------------------------------------------------
00159     unsigned short Technique::getNumPasses(void) const
00160     {
00161         return static_cast<unsigned short>(mPasses.size());
00162     }
00163     //-----------------------------------------------------------------------------
00164     void Technique::removePass(unsigned short index)
00165     {
00166         assert(index < mPasses.size() && "Index out of bounds");
00167         Passes::iterator i = mPasses.begin() + index;
00168         (*i)->queueForDeletion();
00169         mPasses.erase(i);
00170     }
00171     //-----------------------------------------------------------------------------
00172     void Technique::removeAllPasses(void)
00173     {
00174         Passes::iterator i, iend;
00175         iend = mPasses.end();
00176         for (i = mPasses.begin(); i != iend; ++i)
00177         {
00178             (*i)->queueForDeletion();
00179         }
00180         mPasses.clear();
00181     }
00182     //-----------------------------------------------------------------------------
00183     const Technique::PassIterator Technique::getPassIterator(void)
00184     {
00185         return PassIterator(mPasses.begin(), mPasses.end());
00186     }
00187     //-----------------------------------------------------------------------------
00188     Technique& Technique::operator=(const Technique& rhs)
00189     {
00190         this->mIsSupported = rhs.mIsSupported;
00191         this->mLodIndex = rhs.mLodIndex;
00192         // copy passes
00193         removeAllPasses();
00194         Passes::const_iterator i, iend;
00195         iend = rhs.mPasses.end();
00196         for (i = rhs.mPasses.begin(); i != iend; ++i)
00197         {
00198             Pass* p = new Pass(this, (*i)->getIndex(), *(*i));
00199             mPasses.push_back(p);
00200         }
00201         // recompile illumination passes
00202         _compileIlluminationPasses();
00203         return *this;
00204     }
00205     //-----------------------------------------------------------------------------
00206     bool Technique::isTransparent(void) const
00207     {
00208         if (mPasses.empty())
00209         {
00210             return false;
00211         }
00212         else
00213         {
00214             // Base decision on the transparency of the first pass
00215             return mPasses[0]->isTransparent();
00216         }
00217     }
00218     //-----------------------------------------------------------------------------
00219     void Technique::_load(void)
00220     {
00221         assert (mIsSupported && "This technique is not supported");
00222         // Load each pass
00223         Passes::iterator i, iend;
00224         iend = mPasses.end();
00225         for (i = mPasses.begin(); i != iend; ++i)
00226         {
00227             (*i)->_load();
00228         }
00229     }
00230     //-----------------------------------------------------------------------------
00231     void Technique::_unload(void)
00232     {
00233         // Unload each pass
00234         Passes::iterator i, iend;
00235         iend = mPasses.end();
00236         for (i = mPasses.begin(); i != iend; ++i)
00237         {
00238             (*i)->_unload();
00239         }
00240     }
00241     //-----------------------------------------------------------------------------
00242     bool Technique::isLoaded(void) const
00243     {
00244         return mParent->isLoaded();
00245     }
00246     //-----------------------------------------------------------------------
00247     void Technique::setAmbient(Real red, Real green, Real blue)
00248     {
00249         Passes::iterator i, iend;
00250         iend = mPasses.end();
00251         for (i = mPasses.begin(); i != iend; ++i)
00252         {
00253             (*i)->setAmbient(red, green, blue);
00254         }
00255 
00256     }
00257     //-----------------------------------------------------------------------
00258     void Technique::setAmbient(const ColourValue& ambient)
00259     {
00260         setAmbient(ambient.r, ambient.g, ambient.b);
00261     }
00262     //-----------------------------------------------------------------------
00263     void Technique::setDiffuse(Real red, Real green, Real blue)
00264     {
00265         Passes::iterator i, iend;
00266         iend = mPasses.end();
00267         for (i = mPasses.begin(); i != iend; ++i)
00268         {
00269             (*i)->setDiffuse(red, green, blue);
00270         }
00271     }
00272     //-----------------------------------------------------------------------
00273     void Technique::setDiffuse(const ColourValue& diffuse)
00274     {
00275         setDiffuse(diffuse.r, diffuse.g, diffuse.b);
00276     }
00277     //-----------------------------------------------------------------------
00278     void Technique::setSpecular(Real red, Real green, Real blue)
00279     {
00280         Passes::iterator i, iend;
00281         iend = mPasses.end();
00282         for (i = mPasses.begin(); i != iend; ++i)
00283         {
00284             (*i)->setSpecular(red, green, blue);
00285         }
00286     }
00287     //-----------------------------------------------------------------------
00288     void Technique::setSpecular(const ColourValue& specular)
00289     {
00290         setSpecular(specular.r, specular.g, specular.b);
00291     }
00292     //-----------------------------------------------------------------------
00293     void Technique::setShininess(Real val)
00294     {
00295         Passes::iterator i, iend;
00296         iend = mPasses.end();
00297         for (i = mPasses.begin(); i != iend; ++i)
00298         {
00299             (*i)->setShininess(val);
00300         }
00301     }
00302     //-----------------------------------------------------------------------
00303     void Technique::setSelfIllumination(Real red, Real green, Real blue)
00304     {
00305         Passes::iterator i, iend;
00306         iend = mPasses.end();
00307         for (i = mPasses.begin(); i != iend; ++i)
00308         {
00309             (*i)->setSelfIllumination(red, green, blue);
00310         }
00311     }
00312     //-----------------------------------------------------------------------
00313     void Technique::setSelfIllumination(const ColourValue& selfIllum)
00314     {
00315         setSelfIllumination(selfIllum.r, selfIllum.g, selfIllum.b);
00316     }
00317     //-----------------------------------------------------------------------
00318     void Technique::setDepthCheckEnabled(bool enabled)
00319     {
00320         Passes::iterator i, iend;
00321         iend = mPasses.end();
00322         for (i = mPasses.begin(); i != iend; ++i)
00323         {
00324             (*i)->setDepthCheckEnabled(enabled);
00325         }
00326     }
00327     //-----------------------------------------------------------------------
00328     void Technique::setDepthWriteEnabled(bool enabled)
00329     {
00330         Passes::iterator i, iend;
00331         iend = mPasses.end();
00332         for (i = mPasses.begin(); i != iend; ++i)
00333         {
00334             (*i)->setDepthWriteEnabled(enabled);
00335         }
00336     }
00337     //-----------------------------------------------------------------------
00338     void Technique::setDepthFunction( CompareFunction func )
00339     {
00340         Passes::iterator i, iend;
00341         iend = mPasses.end();
00342         for (i = mPasses.begin(); i != iend; ++i)
00343         {
00344             (*i)->setDepthFunction(func);
00345         }
00346     }
00347     //-----------------------------------------------------------------------
00348     void Technique::setColourWriteEnabled(bool enabled)
00349     {
00350         Passes::iterator i, iend;
00351         iend = mPasses.end();
00352         for (i = mPasses.begin(); i != iend; ++i)
00353         {
00354             (*i)->setColourWriteEnabled(enabled);
00355         }
00356     }
00357     //-----------------------------------------------------------------------
00358     void Technique::setCullingMode( CullingMode mode )
00359     {
00360         Passes::iterator i, iend;
00361         iend = mPasses.end();
00362         for (i = mPasses.begin(); i != iend; ++i)
00363         {
00364             (*i)->setCullingMode(mode);
00365         }
00366     }
00367     //-----------------------------------------------------------------------
00368     void Technique::setManualCullingMode( ManualCullingMode mode )
00369     {
00370         Passes::iterator i, iend;
00371         iend = mPasses.end();
00372         for (i = mPasses.begin(); i != iend; ++i)
00373         {
00374             (*i)->setManualCullingMode(mode);
00375         }
00376     }
00377     //-----------------------------------------------------------------------
00378     void Technique::setLightingEnabled(bool enabled)
00379     {
00380         Passes::iterator i, iend;
00381         iend = mPasses.end();
00382         for (i = mPasses.begin(); i != iend; ++i)
00383         {
00384             (*i)->setLightingEnabled(enabled);
00385         }
00386     }
00387     //-----------------------------------------------------------------------
00388     void Technique::setShadingMode( ShadeOptions mode )
00389     {
00390         Passes::iterator i, iend;
00391         iend = mPasses.end();
00392         for (i = mPasses.begin(); i != iend; ++i)
00393         {
00394             (*i)->setShadingMode(mode);
00395         }
00396     }
00397     //-----------------------------------------------------------------------
00398     void Technique::setFog(bool overrideScene, FogMode mode, const ColourValue& colour,
00399         Real expDensity, Real linearStart, Real linearEnd)
00400     {
00401         Passes::iterator i, iend;
00402         iend = mPasses.end();
00403         for (i = mPasses.begin(); i != iend; ++i)
00404         {
00405             (*i)->setFog(overrideScene, mode, colour, expDensity, linearStart, linearEnd);
00406         }
00407     }
00408     //-----------------------------------------------------------------------
00409     void Technique::setDepthBias(ushort bias)
00410     {
00411         Passes::iterator i, iend;
00412         iend = mPasses.end();
00413         for (i = mPasses.begin(); i != iend; ++i)
00414         {
00415             (*i)->setDepthBias(bias);
00416         }
00417     }
00418     //-----------------------------------------------------------------------
00419     void Technique::setTextureFiltering(TextureFilterOptions filterType)
00420     {
00421         Passes::iterator i, iend;
00422         iend = mPasses.end();
00423         for (i = mPasses.begin(); i != iend; ++i)
00424         {
00425             (*i)->setTextureFiltering(filterType);
00426         }
00427     }
00428     // --------------------------------------------------------------------
00429     void Technique::setTextureAnisotropy(unsigned int maxAniso)
00430     {
00431         Passes::iterator i, iend;
00432         iend = mPasses.end();
00433         for (i = mPasses.begin(); i != iend; ++i)
00434         {
00435             (*i)->setTextureAnisotropy(maxAniso);
00436         }
00437     }
00438     // --------------------------------------------------------------------
00439     void Technique::setSceneBlending( const SceneBlendType sbt )
00440     {
00441         Passes::iterator i, iend;
00442         iend = mPasses.end();
00443         for (i = mPasses.begin(); i != iend; ++i)
00444         {
00445             (*i)->setSceneBlending(sbt);
00446         }
00447     }
00448     // --------------------------------------------------------------------
00449     void Technique::setSceneBlending( const SceneBlendFactor sourceFactor, 
00450         const SceneBlendFactor destFactor)
00451     {
00452         Passes::iterator i, iend;
00453         iend = mPasses.end();
00454         for (i = mPasses.begin(); i != iend; ++i)
00455         {
00456             (*i)->setSceneBlending(sourceFactor, destFactor);
00457         }
00458     }
00459 
00460     //-----------------------------------------------------------------------
00461     void Technique::_notifyNeedsRecompile(void)
00462     {
00463         mParent->_notifyNeedsRecompile();
00464     }
00465     //-----------------------------------------------------------------------
00466     void Technique::setLodIndex(unsigned short index)
00467     {
00468         mLodIndex = index;
00469         _notifyNeedsRecompile();
00470     }
00471     //-----------------------------------------------------------------------
00472     void Technique::_compileIlluminationPasses(void)
00473     {
00474         clearIlluminationPasses();
00475 
00476         if (isTransparent())
00477         {
00478             // Don't need to split transparents since they are rendered separately
00479             return;
00480         }
00481 
00482         Passes::iterator i, iend;
00483         iend = mPasses.end();
00484         i = mPasses.begin();
00485         
00486         IlluminationStage iStage = IS_AMBIENT;
00487 
00488         bool haveAmbient = false;
00489         while (i != iend)
00490         {
00491             IlluminationPass* iPass;
00492             Pass* p = *i;
00493             switch(iStage)
00494             {
00495             case IS_AMBIENT:
00496                 // Keep looking for ambient only
00497                 if (p->isAmbientOnly())
00498                 {
00499                     // Add this pass wholesale
00500                     iPass = new IlluminationPass();
00501                     iPass->destroyOnShutdown = false;
00502                     iPass->originalPass = iPass->pass = p;
00503                     iPass->stage = iStage;
00504                     mIlluminationPasses.push_back(iPass);
00505                     haveAmbient = true;
00506                     // progress to next pass
00507                     ++i;
00508                 }
00509                 else
00510                 {
00511                     // Split off any ambient part
00512                     if (p->getAmbient() != ColourValue::Black ||
00513                         p->getSelfIllumination() != ColourValue::Black)
00514                     {
00515                         // Copy existing pass
00516                         Pass* newPass = new Pass(this, p->getIndex());
00517                         *newPass = *p;
00518                         // Remove any texture units
00519                         newPass->removeAllTextureUnitStates();
00520                         // Remove any fragment program
00521                         if (newPass->hasFragmentProgram())
00522                             newPass->setFragmentProgram("");
00523                         // We have to leave vertex program alone (if any) and
00524                         // just trust that the author is using light bindings, which 
00525                         // we will ensure there are none in the ambient pass
00526                         newPass->setDiffuse(ColourValue::Black);
00527                         newPass->setSpecular(ColourValue::Black);
00528 
00529                         // If ambient & emissive are zero, then no colour write
00530                         if (newPass->getAmbient() == ColourValue::Black && 
00531                             newPass->getSelfIllumination() == ColourValue::Black)
00532                         {
00533                             newPass->setColourWriteEnabled(false);
00534                         }
00535 
00536                         iPass = new IlluminationPass();
00537                         iPass->destroyOnShutdown = true;
00538                         iPass->originalPass = p;
00539                         iPass->pass = newPass;
00540                         iPass->stage = iStage;
00541 
00542                         mIlluminationPasses.push_back(iPass);
00543                         haveAmbient = true;
00544                         
00545                     }
00546                     
00547                     if (!haveAmbient)
00548                     {
00549                         // Make up a new basic pass
00550                         Pass* newPass = new Pass(this, p->getIndex());
00551                         newPass->setAmbient(ColourValue::Black);
00552                         newPass->setDiffuse(ColourValue::Black);
00553                         iPass = new IlluminationPass();
00554                         iPass->destroyOnShutdown = true;
00555                         iPass->originalPass = p;
00556                         iPass->pass = newPass;
00557                         iPass->stage = iStage;
00558                         mIlluminationPasses.push_back(iPass);
00559                         haveAmbient = true;
00560                     }
00561                     // This means we're done with ambients, progress to per-light
00562                     iStage = IS_PER_LIGHT;
00563                 }
00564                 break;
00565             case IS_PER_LIGHT:
00566                 if (p->getRunOncePerLight())
00567                 {
00568                     // If this is per-light already, use it directly
00569                     iPass = new IlluminationPass();
00570                     iPass->destroyOnShutdown = false;
00571                     iPass->originalPass = iPass->pass = p;
00572                     iPass->stage = iStage;
00573                     mIlluminationPasses.push_back(iPass);
00574                     // progress to next pass
00575                     ++i;
00576                 }
00577                 else
00578                 {
00579                     // Split off per-light details (can only be done for one)
00580                     if (p->getLightingEnabled() && 
00581                         (p->getDiffuse() != ColourValue::Black ||
00582                         p->getSpecular() != ColourValue::Black))
00583                     {
00584                         // Copy existing pass
00585                         Pass* newPass = new Pass(this, p->getIndex());
00586                         *newPass = *p;
00587                         // remove texture units
00588                         newPass->removeAllTextureUnitStates();
00589                         // remove fragment programs
00590                         if (newPass->hasFragmentProgram())
00591                             newPass->setFragmentProgram("");
00592                         // Cannot remove vertex program, have to assume that
00593                         // it will process diffuse lights, ambient will be turned off
00594                         newPass->setAmbient(ColourValue::Black);
00595                         newPass->setSelfIllumination(ColourValue::Black);
00596                         // must be additive
00597                         newPass->setSceneBlending(SBF_ONE, SBF_ONE);
00598 
00599                         iPass = new IlluminationPass();
00600                         iPass->destroyOnShutdown = true;
00601                         iPass->originalPass = p;
00602                         iPass->pass = newPass;
00603                         iPass->stage = iStage;
00604 
00605                         mIlluminationPasses.push_back(iPass);
00606 
00607                     }
00608                     // This means the end of per-light passes
00609                     iStage = IS_DECAL;
00610                 }
00611                 break;
00612             case IS_DECAL:
00613                 // We just want a 'lighting off' pass to finish off
00614                 // and only if there are texture units
00615                 if (p->getNumTextureUnitStates() > 0)
00616                 {
00617                     if (!p->getLightingEnabled())
00618                     {
00619                         // we assume this pass already combines as required with the scene
00620                         iPass = new IlluminationPass();
00621                         iPass->destroyOnShutdown = false;
00622                         iPass->originalPass = iPass->pass = p;
00623                         iPass->stage = iStage;
00624                         mIlluminationPasses.push_back(iPass);
00625                     }
00626                     else
00627                     {
00628                         // Copy the pass and tweak away the lighting parts
00629                         Pass* newPass = new Pass(this, p->getIndex());
00630                         *newPass = *p;
00631                         newPass->setAmbient(ColourValue::Black);
00632                         newPass->setDiffuse(ColourValue::Black);
00633                         newPass->setSpecular(ColourValue::Black);
00634                         newPass->setSelfIllumination(ColourValue::Black);
00635                         newPass->setLightingEnabled(false);
00636                         // modulate
00637                         newPass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO);
00638 
00639                         // NB there is nothing we can do about vertex & fragment
00640                         // programs here, so people will just have to make their
00641                         // programs friendly-like if they want to use this technique
00642                         iPass = new IlluminationPass();
00643                         iPass->destroyOnShutdown = true;
00644                         iPass->originalPass = p;
00645                         iPass->pass = newPass;
00646                         iPass->stage = iStage;
00647                         mIlluminationPasses.push_back(iPass);
00648 
00649                     }
00650                 }
00651                 ++i; // always increment on decal, since nothing more to do with this pass
00652 
00653                 break;
00654             }
00655         }
00656 
00657     }
00658     //-----------------------------------------------------------------------
00659     void Technique::clearIlluminationPasses(void)
00660     {
00661         IlluminationPassList::iterator i, iend;
00662         iend = mIlluminationPasses.end();
00663         for (i = mIlluminationPasses.begin(); i != iend; ++i)
00664         {
00665             if ((*i)->destroyOnShutdown)
00666             {
00667                 (*i)->pass->queueForDeletion();
00668             }
00669             delete *i;
00670         }
00671         mIlluminationPasses.clear();
00672     }
00673     //-----------------------------------------------------------------------
00674     const Technique::IlluminationPassIterator 
00675     Technique::getIlluminationPassIterator(void)
00676     {
00677         return IlluminationPassIterator(mIlluminationPasses.begin(), 
00678             mIlluminationPasses.end());
00679     }
00680 
00681 
00682 }

Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:50 2004