OpenWalnut  1.2.5
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
WGEShader.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WGESHADER_H
26 #define WGESHADER_H
27 
28 #include <list>
29 #include <map>
30 #include <string>
31 
32 // Use filesystem version 2 for compatibility with newer boost versions.
33 #ifndef BOOST_FILESYSTEM_VERSION
34  #define BOOST_FILESYSTEM_VERSION 2
35 #endif
36 #include <boost/filesystem.hpp>
37 #include <boost/signals2/signal.hpp>
38 
39 #include <osg/NodeCallback>
40 #include <osg/Program>
41 #include <osg/Shader>
42 
43 #include "../../common/WPathHelper.h"
44 #include "../../common/WSharedAssociativeContainer.h"
45 #include "../WExportWGE.h"
46 #include "WGEShaderDefine.h"
47 #include "WGEShaderPreprocessor.h"
48 
49 /**
50  * Class encapsulating the OSG Program class for a more convenient way of adding and modifying shader.
51  */
52 class WGE_EXPORT WGEShader: public osg::Program
53 {
54 public:
55  /**
56  * Convenience typedef for an osg::ref_ptr
57  */
58  typedef osg::ref_ptr< WGEShader > RefPtr;
59 
60  /**
61  * Convenience typedef for an osg::ref_ptr; const
62  */
63  typedef osg::ref_ptr< const WGEShader > ConstRefPtr;
64 
65  /**
66  * Default constructor. Loads the specified shader programs. The path that can be specified is optional but allows modules to load their own
67  * local shaders. The search order for shader files is as follows: 1. search, 2. search/shaders, 3. WPathHelper::getShaderPath()
68  *
69  * \param name the name of the shader. It gets searched in the shader path.
70  * \param search the local search path. If not specified, the global shader path is used.
71  */
72  WGEShader( std::string name, boost::filesystem::path search = WPathHelper::getShaderPath() );
73 
74  /**
75  * Destructor.
76  */
77  virtual ~WGEShader();
78 
79  /**
80  * Apply this shader to the specified node. Use this method to ensure, that reload events can be handled properly during the
81  * update cycle.
82  *
83  * \param node the node where the program should be registered to.
84  */
85  virtual void apply( osg::ref_ptr< osg::Node > node );
86 
87  /**
88  * If enabled, activate our program in the GL pipeline, performing any rebuild operations that might be pending. In addition to the standard
89  * OSG functionality, it also loads/reloads the shader source from file.
90  *
91  * \param state the state to apply the shader program to.
92  */
93  virtual void applyDirect( osg::State& state ); // NOLINT <- ensure this matches the official OSG API by using a non-const ref
94 
95  /**
96  * Removes the shader from the specified node.
97  *
98  * \param node the node where the program is registered to.
99  */
100  virtual void deactivate( osg::ref_ptr< osg::Node > node );
101 
102  /**
103  * Initiate a reload of the shader during the next update cycle.
104  */
105  virtual void reload();
106 
107  /**
108  * 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
109  * defines are a better choice when compared with a lot of branches (if-statements).
110  *
111  * \param key The name of the define
112  * \param value The value of the define. If this is not specified, the define can be used as simple ifdef switch.
113  *
114  * \return the define object allowing later control
115  */
116  template < typename T >
117  typename WGEShaderDefine< T >::SPtr setDefine( std::string key, T value );
118 
119  /**
120  * 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
121  * defines are a better choice when compared with a lot of branches (if-statements).
122  *
123  * \param key The name of the define
124  *
125  * \return the switch allowing to control the define
126  */
127  WGEShaderDefineSwitch::SPtr setDefine( std::string key );
128 
129  /**
130  * Adds the specified preprocessor to this shader. The preprocessor is able to force shader reloads.
131  *
132  * \param preproc the preprocessor to add.
133  */
134  void addPreprocessor( WGEShaderPreprocessor::SPtr preproc );
135 
136  /**
137  * Removes the specified preprocessor. Changes inside the preprocessor won't cause any updates anymore.
138  *
139  * \param preproc the preprocessor to remove. If not exists: nothing is done.
140  */
141  void removePreprocessor( WGEShaderPreprocessor::SPtr preproc );
142 
143  /**
144  * Removes all preprocessors. Be careful with this one since it removes the WGESHaderVersionPreprocessor too, which is mandatory.
145  */
146  void clearPreprocessors();
147 
148 protected:
149 
150  /**
151  * This method searches and processes all includes in the shader source. The filenames in the include statement are assumed to
152  * be relative to this shader's path. It simply unrolls the code.
153  *
154  * \param filename the filename of the shader to process.
155  * \param optional denotes whether a "file not found" is critical or not
156  * \param level the inclusion level. This is used to avoid cycles.
157  *
158  * \return the processed source.
159  */
160  std::string processShaderRecursive( const std::string filename, bool optional = false, int level = 0 );
161 
162  /**
163  * This method searches and processes all includes in the shader source. The filenames in the include statement are assumed to
164  * be relative to this shader's path. It additionally applies preprocessors.
165  *
166  * \see processShaderRecursive
167  *
168  * \param filename the filename of the shader to process.
169  * \param optional denotes whether a "file not found" is critical or not
170  *
171  * \return the processed source.
172  */
173  std::string processShader( const std::string filename, bool optional = false );
174 
175  /**
176  * This completely reloads the shader file and processes it. It also resets m_reload to false.
177  */
178  void reloadShader();
179 
180  /**
181  * Handles all state changes in m_reload and m_deactivated. It ensure that the shader programs are bound properly or deactivated.
182  */
183  void updatePrograms();
184 
185  /**
186  * String that stores the location of all shader files
187  */
188  boost::filesystem::path m_shaderPath;
189 
190  /**
191  * The name of the shader. It is used to construct the actual filename to load.
192  */
193  std::string m_name;
194 
195  /**
196  * Flag denoting whether a shader should be reloaded.
197  */
198  bool m_reload;
199 
200  /**
201  * True if the shaders have been loaded successfully previously.
202  */
204 
205  /**
206  * Flag denoting whether a shader should be deactivated.
207  */
209 
210  /**
211  * Connection object to the reload signal from WGraphbicsEngine.
212  */
213  boost::signals2::connection m_reloadSignalConnection;
214 
215  /**
216  * The list of preprocessors - Type
217  */
219 
220  /**
221  * List of all pre-processing that need to be applied to this shader instance
222  */
224 
225  /**
226  * This preprocessor needs to be run LAST. It handles version-statements in GLSL.
227  */
229 
230  /**
231  * the vertex shader object
232  */
233  osg::ref_ptr< osg::Shader > m_vertexShader;
234 
235  /**
236  * the fragment shader object
237  */
238  osg::ref_ptr< osg::Shader > m_fragmentShader;
239 
240  /**
241  * the geometry shader object
242  */
243  osg::ref_ptr< osg::Shader > m_geometryShader;
244 
245  /**
246  * Update callback which handles the shader reloading.
247  * This ensures thread safe modification of the osg node.
248  */
249  class SafeUpdaterCallback : public osg::NodeCallback
250  {
251  public:
252  /**
253  * Constructor. Creates a new callback.
254  *
255  * \param shader the shader which needs to be updated.
256  */
257  explicit SafeUpdaterCallback( WGEShader* shader );
258 
259  /**
260  * Callback method called by the NodeVisitor when visiting a node.
261  * This inserts and removes enqueued nodes from this group node instance.
262  *
263  * \param node the node calling this update
264  * \param nv The node visitor which performs the traversal. Should be an
265  * update visitor.
266  */
267  virtual void operator()( osg::Node* node, osg::NodeVisitor* nv );
268 
269  protected:
270 
271  /**
272  * The shader belonging to the node currently getting updated.
273  */
275  };
276 
277 private:
278 };
279 
280 template < typename T >
281 typename WGEShaderDefine< T >::SPtr WGEShader::setDefine( std::string key, T value )
282 {
283  typename WGEShaderDefine< T >::SPtr def;
284 
285  // try to find the define. If it exists, set it. If not, add it.
287  for( PreprocessorsList::ConstIterator pp = r->get().begin(); pp != r->get().end(); ++pp )
288  {
289  typename WGEShaderDefine< T >::SPtr define = boost::shared_dynamic_cast< WGEShaderDefine< T > >( ( *pp ).first );
290  if( define && ( define->getName() == key ) )
291  {
292  define->setValue( value );
293  def = define;
294  break;
295  }
296  }
297  r.reset();
298 
299  // did not find it. Add.
300  if( !def )
301  {
302  def = typename WGEShaderDefine< T >::SPtr( new WGEShaderDefine< T >( key, value ) );
303  addPreprocessor( def );
304  }
305  return def;
306 }
307 
308 #endif // WGESHADER_H
309