#include #include #include #include #include #include #include #include #include #include #include #include using namespace osgUtil; //////////////////////////////////////////////////////////////////////////// // Overall Optimizetion function. //////////////////////////////////////////////////////////////////////////// void Optimizer::optimize(osg::Node* node, unsigned int options) { return; if (options & COMBINE_ADJACENT_LODS) { CombineLODsVisitor clv; node->accept(clv); clv.combineLODs(); } if (options & FLATTEN_STATIC_TRANSFORMS) { int i=0; bool result = false; do { osg::notify(osg::DEBUG_INFO) << "** RemoveStaticTransformsVisitor *** Pass "<accept(fstv); result = fstv.removeTransforms(); ++i; } while (result); } if (options & REMOVE_REDUNDENT_NODES) { RemoveEmptyNodesVisitor renv; node->accept(renv); renv.removeEmptyNodes(); RemoveRedundentNodesVisitor rrnv; node->accept(rrnv); rrnv.removeRedundentNodes(); } // convert the old style GeoSet to Geometry // ConvertGeoSetsToGeometryVisitor cgtg; // node->accept(cgtg); if (options & SHARE_DUPLICATE_STATE) { // #if (defined(_MSC_VER) && _MSC_VER<1300 && !defined(_STLPORT_VERSION)) // osg::notify(osg::NOTICE)<<"Warning: this application was built with VisualStudio 6.0's native STL,"<accept(osv); osv.optimize(); MergeGeometryVisitor mgv; node->accept(mgv); // #endif } } class TransformFunctor : public osg::Drawable::AttributeFunctor { public: osg::Matrix _m; osg::Matrix _im; TransformFunctor(const osg::Matrix& m) { _m = m; _im.invert(_m); } virtual ~TransformFunctor() {} virtual void apply(osg::Drawable::AttributeType type,unsigned int count,osg::Vec3* begin) { if (type == osg::Drawable::VERTICES) { osg::Vec3* end = begin+count; for (osg::Vec3* itr=begin;itr(geode.getDrawable(i)); if (geoset) { osg::Geometry* geom = geoset->convertToGeometry(); if (geom) { std::cout<<"Successfully converted GeoSet to Geometry"<getDataVariance()==osg::Object::STATIC) addStateSet(ss,&node); traverse(node); } void Optimizer::StateVisitor::apply(osg::Geode& geode) { osg::StateSet* ss = geode.getStateSet(); if (ss && ss->getDataVariance()==osg::Object::STATIC) addStateSet(ss,&geode); for(unsigned int i=0;igetStateSet(); if (ss && ss->getDataVariance()==osg::Object::STATIC) addStateSet(ss,drawable); } } } void Optimizer::StateVisitor::optimize() { osg::notify(osg::INFO) << "Num of StateSet="<<_statesets.size()<< std::endl; { // create map from state attributes to stateset which contain them. typedef std::pair StateSetUnitPair; typedef std::set StateSetList; typedef std::map AttributeToStateSetMap; const unsigned int NON_TEXTURE_ATTRIBUTE = 0xffffffff; AttributeToStateSetMap _attributeToStateSetMap; // NOTE will need to track state attribute override value too. for(StateSetMap::iterator sitr=_statesets.begin(); sitr!=_statesets.end(); ++sitr) { osg::StateSet::AttributeList& attributes = sitr->first->getAttributeList(); for(osg::StateSet::AttributeList::iterator aitr= attributes.begin(); aitr!=attributes.end(); ++aitr) { if (aitr->second.first->getDataVariance()==osg::Object::STATIC) { _attributeToStateSetMap[aitr->second.first.get()].insert(StateSetUnitPair(sitr->first,NON_TEXTURE_ATTRIBUTE)); } } osg::StateSet::TextureAttributeList& texAttributes = sitr->first->getTextureAttributeList(); for(unsigned int unit=0;unitsecond.first->getDataVariance()==osg::Object::STATIC) { _attributeToStateSetMap[aitr->second.first.get()].insert(StateSetUnitPair(sitr->first,unit)); } } } } if (_attributeToStateSetMap.size()<2) { osg::notify(osg::INFO) << "Too few state attributes to optimize."<< std::endl; return; } // create unique set of state attribute pointers. typedef std::vector AttributeList; AttributeList _attributeList; for(AttributeToStateSetMap::iterator aitr=_attributeToStateSetMap.begin(); aitr!=_attributeToStateSetMap.end(); ++aitr) { _attributeList.push_back(aitr->first); } // sort the attributes so that equal attributes sit along side each // other. std::sort(_attributeList.begin(),_attributeList.end(),LessAttributeFunctor()); osg::notify(osg::INFO) << "state attribute list"<< std::endl; for(AttributeList::iterator aaitr = _attributeList.begin(); aaitr!=_attributeList.end(); ++aaitr) { osg::notify(osg::INFO) << " "<<*aaitr << " "<<(*aaitr)->className()<< std::endl; } osg::notify(osg::INFO) << "searching for duplicate attributes"<< std::endl; // find the duplicates. AttributeList::iterator first_unique = _attributeList.begin(); AttributeList::iterator current = first_unique; ++current; for(; current!=_attributeList.end();++current) { if (**current==**first_unique) { osg::notify(osg::INFO) << " found duplicate "<<(*current)->className()<<" first="<<*first_unique<<" current="<<*current<< std::endl; StateSetList& statesetlist = _attributeToStateSetMap[*current]; for(StateSetList::iterator sitr=statesetlist.begin(); sitr!=statesetlist.end(); ++sitr) { osg::notify(osg::INFO) << " replace duplicate "<<*current<<" with "<<*first_unique<< std::endl; osg::StateSet* stateset = sitr->first; unsigned int unit = sitr->second; if (unit==NON_TEXTURE_ATTRIBUTE) stateset->setAttribute(*first_unique); else stateset->setTextureAttribute(unit,*first_unique); } } else first_unique = current; } } // duplicate state attributes removed. // now need to look at duplicate state sets. { // create the list of stateset's. typedef std::vector StateSetSortList; StateSetSortList _statesetSortList; for(StateSetMap::iterator ssitr=_statesets.begin(); ssitr!=_statesets.end(); ++ssitr) { _statesetSortList.push_back(ssitr->first); } // sort the StateSet's so that equal StateSet's sit along side each // other. std::sort(_statesetSortList.begin(),_statesetSortList.end(),LessStateSetFunctor()); osg::notify(osg::INFO) << "searching for duplicate attributes"<< std::endl; // find the duplicates. StateSetSortList::iterator first_unique = _statesetSortList.begin(); StateSetSortList::iterator current = first_unique; ++current; for(; current!=_statesetSortList.end();++current) { if (**current==**first_unique) { osg::notify(osg::INFO) << " found duplicate "<<(*current)->className()<<" first="<<*first_unique<<" current="<<*current<< std::endl; ObjectSet& objSet = _statesets[*current]; for(ObjectSet::iterator sitr=objSet.begin(); sitr!=objSet.end(); ++sitr) { osg::notify(osg::INFO) << " replace duplicate "<<*current<<" with "<<*first_unique<< std::endl; osg::Object* obj = *sitr; osg::Drawable* drawable = dynamic_cast(obj); if (drawable) { drawable->setStateSet(*first_unique); } else { osg::Node* node = dynamic_cast(obj); if (node) { node->setStateSet(*first_unique); } } } } else first_unique = current; } } } //////////////////////////////////////////////////////////////////////////// // Flatten static transforms //////////////////////////////////////////////////////////////////////////// class CollectLowestTransformsVisitor : public osg::NodeVisitor { public: CollectLowestTransformsVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {} virtual void apply(osg::Node& node) { if (node.getNumParents()) { traverse(node); } else { // for all current objects mark a NULL transform for them. registerWithCurrentObjects(0); } } virtual void apply(osg::LOD& lod) { _currentObjectList.push_back(&lod); traverse(lod); _currentObjectList.pop_back(); } virtual void apply(osg::Transform& transform) { // for all current objects associated this transform with them. registerWithCurrentObjects(&transform); } virtual void apply(osg::Geode& geode) { traverse(geode); } virtual void apply(osg::Billboard& geode) { traverse(geode); } void collectDataFor(osg::Billboard* billboard) { _currentObjectList.push_back(billboard); billboard->accept(*this); _currentObjectList.pop_back(); } void collectDataFor(osg::Drawable* drawable) { _currentObjectList.push_back(drawable); const osg::Drawable::ParentList& parents = drawable->getParents(); for(osg::Drawable::ParentList::const_iterator itr=parents.begin(); itr!=parents.end(); ++itr) { (*itr)->accept(*this); } _currentObjectList.pop_back(); } void setUpMaps(); void disableTransform(osg::Transform* transform); bool removeTransforms(); protected: struct TransformStruct { typedef std::set ObjectSet; TransformStruct():_canBeApplied(true) {} void add(osg::Object* obj) { _objectSet.insert(obj); } bool _canBeApplied; ObjectSet _objectSet; }; struct ObjectStruct { typedef std::set TransformSet; ObjectStruct():_canBeApplied(true),_moreThanOneMatrixRequired(false) {} void add(osg::Transform* transform) { if (transform) { if (transform->getDataVariance()==osg::Transform::DYNAMIC) _moreThanOneMatrixRequired=true; else if (transform->getReferenceFrame()==osg::Transform::RELATIVE_TO_ABSOLUTE) _moreThanOneMatrixRequired=true; else { if (_transformSet.empty()) transform->getLocalToWorldMatrix(_firstMatrix,0); else { osg::Matrix matrix; transform->getLocalToWorldMatrix(_firstMatrix,0); if (_firstMatrix!=matrix) _moreThanOneMatrixRequired=true; } } } else { if (!_transformSet.empty()) { if (_firstMatrix!=osg::Matrix::identity()) _moreThanOneMatrixRequired=true; } } _transformSet.insert(transform); } bool _canBeApplied; bool _moreThanOneMatrixRequired; osg::Matrix _firstMatrix; TransformSet _transformSet; }; void registerWithCurrentObjects(osg::Transform* transform) { for(ObjectList::iterator itr=_currentObjectList.begin(); itr!=_currentObjectList.end(); ++itr) { _objectMap[*itr].add(transform); } } typedef std::map TransformMap; typedef std::map ObjectMap; typedef std::vector ObjectList; void disableObject(osg::Object* object) { disableObject(_objectMap.find(object)); } void disableObject(ObjectMap::iterator itr); void doTransform(osg::Object* obj,osg::Matrix& matrix); TransformMap _transformMap; ObjectMap _objectMap; ObjectList _currentObjectList; }; void CollectLowestTransformsVisitor::doTransform(osg::Object* obj,osg::Matrix& matrix) { osg::Drawable* drawable = dynamic_cast(obj); if (drawable) { TransformFunctor tf(matrix); drawable->accept(tf); drawable->dirtyBound(); return; } osg::LOD* lod = dynamic_cast(obj); if (lod) { osg::Matrix matrix_no_trans = matrix; matrix_no_trans.setTrans(0.0f,0.0f,0.0f); osg::Vec3 v111(1.0f,1.0f,1.0f); osg::Vec3 new_v111 = v111*matrix_no_trans; float ratio = new_v111.length()/v111.length(); // move center point. lod->setCenter(lod->getCenter()*matrix); // adjust ranges to new scale. for(unsigned int i=0;igetNumRanges();++i) { lod->setRange(i,lod->getRange(i)*ratio); } lod->dirtyBound(); return; } osg::Billboard* billboard = dynamic_cast(obj); if (billboard) { osg::Matrix matrix_no_trans = matrix; matrix_no_trans.setTrans(0.0f,0.0f,0.0f); TransformFunctor tf(matrix_no_trans); osg::Vec3 axis = osg::Matrix::transform3x3(tf._im,billboard->getAxis()); axis.normalize(); billboard->setAxis(axis); for(unsigned int i=0;igetNumDrawables();++i) { billboard->setPos(i,billboard->getPos(i)*matrix); billboard->getDrawable(i)->accept(tf); } billboard->dirtyBound(); return; } } void CollectLowestTransformsVisitor::disableObject(ObjectMap::iterator itr) { if (itr==_objectMap.end()) { return; } if (itr->second._canBeApplied) { // we havn't been disabled yet so we need to disable, itr->second._canBeApplied = false; // and then inform everybody we have been disabled. for(ObjectStruct::TransformSet::iterator titr = itr->second._transformSet.begin(); titr != itr->second._transformSet.end(); ++titr) { disableTransform(*titr); } } } void CollectLowestTransformsVisitor::disableTransform(osg::Transform* transform) { TransformMap::iterator itr=_transformMap.find(transform); if (itr==_transformMap.end()) { return; } if (itr->second._canBeApplied) { // we havn't been disabled yet so we need to disable, itr->second._canBeApplied = false; // and then inform everybody we have been disabled. for(TransformStruct::ObjectSet::iterator oitr = itr->second._objectSet.begin(); oitr != itr->second._objectSet.end(); ++oitr) { disableObject(*oitr); } } } void CollectLowestTransformsVisitor::setUpMaps() { // create the TransformMap from the ObjectMap ObjectMap::iterator oitr; for(oitr=_objectMap.begin(); oitr!=_objectMap.end(); ++oitr) { osg::Object* object = oitr->first; ObjectStruct& os = oitr->second; for(ObjectStruct::TransformSet::iterator titr = os._transformSet.begin(); titr != os._transformSet.end(); ++titr) { _transformMap[*titr].add(object); } } // disable all the objects which have more than one matrix associated // with them, and then disable all transforms which have an object associated // them that can't be applied, and then disable all objects which have // disabled transforms associated, recursing until all disabled // associativity. for(oitr=_objectMap.begin(); oitr!=_objectMap.end(); ++oitr) { ObjectStruct& os = oitr->second; if (os._canBeApplied) { if (os._moreThanOneMatrixRequired) { disableObject(oitr); } } } } bool CollectLowestTransformsVisitor::removeTransforms() { // transform the objects that can be applied. for(ObjectMap::iterator oitr=_objectMap.begin(); oitr!=_objectMap.end(); ++oitr) { osg::Object* object = oitr->first; ObjectStruct& os = oitr->second; if (os._canBeApplied) { doTransform(object,os._firstMatrix); } } bool transformRemoved = false; // clean up the transforms. for(TransformMap::iterator titr=_transformMap.begin(); titr!=_transformMap.end(); ++titr) { if (titr->second._canBeApplied) { transformRemoved = true; osg::ref_ptr transform = titr->first; osg::ref_ptr group = osgNew osg::Group; group->setDataVariance(osg::Object::STATIC); for(unsigned int i=0;igetNumChildren();++i) { for(unsigned int j=0;jgetNumParents();++j) { group->addChild(transform->getChild(i)); } } for(int i2=transform->getNumParents()-1;i2>=0;--i2) { transform->getParent(i2)->replaceChild(transform.get(),group.get()); } } } _objectMap.clear(); _transformMap.clear(); return transformRemoved; } void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Geode& geode) { if (!_transformStack.empty()) { for(unsigned int i=0;i0) { if (geode.getNumDrawables()==0) _redundentNodeList.insert(&geode); } } void Optimizer::RemoveEmptyNodesVisitor::apply(osg::Group& group) { if (group.getNumParents()>0) { // only remove empty groups, but not empty occluders. if (group.getNumChildren()==0 && (typeid(group)==typeid(osg::Group) || dynamic_cast(&group))) { _redundentNodeList.insert(&group); } } traverse(group); } void Optimizer::RemoveEmptyNodesVisitor::removeEmptyNodes() { NodeList newEmptyGroups; // keep iterator through until scene graph is cleaned of empty nodes. while (!_redundentNodeList.empty()) { for(NodeList::iterator itr=_redundentNodeList.begin(); itr!=_redundentNodeList.end(); ++itr) { osg::Node* nodeToRemove = (*itr); // take a copy of parents list since subsequent removes will modify the original one. osg::Node::ParentList parents = nodeToRemove->getParents(); for(osg::Node::ParentList::iterator pitr=parents.begin(); pitr!=parents.end(); ++pitr) { (*pitr)->removeChild(nodeToRemove); if ((*pitr)->getNumChildren()==0) newEmptyGroups.insert(*pitr); } } _redundentNodeList.clear(); _redundentNodeList.swap(newEmptyGroups); } } //////////////////////////////////////////////////////////////////////////// // RemoveRedundentNodes. //////////////////////////////////////////////////////////////////////////// void Optimizer::RemoveRedundentNodesVisitor::apply(osg::Group& group) { if (group.getNumParents()>0) { if (group.getNumChildren()==1 && typeid(group)==typeid(osg::Group)) { if (group.getNumParents()>0 && group.getNumChildren()<=1) { if (!group.getUserData() && !group.getAppCallback() && !group.getStateSet() && group.getNodeMask()==0xffffffff) { _redundentNodeList.insert(&group); } } } } traverse(group); } void Optimizer::RemoveRedundentNodesVisitor::apply(osg::Transform& transform) { if (transform.getNumParents()>0 && transform.getDataVariance()==osg::Object::STATIC) { static osg::Matrix identity; osg::Matrix matrix; transform.getWorldToLocalMatrix(matrix,NULL); if (matrix==identity) { _redundentNodeList.insert(&transform); } } traverse(transform); } void Optimizer::RemoveRedundentNodesVisitor::removeRedundentNodes() { for(NodeList::iterator itr=_redundentNodeList.begin(); itr!=_redundentNodeList.end(); ++itr) { osg::ref_ptr group = dynamic_cast(*itr); if (group.valid()) { // take a copy of parents list since subsequent removes will modify the original one. osg::Node::ParentList parents = group->getParents(); if (group->getNumChildren()==1) { osg::Node* child = group->getChild(0); for(osg::Node::ParentList::iterator pitr=parents.begin(); pitr!=parents.end(); ++pitr) { (*pitr)->replaceChild(group.get(),child); } } } else { std::cout<<"failed dynamic_cast"< LODSet; LODSet lodChildren; for(unsigned int i=0;igetNumChildren();++i) { osg::Node* child = group->getChild(i); osg::LOD* lod = dynamic_cast(child); if (lod) { if (lod->getNumRanges()-1==lod->getNumChildren()) { lodChildren.insert(lod); } else { // wonky LOD, numRanges should = numChildren+1 } } } if (lodChildren.size()>=2) { osg::BoundingBox bb; LODSet::iterator lod_itr; for(lod_itr=lodChildren.begin(); lod_itr!=lodChildren.end(); ++lod_itr) { bb.expandBy((*lod_itr)->getCenter()); } if (bb.radius()<1e-2) { typedef std::pair RangePair; typedef std::multimap RangeMap; RangeMap rangeMap; float maxRange = 0.0f; for(lod_itr=lodChildren.begin(); lod_itr!=lodChildren.end(); ++lod_itr) { osg::LOD* lod = *lod_itr; for(unsigned int i=0;igetNumRanges()-1;++i) { if (maxRangegetRange(i+1)) maxRange = lod->getRange(i+1); rangeMap.insert(RangeMap::value_type(RangePair(lod->getRange(i),lod->getRange(i+1)),lod->getChild(i))); } } // create new LOD containing all other LOD's children. osg::LOD* newLOD = osgNew osg::LOD; newLOD->setName("newLOD"); newLOD->setCenter(bb.center()); int i=0; for(RangeMap::iterator c_itr=rangeMap.begin(); c_itr!=rangeMap.end(); ++c_itr,++i) { newLOD->setRange(i,c_itr->first.first); newLOD->addChild(c_itr->second); } newLOD->setRange(i,maxRange); // add LOD into parent. group->addChild(newLOD); // remove all the old LOD's from group. for(lod_itr=lodChildren.begin(); lod_itr!=lodChildren.end(); ++lod_itr) { group->removeChild(*lod_itr); } } } } _groupList.clear(); } //////////////////////////////////////////////////////////////////////////// // code to merge geometry object which share, state, and attribute bindings. //////////////////////////////////////////////////////////////////////////// struct LessGeometry { bool operator() (const osg::Geometry* lhs,const osg::Geometry* rhs) const { if (lhs->getStateSet()getStateSet()) return true; if (rhs->getStateSet()getStateSet()) return false; if (lhs->getColorBinding()getColorBinding()) return true; if (rhs->getColorBinding()getColorBinding()) return false; if (lhs->getNormalBinding()getNormalBinding()) return true; if (rhs->getNormalBinding()getNormalBinding()) return false; if (lhs->getNumTexCoordArrays()getNumTexCoordArrays()) return true; if (rhs->getNumTexCoordArrays()getNumTexCoordArrays()) return false; // therefore lhs->getNumTexCoordArrays()==rhs->getNumTexCoordArrays() for(unsigned int i=0;igetNumTexCoordArrays();++i) { if (rhs->getTexCoordArray(i)) { if (!lhs->getTexCoordArray(i)) return true; } else if (lhs->getTexCoordArray(i)) return false; } if (lhs->getNormalBinding()==osg::Geometry::BIND_OVERALL) { // assumes that the bindings and arrays are set up correctly, this // should be the case after running computeCorrectBindingsAndArraySizes(); const osg::Vec3& lhs_normal = (*(lhs->getNormalArray()))[0]; const osg::Vec3& rhs_normal = (*(rhs->getNormalArray()))[0]; if (lhs_normalgetColorBinding()==osg::Geometry::BIND_OVERALL) { const osg::Array* lhs_colorArray = lhs->getColorArray(); const osg::Array* rhs_colorArray = rhs->getColorArray(); if (lhs_colorArray->getType()getType()) return true; if (rhs_colorArray->getType()getType()) return false; switch(lhs_colorArray->getType()) { case(osg::Array::UByte4ArrayType): if ((*static_cast(lhs_colorArray))[0]<(*static_cast(rhs_colorArray))[0]) return true; if ((*static_cast(rhs_colorArray))[0]<(*static_cast(lhs_colorArray))[0]) return false; case(osg::Array::Vec3ArrayType): if ((*static_cast(lhs_colorArray))[0]<(*static_cast(rhs_colorArray))[0]) return true; if ((*static_cast(rhs_colorArray))[0]<(*static_cast(lhs_colorArray))[0]) return false; case(osg::Array::Vec4ArrayType): if ((*static_cast(lhs_colorArray))[0]<(*static_cast(rhs_colorArray))[0]) return true; if ((*static_cast(rhs_colorArray))[0]<(*static_cast(lhs_colorArray))[0]) return false; break; default: break; } } return false; } }; struct LessGeometryPrimitiveType { bool operator() (const osg::Geometry* lhs,const osg::Geometry* rhs) const { if (lhs->getNumPrimitives()>0) { if (rhs->getNumPrimitives()>0) { if (lhs->getPrimitive(0)->getType()getPrimitive(0)->getType()) return true; else if (rhs->getPrimitive(0)->getType()getPrimitive(0)->getType()) return false; if (lhs->getPrimitive(0)->getMode()getPrimitive(0)->getMode()) return true; else if (rhs->getPrimitive(0)->getMode()getPrimitive(0)->getMode()) return false; } return false; } else if (rhs->getNumPrimitives()>0) return true; return false; } }; bool Optimizer::MergeGeometryVisitor::mergeGeode(osg::Geode& geode) { if (geode.getNumDrawables()<2) return false; typedef std::vector DuplicateList; typedef std::map GeometryDuplicateMap; GeometryDuplicateMap geometryDuplicateMap; unsigned int i; for(i=0;i(geode.getDrawable(i)); if (geom) { geom->computeCorrectBindingsAndArraySizes(); geometryDuplicateMap[geom].push_back(geom); } } for(GeometryDuplicateMap::iterator itr=geometryDuplicateMap.begin(); itr!=geometryDuplicateMap.end(); ++itr) { if (itr->second.size()>1) { std::sort(itr->second.begin(),itr->second.end(),LessGeometryPrimitiveType()); osg::Geometry* lhs = itr->second[0]; for(DuplicateList::iterator dupItr=itr->second.begin()+1; dupItr!=itr->second.end(); ++dupItr) { osg::Geometry* rhs = *dupItr; if (mergeGeometry(*lhs,*rhs)) { geode.removeDrawable(rhs); static int co = 0; osg::notify(osg::INFO)<<"merged and removed Geometry "<<++co<(geode.getDrawable(i)); if (geom) { if (geom->getNumPrimitives()>0) { osg::Geometry::PrimitiveList& primitives = geom->getPrimitiveList(); unsigned int primNo=0; while(primNo+1getType()==rhs->getType() && lhs->getMode()==rhs->getMode()) { switch(lhs->getMode()) { case(osg::Primitive::POINTS): case(osg::Primitive::LINES): case(osg::Primitive::TRIANGLES): case(osg::Primitive::QUADS): combine = true; break; } } if (combine) { switch(lhs->getType()) { case(osg::Primitive::DrawArraysPrimitiveType): combine = mergePrimitive(*(static_cast(lhs)),*(static_cast(rhs))); break; case(osg::Primitive::DrawArrayLengthsPrimitiveType): combine = mergePrimitive(*(static_cast(lhs)),*(static_cast(rhs))); break; case(osg::Primitive::DrawElementsUBytePrimitiveType): combine = mergePrimitive(*(static_cast(lhs)),*(static_cast(rhs))); break; case(osg::Primitive::DrawElementsUShortPrimitiveType): combine = mergePrimitive(*(static_cast(lhs)),*(static_cast(rhs))); break; case(osg::Primitive::DrawElementsUIntPrimitiveType): combine = mergePrimitive(*(static_cast(lhs)),*(static_cast(rhs))); break; default: break; } } if (combine) { primitives.erase(primitives.begin()+primNo+1); } if (!combine) { primNo++; } } } } } return false; } bool Optimizer::MergeGeometryVisitor::mergeGeometry(osg::Geometry& lhs,osg::Geometry& rhs) { unsigned int base = 0; if (lhs.getVertexArray() && rhs.getVertexArray()) { base = lhs.getVertexArray()->size(); lhs.getVertexArray()->insert(lhs.getVertexArray()->end(),rhs.getVertexArray()->begin(),rhs.getVertexArray()->end()); } else if (rhs.getVertexArray()) { lhs.setVertexArray(rhs.getVertexArray()); } if (lhs.getNormalArray() && rhs.getNormalArray() && lhs.getNormalBinding()!=osg::Geometry::BIND_OVERALL) { lhs.getNormalArray()->insert(lhs.getNormalArray()->end(),rhs.getNormalArray()->begin(),rhs.getNormalArray()->end()); } else if (rhs.getNormalArray()) { lhs.setNormalArray(rhs.getNormalArray()); } if (lhs.getColorArray() && rhs.getColorArray() && lhs.getColorBinding()!=osg::Geometry::BIND_OVERALL) { // we need to add the handling of the other array types... osg::Vec4Array* col_lhs = dynamic_cast(lhs.getColorArray()); osg::Vec4Array* col_rhs = dynamic_cast(rhs.getColorArray()); if (col_lhs && col_rhs) { col_lhs->insert(col_lhs->end(),col_rhs->begin(),col_rhs->end()); } } else if (rhs.getColorArray()) { lhs.setColorArray(rhs.getColorArray()); } for(unsigned int unit=0;unit(lhs.getTexCoordArray(unit)); osg::Vec2Array* tex_rhs = dynamic_cast(rhs.getTexCoordArray(unit)); if (tex_lhs && tex_rhs) { tex_lhs->insert(tex_lhs->end(),tex_rhs->begin(),tex_rhs->end()); } } // shift the indices of the incomming primitives to account for the pre exisiting geometry. for(osg::Geometry::PrimitiveList::iterator primItr=rhs.getPrimitiveList().begin(); primItr!=rhs.getPrimitiveList().end(); ++primItr) { osg::Primitive* primitive = primItr->get(); primitive->offsetIndices(base); } lhs.getPrimitiveList().insert(lhs.getPrimitiveList().end(),rhs.getPrimitiveList().begin(),rhs.getPrimitiveList().end()); return true; } bool Optimizer::MergeGeometryVisitor::mergePrimitive(osg::DrawArrays& lhs,osg::DrawArrays& rhs) { if (lhs.getFirst()+lhs.getCount()==rhs.getFirst()) { lhs.setCount(lhs.getCount()+rhs.getCount()); return true; } return false; } bool Optimizer::MergeGeometryVisitor::mergePrimitive(osg::DrawArrayLengths& lhs,osg::DrawArrayLengths& rhs) { int lhs_count = std::accumulate(lhs.begin(),lhs.end(),0); if (lhs.getFirst()+lhs_count==rhs.getFirst()) { lhs.insert(lhs.end(),rhs.begin(),rhs.end()); return true; } return false; } bool Optimizer::MergeGeometryVisitor::mergePrimitive(osg::DrawElementsUByte& lhs,osg::DrawElementsUByte& rhs) { lhs.insert(lhs.end(),rhs.begin(),rhs.end()); return true; } bool Optimizer::MergeGeometryVisitor::mergePrimitive(osg::DrawElementsUShort& lhs,osg::DrawElementsUShort& rhs) { lhs.insert(lhs.end(),rhs.begin(),rhs.end()); return true; } bool Optimizer::MergeGeometryVisitor::mergePrimitive(osg::DrawElementsUInt& lhs,osg::DrawElementsUInt& rhs) { lhs.insert(lhs.end(),rhs.begin(),rhs.end()); return true; }