OpenWalnut  1.5.0dev
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 <map>
29 #include <string>
30 
31 #include <boost/filesystem.hpp>
32 #include <boost/signals2/signal.hpp>
33 
34 #include <osg/NodeCallback>
35 #include <osg/Program>
36 #include <osg/Shader>
37 
38 #include "../../common/WPathHelper.h"
39 #include "../../common/WSharedAssociativeContainer.h"
40 
41 #include "WGEShaderDefine.h"
42 #include "WGEShaderPreprocessor.h"
43 
44 /**
45  * Class encapsulating the OSG Program class for a more convenient way of adding and modifying shader.
46  */
47 class WGEShader: public osg::Program
48 {
49 public:
50  /**
51  * Convenience typedef for an osg::ref_ptr
52  */
53  typedef osg::ref_ptr< WGEShader > RefPtr;
54 
55  /**
56  * Convenience typedef for an osg::ref_ptr; const
57  */
58  typedef osg::ref_ptr< const WGEShader > ConstRefPtr;
59 
60  /**
61  * Default constructor. Loads the specified shader programs. The path that can be specified is optional but allows modules to load their own
62  * local shaders. The search order for shader files is as follows: 1. search, 2. search/shaders, 3. WPathHelper::getShaderPath()
63  *
64  * \param name the name of the shader. It gets searched in the shader path.
65  * \param search the local search path. If not specified, the global shader path is used.
66  */
67  WGEShader( std::string name, boost::filesystem::path search = WPathHelper::getShaderPath() );
68 
69  /**
70  * Destructor.
71  */
72  virtual ~WGEShader();
73 
74  // We do not want to override the original function with the same signature as applyDirect.
75  using osg::Program::apply;
76 
77  /**
78  * Apply this shader to the specified node. Use this method to ensure, that reload events can be handled properly during the
79  * update cycle.
80  *
81  * \param node the node where the program should be registered to.
82  */
83  virtual void apply( osg::ref_ptr< osg::Node > node );
84 
85  /**
86  * If enabled, activate our program in the GL pipeline, performing any rebuild operations that might be pending. In addition to the standard
87  * OSG functionality, it also loads/reloads the shader source from file.
88  *
89  * \param state the state to apply the shader program to.
90  */
91  virtual void applyDirect( osg::State& state ); // NOLINT <- ensure this matches the official OSG API by using a non-const ref
92 
93  /**
94  * Removes the shader from the specified node.
95  *
96  * \param node the node where the program is registered to.
97  */
98  virtual void deactivate( osg::ref_ptr< osg::Node > node );
99 
100  /**
101  * Initiate a reload of the shader during the next update cycle.
102  */
103  virtual void reload();
104 
105  /**
106  * 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
107  * defines are a better choice when compared with a lot of branches (if-statements).
108  *
109  * \param key The name of the define
110  * \param value The value of the define. If this is not specified, the define can be used as simple ifdef switch.
111  *
112  * \return the define object allowing later control
113  */
114  template < typename T >
115  typename WGEShaderDefine< T >::SPtr setDefine( std::string key, T value );
116 
117  /**
118  * 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
119  * defines are a better choice when compared with a lot of branches (if-statements).
120  *
121  * \param key The name of the define
122  *
123  * \return the switch allowing to control the define
124  */
125  WGEShaderDefineSwitch::SPtr setDefine( std::string key );
126 
127  /**
128  * Adds the specified preprocessor to this shader. The preprocessor is able to force shader reloads.
129  *
130  * \param preproc the preprocessor to add.
131  */
133 
134  /**
135  * Removes the specified preprocessor. Changes inside the preprocessor won't cause any updates anymore.
136  *
137  * \param preproc the preprocessor to remove. If not exists: nothing is done.
138  */
140 
141  /**
142  * Removes all preprocessors. Be careful with this one since it removes the WGESHaderVersionPreprocessor too, which is mandatory.
143  */
144  void clearPreprocessors();
145 
146 protected:
147  /**
148  * This method searches and processes all includes in the shader source. The filenames in the include statement are assumed to
149  * be relative to this shader's path. It simply unrolls the code.
150  *
151  * \param filename the filename of the shader to process.
152  * \param optional denotes whether a "file not found" is critical or not
153  * \param level the inclusion level. This is used to avoid cycles.
154  *
155  * \return the processed source.
156  */
157  std::string processShaderRecursive( const std::string filename, bool optional = false, int level = 0 );
158 
159  /**
160  * This method searches and processes all includes in the shader source. The filenames in the include statement are assumed to
161  * be relative to this shader's path. It additionally applies preprocessors.
162  *
163  * \see processShaderRecursive
164  *
165  * \param filename the filename of the shader to process.
166  * \param optional denotes whether a "file not found" is critical or not
167  *
168  * \return the processed source.
169  */
170  std::string processShader( const std::string filename, bool optional = false );
171 
172  /**
173  * This completely reloads the shader file and processes it. It also resets m_reload to false.
174  */
175  void reloadShader();
176 
177  /**
178  * Handles all state changes in m_reload and m_deactivated. It ensure that the shader programs are bound properly or deactivated.
179  */
180  void updatePrograms();
181 
182  /**
183  * String that stores the location of all shader files
184  */
185  boost::filesystem::path m_shaderPath;
186 
187  /**
188  * The name of the shader. It is used to construct the actual filename to load.
189  */
190  std::string m_name;
191 
192  /**
193  * Flag denoting whether a shader should be reloaded.
194  */
195  bool m_reload;
196 
197  /**
198  * True if the shaders have been loaded successfully previously.
199  */
201 
202  /**
203  * Flag denoting whether a shader should be deactivated.
204  */
206 
207  /**
208  * Connection object to the reload signal from WGraphbicsEngine.
209  */
210  boost::signals2::connection m_reloadSignalConnection;
211 
212  /**
213  * The list of preprocessors - Type
214  */
216 
217  /**
218  * List of all pre-processing that need to be applied to this shader instance
219  */
221 
222  /**
223  * This preprocessor needs to be run LAST. It handles version-statements in GLSL.
224  */
226 
227  /**
228  * the vertex shader object
229  */
230  osg::ref_ptr< osg::Shader > m_vertexShader;
231 
232  /**
233  * the fragment shader object
234  */
235  osg::ref_ptr< osg::Shader > m_fragmentShader;
236 
237  /**
238  * the geometry shader object
239  */
240  osg::ref_ptr< osg::Shader > m_geometryShader;
241 
242  /**
243  * Update callback which handles the shader reloading.
244  * This ensures thread safe modification of the osg node.
245  */
246  class SafeUpdaterCallback : public osg::NodeCallback
247  {
248  public:
249  /**
250  * Constructor. Creates a new callback.
251  *
252  * \param shader the shader which needs to be updated.
253  */
254  explicit SafeUpdaterCallback( WGEShader* shader );
255 
256  /**
257  * Callback method called by the NodeVisitor when visiting a node.
258  * This inserts and removes enqueued nodes from this group node instance.
259  *
260  * \param node the node calling this update
261  * \param nv The node visitor which performs the traversal. Should be an
262  * update visitor.
263  */
264  virtual void operator()( osg::Node* node, osg::NodeVisitor* nv );
265 
266  protected:
267  /**
268  * The shader belonging to the node currently getting updated.
269  */
271  };
272 
273 private:
274 };
275 
276 template < typename T >
277 typename WGEShaderDefine< T >::SPtr WGEShader::setDefine( std::string key, T value )
278 {
279  typename WGEShaderDefine< T >::SPtr def;
280 
281  // try to find the define. If it exists, set it. If not, add it.
283  for( PreprocessorsList::ConstIterator pp = r->get().begin(); pp != r->get().end(); ++pp )
284  {
285  typename WGEShaderDefine< T >::SPtr define = std::dynamic_pointer_cast< WGEShaderDefine< T > >( ( *pp ).first );
286  if( define && ( define->getName() == key ) )
287  {
288  define->setValue( value );
289  def = define;
290  break;
291  }
292  }
293  r.reset();
294 
295  // did not find it. Add.
296  if( !def )
297  {
298  def = typename WGEShaderDefine< T >::SPtr( new WGEShaderDefine< T >( key, value ) );
299  addPreprocessor( def );
300  }
301  return def;
302 }
303 
304 #endif // WGESHADER_H
305 
This class is able to provide arbitrary values as define statements in GLSL code.
void setValue(const ValueType &value)
Sets the new value for this define.
std::shared_ptr< WGEShaderDefine< ValueType > > SPtr
Shared pointer for this class.
std::string getName() const
Returns the name of the define.
std::shared_ptr< WGEShaderPreprocessor > SPtr
Shared pointer for this class.
Update callback which handles the shader reloading.
Definition: WGEShader.h:247
SafeUpdaterCallback(WGEShader *shader)
Constructor.
Definition: WGEShader.cpp:193
virtual void operator()(osg::Node *node, osg::NodeVisitor *nv)
Callback method called by the NodeVisitor when visiting a node.
Definition: WGEShader.cpp:198
WGEShader * m_shader
The shader belonging to the node currently getting updated.
Definition: WGEShader.h:270
Class encapsulating the OSG Program class for a more convenient way of adding and modifying shader.
Definition: WGEShader.h:48
bool m_shaderLoaded
True if the shaders have been loaded successfully previously.
Definition: WGEShader.h:200
osg::ref_ptr< osg::Shader > m_vertexShader
the vertex shader object
Definition: WGEShader.h:230
virtual void deactivate(osg::ref_ptr< osg::Node > node)
Removes the shader from the specified node.
Definition: WGEShader.cpp:98
std::string processShaderRecursive(const std::string filename, bool optional=false, int level=0)
This method searches and processes all includes in the shader source.
Definition: WGEShader.cpp:206
WGEShaderDefine< T >::SPtr setDefine(std::string key, T value)
Sets a define which is include into the shader source code.
Definition: WGEShader.h:277
virtual void reload()
Initiate a reload of the shader during the next update cycle.
Definition: WGEShader.cpp:117
void updatePrograms()
Handles all state changes in m_reload and m_deactivated.
Definition: WGEShader.cpp:177
osg::ref_ptr< osg::Shader > m_fragmentShader
the fragment shader object
Definition: WGEShader.h:235
virtual void applyDirect(osg::State &state)
If enabled, activate our program in the GL pipeline, performing any rebuild operations that might be ...
Definition: WGEShader.cpp:92
WGEShaderPreprocessor::SPtr m_versionPreprocessor
This preprocessor needs to be run LAST.
Definition: WGEShader.h:225
void removePreprocessor(WGEShaderPreprocessor::SPtr preproc)
Removes the specified preprocessor.
Definition: WGEShader.cpp:372
void reloadShader()
This completely reloads the shader file and processes it.
Definition: WGEShader.cpp:122
boost::signals2::connection m_reloadSignalConnection
Connection object to the reload signal from WGraphbicsEngine.
Definition: WGEShader.h:210
virtual void apply(osg::ref_ptr< osg::Node > node)
Apply this shader to the specified node.
Definition: WGEShader.cpp:79
WGEShader(std::string name, boost::filesystem::path search=WPathHelper::getShaderPath())
Default constructor.
Definition: WGEShader.cpp:49
bool m_reload
Flag denoting whether a shader should be reloaded.
Definition: WGEShader.h:195
void clearPreprocessors()
Removes all preprocessors.
Definition: WGEShader.cpp:384
bool m_deactivated
Flag denoting whether a shader should be deactivated.
Definition: WGEShader.h:205
void addPreprocessor(WGEShaderPreprocessor::SPtr preproc)
Adds the specified preprocessor to this shader.
Definition: WGEShader.cpp:359
osg::ref_ptr< osg::Shader > m_geometryShader
the geometry shader object
Definition: WGEShader.h:240
boost::filesystem::path m_shaderPath
String that stores the location of all shader files.
Definition: WGEShader.h:185
virtual ~WGEShader()
Destructor.
Definition: WGEShader.cpp:73
osg::ref_ptr< WGEShader > RefPtr
Convenience typedef for an osg::ref_ptr.
Definition: WGEShader.h:53
osg::ref_ptr< const WGEShader > ConstRefPtr
Convenience typedef for an osg::ref_ptr; const.
Definition: WGEShader.h:58
std::string processShader(const std::string filename, bool optional=false)
This method searches and processes all includes in the shader source.
Definition: WGEShader.cpp:334
WSharedAssociativeContainer< std::map< WGEShaderPreprocessor::SPtr, boost::signals2::connection > > PreprocessorsList
The list of preprocessors - Type.
Definition: WGEShader.h:215
std::string m_name
The name of the shader.
Definition: WGEShader.h:190
PreprocessorsList m_preprocessors
List of all pre-processing that need to be applied to this shader instance.
Definition: WGEShader.h:220
static boost::filesystem::path getShaderPath()
The path to the global shaders.
This class provides a common interface for thread-safe access to associative containers (set,...
T::const_iterator ConstIterator
A typedef for the correct const iterator useful to traverse this sequence container.
std::shared_ptr< WSharedObjectTicketRead< T > > ReadTicket
Type for read tickets.
Definition: WSharedObject.h:65
ReadTicket getReadTicket() const
Returns a ticket to get read access to the contained data.