OpenWalnut  1.4.0
WGEShader.h
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #ifndef WGESHADER_H
00026 #define WGESHADER_H
00027 
00028 #include <map>
00029 #include <string>
00030 
00031 #include <boost/filesystem.hpp>
00032 #include <boost/signals2/signal.hpp>
00033 
00034 #include <osg/NodeCallback>
00035 #include <osg/Program>
00036 #include <osg/Shader>
00037 
00038 #include "../../common/WPathHelper.h"
00039 #include "../../common/WSharedAssociativeContainer.h"
00040 
00041 #include "WGEShaderDefine.h"
00042 #include "WGEShaderPreprocessor.h"
00043 
00044 /**
00045  * Class encapsulating the OSG Program class for a more convenient way of adding and modifying shader.
00046  */
00047 class WGEShader: public osg::Program
00048 {
00049 public:
00050     /**
00051      * Convenience typedef for an osg::ref_ptr
00052      */
00053     typedef osg::ref_ptr< WGEShader > RefPtr;
00054 
00055     /**
00056      * Convenience typedef for an osg::ref_ptr; const
00057      */
00058     typedef osg::ref_ptr< const WGEShader > ConstRefPtr;
00059 
00060     /**
00061      * Default constructor. Loads the specified shader programs. The path that can be specified is optional but allows modules to load their own
00062      * local shaders. The search order for shader files is as follows: 1. search, 2. search/shaders, 3. WPathHelper::getShaderPath()
00063      *
00064      * \param name the name of the shader. It gets searched in the shader path.
00065      * \param search the local search path. If not specified, the global shader path is used.
00066      */
00067     WGEShader( std::string name, boost::filesystem::path search = WPathHelper::getShaderPath() );
00068 
00069     /**
00070      * Destructor.
00071      */
00072     virtual ~WGEShader();
00073 
00074     /**
00075      * Apply this shader to the specified node. Use this method to ensure, that reload events can be handled properly during the
00076      * update cycle.
00077      *
00078      * \param node the node where the program should be registered to.
00079      */
00080     virtual void apply( osg::ref_ptr< osg::Node > node );
00081 
00082     /**
00083      * If enabled, activate our program in the GL pipeline, performing any rebuild operations that might be pending. In addition to the standard
00084      * OSG functionality, it also loads/reloads the shader source from file.
00085      *
00086      * \param state the state to apply the shader program to.
00087      */
00088     virtual void applyDirect( osg::State& state );  // NOLINT <- ensure this matches the official OSG API by using a non-const ref
00089 
00090     /**
00091      * Removes the shader from the specified node.
00092      *
00093      * \param node the node where the program is registered to.
00094      */
00095     virtual void deactivate( osg::ref_ptr< osg::Node > node );
00096 
00097     /**
00098      * Initiate a reload of the shader during the next update cycle.
00099      */
00100     virtual void reload();
00101 
00102     /**
00103      * Sets a define which is include into the shader source code. This allows the preprocessor to turn on/off several parts of your code. In GLSL
00104      * defines are a better choice when compared with a lot of branches (if-statements).
00105      *
00106      * \param key The name of the define
00107      * \param value The value of the define. If this is not specified, the define can be used as simple ifdef switch.
00108      *
00109      * \return the define object allowing later control
00110      */
00111     template < typename T >
00112     typename WGEShaderDefine< T >::SPtr setDefine( std::string key, T value );
00113 
00114     /**
00115      * Sets a define which is include into the shader source code. This allows the preprocessor to turn on/off several parts of your code. In GLSL
00116      * defines are a better choice when compared with a lot of branches (if-statements).
00117      *
00118      * \param key The name of the define
00119      *
00120      * \return the switch allowing to control the define
00121      */
00122     WGEShaderDefineSwitch::SPtr setDefine( std::string key );
00123 
00124     /**
00125      * Adds the specified preprocessor to this shader. The preprocessor is able to force shader reloads.
00126      *
00127      * \param preproc the preprocessor to add.
00128      */
00129     void addPreprocessor( WGEShaderPreprocessor::SPtr preproc );
00130 
00131     /**
00132      * Removes the specified preprocessor. Changes inside the preprocessor won't cause any updates anymore.
00133      *
00134      * \param preproc the preprocessor to remove. If not exists: nothing is done.
00135      */
00136     void removePreprocessor( WGEShaderPreprocessor::SPtr preproc );
00137 
00138     /**
00139      * Removes all preprocessors. Be careful with this one since it removes the WGESHaderVersionPreprocessor too, which is mandatory.
00140      */
00141     void clearPreprocessors();
00142 
00143 protected:
00144     /**
00145      * This method searches and processes all includes in the shader source. The filenames in the include statement are assumed to
00146      * be relative to this shader's path. It simply unrolls the code.
00147      *
00148      * \param filename the filename of the shader to process.
00149      * \param optional denotes whether a "file not found" is critical or not
00150      * \param level the inclusion level. This is used to avoid cycles.
00151      *
00152      * \return the processed source.
00153      */
00154     std::string processShaderRecursive( const std::string filename, bool optional = false, int level = 0 );
00155 
00156     /**
00157      * This method searches and processes all includes in the shader source. The filenames in the include statement are assumed to
00158      * be relative to this shader's path. It additionally applies preprocessors.
00159      *
00160      * \see processShaderRecursive
00161      *
00162      * \param filename the filename of the shader to process.
00163      * \param optional denotes whether a "file not found" is critical or not
00164      *
00165      * \return the processed source.
00166      */
00167     std::string processShader( const std::string filename, bool optional = false );
00168 
00169     /**
00170      * This completely reloads the shader file and processes it. It also resets m_reload to false.
00171      */
00172     void reloadShader();
00173 
00174     /**
00175      * Handles all state changes in m_reload and m_deactivated. It ensure that the shader programs are bound properly or deactivated.
00176      */
00177     void updatePrograms();
00178 
00179     /**
00180      * String that stores the location of all shader files
00181      */
00182     boost::filesystem::path m_shaderPath;
00183 
00184     /**
00185      * The name of the shader. It is used to construct the actual filename to load.
00186      */
00187     std::string m_name;
00188 
00189     /**
00190      * Flag denoting whether a shader should be reloaded.
00191      */
00192     bool m_reload;
00193 
00194     /**
00195      * True if the shaders have been loaded successfully previously.
00196      */
00197     bool m_shaderLoaded;
00198 
00199     /**
00200      * Flag denoting whether a shader should be deactivated.
00201      */
00202     bool m_deactivated;
00203 
00204     /**
00205      * Connection object to the reload signal from WGraphbicsEngine.
00206      */
00207     boost::signals2::connection m_reloadSignalConnection;
00208 
00209     /**
00210      * The list of preprocessors - Type
00211      */
00212     typedef WSharedAssociativeContainer< std::map< WGEShaderPreprocessor::SPtr, boost::signals2::connection > > PreprocessorsList;
00213 
00214     /**
00215      * List of all pre-processing that need to be applied to this shader instance
00216      */
00217     PreprocessorsList m_preprocessors;
00218 
00219     /**
00220      * This preprocessor needs to be run LAST. It handles version-statements in GLSL.
00221      */
00222     WGEShaderPreprocessor::SPtr m_versionPreprocessor;
00223 
00224     /**
00225      * the vertex shader object
00226      */
00227     osg::ref_ptr< osg::Shader > m_vertexShader;
00228 
00229     /**
00230      * the fragment shader object
00231      */
00232     osg::ref_ptr< osg::Shader > m_fragmentShader;
00233 
00234     /**
00235      * the geometry shader object
00236      */
00237     osg::ref_ptr< osg::Shader > m_geometryShader;
00238 
00239     /**
00240      * Update callback which handles the shader reloading.
00241      * This ensures thread safe modification of the osg node.
00242      */
00243     class SafeUpdaterCallback : public osg::NodeCallback
00244     {
00245     public:
00246         /**
00247          * Constructor. Creates a new callback.
00248          *
00249          * \param shader the shader which needs to be updated.
00250          */
00251         explicit SafeUpdaterCallback( WGEShader* shader );
00252 
00253         /**
00254          * Callback method called by the NodeVisitor when visiting a node.
00255          * This inserts and removes enqueued nodes from this group node instance.
00256          *
00257          * \param node the node calling this update
00258          * \param nv The node visitor which performs the traversal. Should be an
00259          * update visitor.
00260          */
00261         virtual void operator()( osg::Node* node, osg::NodeVisitor* nv );
00262 
00263     protected:
00264         /**
00265          * The shader belonging to the node currently getting updated.
00266          */
00267         WGEShader* m_shader;
00268     };
00269 
00270 private:
00271 };
00272 
00273 template < typename T >
00274 typename WGEShaderDefine< T >::SPtr WGEShader::setDefine( std::string key, T value )
00275 {
00276     typename WGEShaderDefine< T >::SPtr def;
00277 
00278     // try to find the define. If it exists, set it. If not, add it.
00279     PreprocessorsList::ReadTicket r = m_preprocessors.getReadTicket();
00280     for( PreprocessorsList::ConstIterator pp = r->get().begin(); pp != r->get().end(); ++pp )
00281     {
00282         typename WGEShaderDefine< T >::SPtr define = boost::dynamic_pointer_cast< WGEShaderDefine< T > >( ( *pp ).first );
00283         if( define && ( define->getName() == key ) )
00284         {
00285             define->setValue( value );
00286             def = define;
00287             break;
00288         }
00289     }
00290     r.reset();
00291 
00292     // did not find it. Add.
00293     if( !def )
00294     {
00295         def = typename WGEShaderDefine< T >::SPtr( new WGEShaderDefine< T >( key, value ) );
00296         addPreprocessor( def );
00297     }
00298     return def;
00299 }
00300 
00301 #endif  // WGESHADER_H
00302