/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include using namespace osg; using namespace osgUtil; class RenderBinPrototypeList : osg::depends_on, public osg::Referenced, public std::map< std::string, osg::ref_ptr > { public: RenderBinPrototypeList() { add("RenderBin",new RenderBin(RenderBin::getDefaultRenderBinSortMode())); add("StateSortedBin",new RenderBin(RenderBin::SORT_BY_STATE)); add("DepthSortedBin",new RenderBin(RenderBin::SORT_BACK_TO_FRONT)); add("SORT_BACK_TO_FRONT",new RenderBin(RenderBin::SORT_BACK_TO_FRONT)); add("SORT_FRONT_TO_BACK",new RenderBin(RenderBin::SORT_FRONT_TO_BACK)); add("TraversalOrderBin",new RenderBin(RenderBin::TRAVERSAL_ORDER)); } void add(const std::string& name, RenderBin* bin) { (*this)[name] = bin; } ~RenderBinPrototypeList() {} }; static RenderBinPrototypeList* renderBinPrototypeList() { static osg::ref_ptr s_renderBinPrototypeList = new RenderBinPrototypeList; return s_renderBinPrototypeList.get(); } // Use a proxy to force the initialization of the RenderBinPrototypeListSingleton during static initialization OSG_INIT_SINGLETON_PROXY(RenderBinSingletonProxy, renderBinPrototypeList()) RenderBin* RenderBin::getRenderBinPrototype(const std::string& binName) { RenderBinPrototypeList* list = renderBinPrototypeList(); if (list) { RenderBinPrototypeList::iterator itr = list->find(binName); if (itr != list->end()) return itr->second.get(); } return NULL; } RenderBin* RenderBin::createRenderBin(const std::string& binName) { RenderBinPrototypeList* list = renderBinPrototypeList(); if (list) { RenderBin* prototype = getRenderBinPrototype(binName); if (prototype) return dynamic_cast(prototype->clone(osg::CopyOp::DEEP_COPY_ALL)); } OSG_WARN <<"Warning: RenderBin \""<begin(); itr != list->end(); ++itr) { if (itr->second == proto) { // OSG_NOTICE<<"Found protype, now erasing "<first<erase(itr); return; } } } // OSG_NOTICE<<"Not found protype"<","SORT_BY_STATE | SORT_BY_STATE_THEN_FRONT_TO_BACK | SORT_FRONT_TO_BACK | SORT_BACK_TO_FRONT"); void RenderBin::setDefaultRenderBinSortMode(RenderBin::SortMode mode) { s_defaultBinSortModeInitialized = true; s_defaultBinSortMode = mode; } RenderBin::SortMode RenderBin::getDefaultRenderBinSortMode() { if (!s_defaultBinSortModeInitialized) { s_defaultBinSortModeInitialized = true; const char* str = getenv("OSG_DEFAULT_BIN_SORT_MODE"); if (str) { if (strcmp(str,"SORT_BY_STATE")==0) s_defaultBinSortMode = RenderBin::SORT_BY_STATE; else if (strcmp(str,"SORT_BY_STATE_THEN_FRONT_TO_BACK")==0) s_defaultBinSortMode = RenderBin::SORT_BY_STATE_THEN_FRONT_TO_BACK; else if (strcmp(str,"SORT_FRONT_TO_BACK")==0) s_defaultBinSortMode = RenderBin::SORT_FRONT_TO_BACK; else if (strcmp(str,"SORT_BACK_TO_FRONT")==0) s_defaultBinSortMode = RenderBin::SORT_BACK_TO_FRONT; else if (strcmp(str,"TRAVERSAL_ORDER")==0) s_defaultBinSortMode = RenderBin::TRAVERSAL_ORDER; } } return s_defaultBinSortMode; } RenderBin::RenderBin() { _binNum = 0; _parent = NULL; _stage = NULL; _sorted = false; _sortMode = getDefaultRenderBinSortMode(); } RenderBin::RenderBin(SortMode mode) { _binNum = 0; _parent = NULL; _stage = NULL; _sorted = false; _sortMode = mode; #if 1 if (_sortMode==SORT_BACK_TO_FRONT) { _stateset = new osg::StateSet; _stateset->setThreadSafeRefUnref(true); // set up an alphafunc by default to speed up blending operations. #ifdef OSG_GL_FIXED_FUNCTION_AVAILABLE osg::AlphaFunc* alphafunc = new osg::AlphaFunc; alphafunc->setFunction(osg::AlphaFunc::GREATER,0.0f); alphafunc->setThreadSafeRefUnref(true); _stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); #endif } #endif } RenderBin::RenderBin(const RenderBin& rhs,const CopyOp& copyop): Object(rhs,copyop), _binNum(rhs._binNum), _parent(rhs._parent), _stage(rhs._stage), _bins(rhs._bins), _stateGraphList(rhs._stateGraphList), _renderLeafList(rhs._renderLeafList), _sorted(rhs._sorted), _sortMode(rhs._sortMode), _sortCallback(rhs._sortCallback), _drawCallback(rhs._drawCallback), _stateset(rhs._stateset) { } RenderBin::~RenderBin() { } void RenderBin::reset() { _stateGraphList.clear(); _renderLeafList.clear(); _bins.clear(); _sorted = false; } void RenderBin::sort() { if (_sorted) return; for(RenderBinList::iterator itr = _bins.begin(); itr!=_bins.end(); ++itr) { itr->second->sort(); } if (_sortCallback.valid()) { _sortCallback->sortImplementation(this); } else sortImplementation(); _sorted = true; } void RenderBin::setSortMode(SortMode mode) { _sortMode = mode; } void RenderBin::sortImplementation() { switch(_sortMode) { case(SORT_BY_STATE): sortByState(); break; case(SORT_BY_STATE_THEN_FRONT_TO_BACK): sortByStateThenFrontToBack(); break; case(SORT_FRONT_TO_BACK): sortFrontToBack(); break; case(SORT_BACK_TO_FRONT): sortBackToFront(); break; case(TRAVERSAL_ORDER): sortTraversalOrder(); break; } } struct SortByStateFunctor { bool operator() (const StateGraph* lhs,const StateGraph* rhs) const { return (*(lhs->_stateset)<*(rhs->_stateset)); } }; void RenderBin::sortByState() { //OSG_NOTICE<<"sortByState()"<_minimumDistance_minimumDistance); } }; void RenderBin::sortByStateThenFrontToBack() { for(StateGraphList::iterator itr=_stateGraphList.begin(); itr!=_stateGraphList.end(); ++itr) { (*itr)->sortFrontToBack(); (*itr)->getMinimumDistance(); } std::sort(_stateGraphList.begin(),_stateGraphList.end(),StateGraphFrontToBackSortFunctor()); } struct FrontToBackSortFunctor { bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs) const { return (lhs->_depth_depth); } }; void RenderBin::sortFrontToBack() { copyLeavesFromStateGraphListToRenderLeafList(); // now sort the list into acending depth order. std::sort(_renderLeafList.begin(),_renderLeafList.end(),FrontToBackSortFunctor()); // cout << "sort front to back"<_depth_depth); } }; void RenderBin::sortBackToFront() { copyLeavesFromStateGraphListToRenderLeafList(); // now sort the list into acending depth order. std::sort(_renderLeafList.begin(),_renderLeafList.end(),BackToFrontSortFunctor()); // cout << "sort back to front"<_traversalNumber_traversalNumber); } }; void RenderBin::sortTraversalOrder() { copyLeavesFromStateGraphListToRenderLeafList(); // now sort the list into acending depth order. std::sort(_renderLeafList.begin(),_renderLeafList.end(),TraversalOrderFunctor()); } void RenderBin::copyLeavesFromStateGraphListToRenderLeafList() { _renderLeafList.clear(); int totalsize=0; StateGraphList::iterator itr; for(itr=_stateGraphList.begin(); itr!=_stateGraphList.end(); ++itr) { totalsize += (*itr)->_leaves.size(); } _renderLeafList.reserve(totalsize); bool detectedNaN = false; // first copy all the leaves from the render graphs into the leaf list. for(itr=_stateGraphList.begin(); itr!=_stateGraphList.end(); ++itr) { for(StateGraph::LeafList::iterator dw_itr = (*itr)->_leaves.begin(); dw_itr != (*itr)->_leaves.end(); ++dw_itr) { if (!osg::isNaN((*dw_itr)->_depth)) { _renderLeafList.push_back(dw_itr->get()); } else { detectedNaN = true; } } } if (detectedNaN) OSG_NOTICE<<"Warning: RenderBin::copyLeavesFromStateGraphListToRenderLeafList() detected NaN depth values, database may be corrupted."<second.get(); // create a rendering bin and insert into bin list. RenderBin* rb = RenderBin::createRenderBin(binName); if (rb) { RenderStage* rs = dynamic_cast(rb); if (rs) { rs->_binNum = binNum; rs->_parent = NULL; rs->_stage = rs; _stage->addPreRenderStage(rs); } else { rb->_binNum = binNum; rb->_parent = this; rb->_stage = _stage; _bins[binNum] = rb; } } return rb; } void RenderBin::draw(osg::RenderInfo& renderInfo,RenderLeaf*& previous) { renderInfo.pushRenderBin(this); if (_drawCallback.valid()) { _drawCallback->drawImplementation(this,renderInfo,previous); } else drawImplementation(renderInfo,previous); renderInfo.popRenderBin(); } void RenderBin::drawImplementation(osg::RenderInfo& renderInfo,RenderLeaf*& previous) { osg::State& state = *renderInfo.getState(); // OSG_NOTICE<<"begin RenderBin::drawImplementation "<_parent) : 0); if (numToPop>1) --numToPop; unsigned int insertStateSetPosition = state.getStateSetStackSize() - numToPop; if (_stateset.valid()) { state.insertStateSet(insertStateSetPosition, _stateset.get()); } // draw first set of draw bins. RenderBinList::iterator rbitr; for(rbitr = _bins.begin(); rbitr!=_bins.end() && rbitr->first<0; ++rbitr) { rbitr->second->draw(renderInfo,previous); } // draw fine grained ordering. for(RenderLeafList::iterator rlitr= _renderLeafList.begin(); rlitr!= _renderLeafList.end(); ++rlitr) { RenderLeaf* rl = *rlitr; rl->render(renderInfo,previous); previous = rl; } bool draw_forward = true; //(_sortMode!=SORT_BY_STATE) || (state.getFrameStamp()->getFrameNumber() % 2)==0; // draw coarse grained ordering. if (draw_forward) { for(StateGraphList::iterator oitr=_stateGraphList.begin(); oitr!=_stateGraphList.end(); ++oitr) { for(StateGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin(); dw_itr != (*oitr)->_leaves.end(); ++dw_itr) { RenderLeaf* rl = dw_itr->get(); rl->render(renderInfo,previous); previous = rl; } } } else { for(StateGraphList::reverse_iterator oitr=_stateGraphList.rbegin(); oitr!=_stateGraphList.rend(); ++oitr) { for(StateGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin(); dw_itr != (*oitr)->_leaves.end(); ++dw_itr) { RenderLeaf* rl = dw_itr->get(); rl->render(renderInfo,previous); previous = rl; } } } // draw post bins. for(; rbitr!=_bins.end(); ++rbitr) { rbitr->second->draw(renderInfo,previous); } if (_stateset.valid()) { state.removeStateSet(insertStateSetPosition); // state.apply(); } // OSG_NOTICE<<"end RenderBin::drawImplementation "<getDrawable(); stats.addDrawable(); // number of geosets const Geometry* geom = dw->asGeometry(); if (geom) { stats.addFastDrawable(); } if (rl->_modelview.get()) { stats.addMatrix(); // number of matrices } // then tot up the primitive types and no vertices. dw->accept(stats); // use sub-class to find the stats for each drawable statsCollected = true; } stats.addStateGraphs(_stateGraphList.size()); for(StateGraphList::const_iterator oitr=_stateGraphList.begin(); oitr!=_stateGraphList.end(); ++oitr) { for(StateGraph::LeafList::const_iterator dw_itr = (*oitr)->_leaves.begin(); dw_itr != (*oitr)->_leaves.end(); ++dw_itr) { const RenderLeaf* rl = dw_itr->get(); const Drawable* dw = rl->getDrawable(); stats.addDrawable(); // number of geosets const Geometry* geom = dw->asGeometry(); if (geom) { stats.addFastDrawable(); } if (rl->_modelview.get()) stats.addMatrix(); // number of matrices // then tot up the primitive types and no vertices. dw->accept(stats); // use sub-class to find the stats for each drawable } statsCollected = true; } // now collects stats for any subbins. for(RenderBinList::const_iterator itr = _bins.begin(); itr!=_bins.end(); ++itr) { if (itr->second->getStats(stats)) { statsCollected = true; } } return statsCollected; } unsigned int RenderBin::computeNumberOfDynamicRenderLeaves() const { unsigned int count = 0; // draw first set of draw bins. RenderBinList::const_iterator rbitr; for(rbitr = _bins.begin(); rbitr!=_bins.end() && rbitr->first<0; ++rbitr) { count += rbitr->second->computeNumberOfDynamicRenderLeaves(); } // draw fine grained ordering. for(RenderLeafList::const_iterator rlitr= _renderLeafList.begin(); rlitr!= _renderLeafList.end(); ++rlitr) { RenderLeaf* rl = *rlitr; if (rl->_dynamic) ++count; } // draw coarse grained ordering. for(StateGraphList::const_iterator oitr=_stateGraphList.begin(); oitr!=_stateGraphList.end(); ++oitr) { for(StateGraph::LeafList::const_iterator dw_itr = (*oitr)->_leaves.begin(); dw_itr != (*oitr)->_leaves.end(); ++dw_itr) { RenderLeaf* rl = dw_itr->get(); if (rl->_dynamic) ++count; } } // draw post bins. for(; rbitr!=_bins.end(); ++rbitr) { count += rbitr->second->computeNumberOfDynamicRenderLeaves(); } return count; } void RenderBin::releaseGLObjects(osg::State* state) const { if (_stateset) _stateset->releaseGLObjects(state); for(RenderBinList::const_iterator itr = _bins.begin(); itr != _bins.end(); ++itr) { itr->second->releaseGLObjects(state); } }