/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2005 The OGRE Team Also see acknowledgements in Readme.html This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt. ----------------------------------------------------------------------------- */ #include "OgreStableHeaders.h" #include "OgreRenderQueueSortingGrouping.h" namespace Ogre { //----------------------------------------------------------------------- void RenderPriorityGroup::destroySolidPassMap(SolidRenderablePassMap& passmap) { // destroy all the pass map entries SolidRenderablePassMap::iterator i, iend; iend = passmap.end(); for (i = passmap.begin(); i != iend; ++i) { // Free the list associated with this pass delete i->second; } passmap.clear(); } //----------------------------------------------------------------------- void RenderPriorityGroup::removeSolidPassEntry(Pass* p) { SolidRenderablePassMap::iterator i; i = mSolidPasses.find(p); if (i != mSolidPasses.end()) { // free memory delete i->second; // erase from map mSolidPasses.erase(i); } i = mSolidPassesDiffuseSpecular.find(p); if (i != mSolidPassesDiffuseSpecular.end()) { // free memory delete i->second; // erase from map mSolidPassesDiffuseSpecular.erase(i); } i = mSolidPassesDecal.find(p); if (i != mSolidPassesDecal.end()) { // free memory delete i->second; // erase from map mSolidPassesDecal.erase(i); } i = mSolidPassesNoShadow.find(p); if (i != mSolidPassesNoShadow.end()) { // free memory delete i->second; // erase from map mSolidPassesNoShadow.erase(i); } } //----------------------------------------------------------------------- void RenderPriorityGroup::clearSolidPassMap(SolidRenderablePassMap& passmap) { SolidRenderablePassMap::iterator i, iend; iend = passmap.end(); for (i = passmap.begin(); i != iend; ++i) { // Clear the list associated with this pass, but leave the pass entry i->second->clear(); } } //----------------------------------------------------------------------- void RenderPriorityGroup::addRenderable(Renderable* rend) { // Check material & technique supplied (the former since the default implementation // of getTechnique is based on it for backwards compatibility Technique* pTech; if(rend->getMaterial().isNull() || !rend->getTechnique()) { // Use default base white MaterialPtr baseWhite = MaterialManager::getSingleton().getByName("BaseWhite"); pTech = baseWhite->getTechnique(0); } else { // Get technique pTech = rend->getTechnique(); } // Transparent and depth settings mean depth sorting is required? if (pTech->isTransparent() && !(pTech->isDepthWriteEnabled() && pTech->isDepthCheckEnabled()) ) { addTransparentRenderable(pTech, rend); } else { if (mSplitNoShadowPasses && !pTech->getParent()->getReceiveShadows()) { // Add solid renderable and add passes to no-shadow group addSolidRenderable(pTech, rend, true); } else { if (mSplitPassesByLightingType) { addSolidRenderableSplitByLightType(pTech, rend); } else { addSolidRenderable(pTech, rend, false); } } } } //----------------------------------------------------------------------- void RenderPriorityGroup::addSolidRenderable(Technique* pTech, Renderable* rend, bool addToNoShadow) { Technique::PassIterator pi = pTech->getPassIterator(); SolidRenderablePassMap* passMap; if (addToNoShadow) { passMap = &mSolidPassesNoShadow; } else { passMap = &mSolidPasses; } while (pi.hasMoreElements()) { // Insert into solid list Pass* p = pi.getNext(); SolidRenderablePassMap::iterator i = passMap->find(p); if (i == passMap->end()) { std::pair retPair; // Create new pass entry, build a new list // Note that this pass and list are never destroyed until the engine // shuts down, although the lists will be cleared retPair = passMap->insert( SolidRenderablePassMap::value_type(p, new RenderableList() ) ); assert(retPair.second && "Error inserting new pass entry into SolidRenderablePassMap"); i = retPair.first; } // Insert renderable i->second->push_back(rend); } } //----------------------------------------------------------------------- void RenderPriorityGroup::addSolidRenderableSplitByLightType(Technique* pTech, Renderable* rend) { // Divide the passes into the 3 categories Technique::IlluminationPassIterator pi = pTech->getIlluminationPassIterator(); while (pi.hasMoreElements()) { // Insert into solid list IlluminationPass* p = pi.getNext(); SolidRenderablePassMap* passMap; switch(p->stage) { case IS_AMBIENT: passMap = &mSolidPasses; break; case IS_PER_LIGHT: passMap = &mSolidPassesDiffuseSpecular; break; case IS_DECAL: passMap = &mSolidPassesDecal; break; }; SolidRenderablePassMap::iterator i = passMap->find(p->pass); if (i == passMap->end()) { std::pair retPair; // Create new pass entry, build a new list // Note that this pass and list are never destroyed until the engine // shuts down, although the lists will be cleared retPair = passMap->insert( SolidRenderablePassMap::value_type(p->pass, new RenderableList() ) ); assert(retPair.second && "Error inserting new pass entry into SolidRenderablePassMap"); i = retPair.first; } // Insert renderable i->second->push_back(rend); } } //----------------------------------------------------------------------- void RenderPriorityGroup::addTransparentRenderable(Technique* pTech, Renderable* rend) { Technique::PassIterator pi = pTech->getPassIterator(); while (pi.hasMoreElements()) { // Insert into transparent list mTransparentPasses.push_back(RenderablePass(rend, pi.getNext())); } } //----------------------------------------------------------------------- void RenderPriorityGroup::sort(const Camera* cam) { TransparentQueueItemLess transFunctor; transFunctor.camera = cam; std::stable_sort(mTransparentPasses.begin(), mTransparentPasses.end(), transFunctor); } //----------------------------------------------------------------------- void RenderPriorityGroup::clear(void) { SolidRenderablePassMap::iterator i, iend; // Delete queue groups which are using passes which are to be // deleted, we won't need these any more and they clutter up // the list and can cause problems with future clones const Pass::PassSet& graveyardList = Pass::getPassGraveyard(); Pass::PassSet::const_iterator gi, giend; giend = graveyardList.end(); for (gi = graveyardList.begin(); gi != giend; ++gi) { removeSolidPassEntry(*gi); } // Now remove any dirty passes, these will have their hashes recalculated // by the parent queue after all groups have been processed // If we don't do this, the std::map will become inconsistent for new insterts const Pass::PassSet& dirtyList = Pass::getDirtyHashList(); Pass::PassSet::const_iterator di, diend; diend = dirtyList.end(); for (di = dirtyList.begin(); di != diend; ++di) { removeSolidPassEntry(*di); } // NB we do NOT clear the graveyard or the dirty list here, because // it needs to be acted on for all groups, the parent queue takes // care of this afterwards // We do not clear the unchanged solid pass maps, only the contents of each list // This is because we assume passes are reused a lot and it saves resorting clearSolidPassMap(mSolidPasses); clearSolidPassMap(mSolidPassesDecal); clearSolidPassMap(mSolidPassesDiffuseSpecular); clearSolidPassMap(mSolidPassesNoShadow); // Always empty the transparents list mTransparentPasses.clear(); } #ifdef GTP_VISIBILITY_MODIFIED_OGRE //----------------------------------------------------------------------- void RenderPriorityGroup::clear(const int leavePassesInQueue) { //-- standard method if no passes are left in queue if (leavePassesInQueue == 0) { clear(); return; } // We do not clear the unchanged solid pass maps, only the contents of each list // This is because we assume passes are reused a lot and it saves resorting if (!(leavePassesInQueue & SOLID_PASSES)) destroySolidPassMap(mSolidPasses); if (!(leavePassesInQueue & SOLID_PASSES_DECAL)) destroySolidPassMap(mSolidPassesDecal); if (!(leavePassesInQueue & SOLID_PASSES_DIFFUSE_SPECULAR)) destroySolidPassMap(mSolidPassesDiffuseSpecular); if (!(leavePassesInQueue & SOLID_PASSES_NOSHADOW)) destroySolidPassMap(mSolidPassesNoShadow); if (!(leavePassesInQueue & TRANSPARENT_PASSES)) mTransparentPasses.clear(); } //----------------------------------------------------------------------- void RenderPriorityGroup::destroyPassMaps(const int leavePassesInQueue) { /* const Pass::PassSet& graveyardList = Pass::getPassGraveyard(); Pass::PassSet::const_iterator gi, giend; giend = graveyardList.end(); for (gi = graveyardList.begin(); gi != giend; ++gi) { removeSolidPassEntry(*gi); } const Pass::PassSet& dirtyList = Pass::getDirtyHashList(); Pass::PassSet::const_iterator di, diend; diend = dirtyList.end(); for (di = dirtyList.begin(); di != diend; ++di) { removeSolidPassEntry(*di); } */ // We do not clear the unchanged solid pass maps, only the contents of each list // This is because we assume passes are reused a lot and it saves resorting if (!(leavePassesInQueue & SOLID_PASSES)) destroySolidPassMap(mSolidPasses); if (!(leavePassesInQueue & SOLID_PASSES_DECAL)) destroySolidPassMap(mSolidPassesDecal); if (!(leavePassesInQueue & SOLID_PASSES_DIFFUSE_SPECULAR)) destroySolidPassMap(mSolidPassesDiffuseSpecular); if (!(leavePassesInQueue & SOLID_PASSES_NOSHADOW)) destroySolidPassMap(mSolidPassesNoShadow); } #endif // GTP_VISIBILITY_MODIFIED_OGRE //----------------------------------------------------------------------- }