void VirtualProgram::apply( osg::State & state ) const { if( _shaderMap.empty() ) // Virtual Program works as normal Program return Program::apply( state ); // first, find and collect all the VirtualProgram attributes: ShaderMap shaderMap; const StateHack::AttributeVec* av = StateHack::GetAttributeVec( state, this ); if ( av ) { for( StateHack::AttributeVec::const_iterator i = av->begin(); i != av->end(); ++i ) { const osg::StateAttribute* sa = i->first; const VirtualProgram* vp = dynamic_cast< const VirtualProgram* >( sa ); if( vp && ( vp->_mask & _mask ) ) { for( ShaderMap::const_iterator i = vp->_shaderMap.begin(); i != vp->_shaderMap.end(); ++i ) { shaderMap[ i->first ] = i->second; } } } } // next add the local shader components to the map: for( ShaderMap::const_iterator i = _shaderMap.begin(); i != _shaderMap.end(); ++i ) shaderMap[ i->first ] = i->second; if( shaderMap.size() ) { // next, assemble a list of the shaders in the map so we can compare it: ShaderList sl; for( ShaderMap::iterator i = shaderMap.begin(); i != shaderMap.end(); ++i ) sl.push_back( i->second ); // see if there's already a program associated with this list: osg::Program* program = 0L; ProgramMap::iterator p = _programMap.find( sl ); if ( p != _programMap.end() ) { program = p->second.get(); } else { ShaderFactory* sf = osgEarth::Registry::instance()->getShaderFactory(); // build a new set of accumulated functions, to support the creation of main() const_cast<VirtualProgram*>(this)->refreshAccumulatedFunctions( state ); osg::Shader* vert_main = sf->createVertexShaderMain( _accumulatedFunctions ); const_cast<VirtualProgram*>(this)->setShader( "osgearth_vert_main", vert_main ); shaderMap[ ShaderSemantic("osgearth_vert_main", osg::Shader::VERTEX) ] = vert_main; osg::Shader* frag_main = sf->createFragmentShaderMain( _accumulatedFunctions ); const_cast<VirtualProgram*>(this)->setShader( "osgearth_frag_main", frag_main ); shaderMap[ ShaderSemantic("osgearth_frag_main", osg::Shader::FRAGMENT) ] = frag_main; // rebuild the shader list now that we've changed the shader map. sl.clear(); for( ShaderMap::iterator i = shaderMap.begin(); i != shaderMap.end(); ++i ) sl.push_back( i->second ); // Create a new program and add all our shaders. program = new osg::Program(); #if !MERGE_SHADERS for( ShaderList::iterator i = sl.begin(); i != sl.end(); ++i ) { program->addShader( i->get() ); } #else std::string strFragment; std::string strVertex; std::string strGeometry; for( ShaderList::iterator i = sl.begin(); i != sl.end(); ++i ) { if( i->get()->getType() == osg::Shader::FRAGMENT ) strFragment += i->get()->getShaderSource(); else if ( i->get()->getType() == osg::Shader::VERTEX ) strVertex += i->get()->getShaderSource(); else if ( i->get()->getType() == osg::Shader::GEOMETRY ) strGeometry += i->get()->getShaderSource(); } if( strFragment.length() > 0 ) { program->addShader( new osg::Shader( osg::Shader::FRAGMENT, strFragment ) ); } if( strVertex.length() > 0 ) { program->addShader( new osg::Shader( osg::Shader::VERTEX, strVertex ) ); } if( strGeometry.length() > 0 ) { program->addShader( new osg::Shader( osg::Shader::GEOMETRY, strGeometry ) ); } #endif // finally, cache the program so we only regenerate it when it changes. _programMap[ sl ] = program; } // finally, apply the program attribute. program->apply( state ); } else { Program::apply( state ); } }
void VirtualProgram::apply( osg::State & state ) const { if( _shaderMap.empty() ) // Virtual Program works as normal Program return Program::apply( state ); State::AttributeVec *av = &state.getAttributeVec(this); #if NOTIFICATION_MESSAGES std::ostream &os = osg::notify( osg::NOTICE ); os << "VirtualProgram cumulate Begin" << std::endl; #endif ShaderMap shaderMap; for( State::AttributeVec::iterator i = av->begin(); i != av->end(); ++i ) { const osg::StateAttribute * sa = i->first; const VirtualProgram * vp = dynamic_cast< const VirtualProgram *>( sa ); if( vp && ( vp->_mask & _mask ) ) { #if NOTIFICATION_MESSAGES if( vp->getName().empty() ) os << "VirtualProgram cumulate [ Unnamed VP ] apply" << std::endl; else os << "VirtualProgram cumulate ["<< vp->getName() << "] apply" << std::endl; #endif for( ShaderMap::const_iterator i = vp->_shaderMap.begin(); i != vp->_shaderMap.end(); ++i ) { shaderMap[ i->first ] = i->second; } } else { #if NOTIFICATION_MESSAGES os << "VirtualProgram cumulate ( not VP or mask not match ) ignored" << std::endl; #endif continue; // ignore osg::Programs } } for( ShaderMap::const_iterator i = this->_shaderMap.begin(); i != this->_shaderMap.end(); ++i ) shaderMap[ i->first ] = i->second; #if NOTIFICATION_MESSAGES os << "VirtualProgram cumulate End" << std::endl; #endif if( shaderMap.size() ) { ShaderList sl; for( ShaderMap::iterator i = shaderMap.begin(); i != shaderMap.end(); ++i ) sl.push_back( i->second ); osg::ref_ptr< osg::Program > & program = _programMap[ sl ]; if( !program.valid() ) { program = new osg::Program; #if !MERGE_SHADERS for( ShaderList::iterator i = sl.begin(); i != sl.end(); ++i ) program->addShader( i->get() ); #else std::string strFragment; std::string strVertex; std::string strGeometry; for( ShaderList::iterator i = sl.begin(); i != sl.end(); ++i ) { if( i->get()->getType() == osg::Shader::FRAGMENT ) strFragment += i->get()->getShaderSource(); else if ( i->get()->getType() == osg::Shader::VERTEX ) strVertex += i->get()->getShaderSource(); else if ( i->get()->getType() == osg::Shader::GEOMETRY ) strGeometry += i->get()->getShaderSource(); } if( strFragment.length() > 0 ) { program->addShader( new osg::Shader( osg::Shader::FRAGMENT, strFragment ) ); #if NOTIFICATION_MESSAGES os << "====VirtualProgram merged Fragment Shader:" << std::endl << strFragment << "====" << std::endl; #endif } if( strVertex.length() > 0 ) { program->addShader( new osg::Shader( osg::Shader::VERTEX, strVertex ) ); #if NOTIFICATION_MESSAGES os << "VirtualProgram merged Vertex Shader:" << std::endl << strVertex << "====" << std::endl; #endif } if( strGeometry.length() > 0 ) { program->addShader( new osg::Shader( osg::Shader::GEOMETRY, strGeometry ) ); #if NOTIFICATION_MESSAGES os << "VirtualProgram merged Geometry Shader:" << std::endl << strGeometry << "====" << std::endl; #endif } #endif } state.applyAttribute( program.get() ); } else { Program::apply( state ); } #if NOTIFICATION_MESSAGES os << "VirtualProgram Apply" << std::endl; #endif }