void ShaderGenerator::apply( osg::Geode& node ) { if ( !_active ) return; bool ignore; if ( node.getUserValue(SHADERGEN_HINT_IGNORE, ignore) && ignore ) return; osg::ref_ptr<osg::StateSet> stateset = node.getStateSet(); if ( stateset.valid() ) { _state->pushStateSet( stateset.get() ); } unsigned numDrawables = node.getNumDrawables(); bool traverseDrawables = true; // This block checks whether all the geode's drawables are equivalent, // i.e., they are the same type (geometry or text) and none of them // have their own state sets. IF that's the case, we can create a // single shader program for the entire geode. This is an optimization. if ( stateset.valid() ) { unsigned d; unsigned numInheritingText = 0, numInheritingGeometry = 0; for( d = 0; d < numDrawables; ++d ) { osg::Drawable* drawable = node.getDrawable(d); if ( drawable->getStateSet() == 0L ) { if ( drawable->asGeometry() ) numInheritingGeometry++; else if ( dynamic_cast<osgText::Text*>(drawable) ) numInheritingText++; } } if (numInheritingGeometry == numDrawables ) { osg::ref_ptr<osg::StateSet> replacement; if ( processGeometry(stateset.get(), replacement) ) { node.setStateSet(replacement.get() ); traverseDrawables = false; } } else if (numInheritingText == numDrawables ) { osg::ref_ptr<osg::StateSet> replacement; if ( processText(stateset.get(), replacement) ) { node.setStateSet(replacement.get() ); traverseDrawables = false; } } } // Drawables have state sets, so let's traverse them. if ( traverseDrawables ) { for( unsigned d = 0; d < node.getNumDrawables(); ++d ) { apply( node.getDrawable(d) ); } } if ( stateset.valid() ) { _state->popStateSet(); } }