Beispiel #1
0
void ShaderProgram::unload() {
	if (!program) { return; }

	// Detach and delete shaders
	for (ShaderList::iterator iter = shaders.begin();
		 iter != shaders.end();
		 iter++) {
		iter->unload(program);
	}

	// Delete the shader program
	glDeleteProgram(program);
	program = 0;
}
Beispiel #2
0
void ShaderProgram::load() {
	// If we have a program, clear it out.
	if (program) { unload(); }

	// Make sure we clean up if an exception is thrown.
	try {
		// Create the program object
		program = glCreateProgram();
		if (!program) {
			// TODO: throw better exception!
			throw false;
		}

		// Loop over each shader, loading and compiling it.
		for (ShaderList::iterator iter = shaders.begin();
			 iter != shaders.end();
			 iter++) {
			iter->load(program);
		}

		// Link shaders
		glLinkProgram(program);

		// Check for linker errors
		GLint status;
		glGetProgramiv(program, GL_LINK_STATUS, &status);
		if (status != GL_TRUE) {
			GLint logLength = 0, maxLength;
			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
			char* log = new char[maxLength];
			glGetProgramInfoLog(program, maxLength, &logLength, log);
		
			if (logLength > 0) {
				fl_alert("Failed to link the shader:\n%s", log);
			} else {
				fl_alert("Failed to link the shader - no explanation.");
			}

			delete log;
			throw false;
		}
	} catch (...) {
		// Destroy the program and all attached shaders
		unload();

		// Rethrow the exception
		throw;
	}
}
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 );
    }
}
Beispiel #4
0
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

}