OpenWalnut
1.4.0
|
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