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