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