FPLBase
An open source project by FPL.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
shader.h
Go to the documentation of this file.
1 // Copyright 2014 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef FPLBASE_SHADER_H
16 #define FPLBASE_SHADER_H
17 
18 #include <set>
19 
20 #include "fplbase/config.h" // Must come first.
21 
22 #include "fplbase/async_loader.h"
23 #include "fplbase/handles.h"
24 #include "mathfu/glsl_mappings.h"
25 
26 namespace fplbase {
27 class Renderer;
28 struct ShaderImpl;
29 
30 /// @file
31 /// @addtogroup fplbase_shader
32 /// @{
33 
34 static const int kMaxTexturesPerShader = 8;
35 static const int kNumVec4sInAffineTransform = 3;
36 
37 /// @class Shader
38 /// @brief Represents a shader consisting of a vertex and pixel shader.
39 ///
40 /// Represents a shader consisting of a vertex and pixel shader. Also stores
41 /// ids of standard uniforms. Use the Renderer class below to create these.
42 class Shader : public AsyncAsset {
43  public:
44  Shader(const char *filename, const std::vector<std::string> &local_defines,
45  Renderer *renderer)
46  : AsyncAsset(filename ? filename : ""), impl_(CreateShaderImpl()) {
47  const ShaderHandle invalid = InvalidShaderHandle();
48  Init(invalid /* program */, invalid /* vs */, invalid /* ps */,
49  local_defines, renderer);
50  }
51 
53  : impl_(CreateShaderImpl()) {
54  static const std::vector<std::string> empty_defines;
55  Init(program, vs, ps, empty_defines, nullptr /* renderer */);
56  }
57 
58  ~Shader();
59 
60  /// @brief Recalculates the defines of this shader, and marks dirty if
61  /// they differ from the last Reload().
62  ///
63  /// Defines change the shader source code when it is preprocessed.
64  /// Typically, you have one uber-shader that contains all possible shader
65  /// features, and enable the features using preprocessor defines.
66  /// This function allows you to specify which features are enabled.
67  ///
68  /// @note This function does not reload the shader. It will simply mark
69  /// the shader as dirty, if its defines have changed.
70  ///
71  /// @param global_defines_to_add the defines to be added into 'local_defines'
72  /// above. These are generally global rendering settings, for example,
73  /// enabling shadows or specular.
74  /// @param global_defines_to_omit the defines to forcefully omit from
75  /// 'local_defines'. Generally used to globally disable expensive features
76  /// such as shadows, on low-powered hardware.
78  const std::vector<std::string> &global_defines_to_add,
79  const std::vector<std::string> &global_defines_to_omit);
80 
81  /// @brief If the shader has been marked dirty, reload it and clear the
82  /// dirty flag.
83  ///
84  /// Lazy loading ensures shaders are only loaded and compiled when they
85  /// are used. Also allows the caller to ensure that the reload is happening
86  /// on the correct thread.
87  bool ReloadIfDirty();
88 
89  /// @brief Loads and unpacks the Shader from `filename_` into `data_`.
90  virtual void Load();
91 
92  /// @brief Creates a Shader from `data_`.
93  virtual bool Finalize();
94 
95  /// @brief Whether this object loaded and finalized correctly. Call after
96  /// Finalize has been called (by AssetManager::TryFinalize).
97  bool IsValid() { return ValidShaderHandle(program_); }
98 
99  /// @brief Activate this shader for subsequent draw calls.
100  ///
101  /// Will make this shader active for any subsequent draw calls, and sets
102  /// all standard uniforms (e.g. mvp matrix) based on current values in
103  /// Renderer, if this shader refers to them.
104  ///
105  /// @param renderer The renderer that has the standard uniforms set.
106  void Set(const Renderer &renderer) const;
107 
108  /// @brief Find a non-standard uniform by name.
109  ///
110  /// @param uniform_name The name of the uniform to find.
111  /// @return Returns a handle to the requested uniform, -1 if not found.
112  UniformHandle FindUniform(const char *uniform_name);
113 
114  /// @brief Raw call to set any uniform (with 1/2/3/4/16 components).
115  ///
116  /// More convenient variants below.
117  ///
118  /// @param uniform_loc Handle to the uniform that will be set.
119  /// @param value The value to set the uniform to.
120  /// @param num_components The number of components used by the uniform.
121  void SetUniform(UniformHandle uniform_loc, const float *value,
122  size_t num_components);
123 
124  /// @brief Set an non-standard uniform to a vec2/3/4 value.
125  ///
126  /// Call this after Set() or FindUniform().
127  ///
128  /// @param uniform_loc Handle to the uniform that will be set.
129  /// @param value The vector to set the uniform to.
130  template <int N>
131  void SetUniform(UniformHandle uniform_loc,
132  const mathfu::Vector<float, N> &value) {
133  SetUniform(uniform_loc, &value[0], N);
134  }
135 
136  /// @brief Convenience call that does a Lookup and a Set if found.
137  ///
138  /// Call this after Set().
139  ///
140  /// @param uniform_name The name of the uniform that will be set.
141  /// @param value The vector to set the uniform to.
142  /// @return Returns true if the uniform was found and set, false otherwise.
143  template <int N>
144  bool SetUniform(const char *uniform_name,
145  const mathfu::Vector<float, N> &value) {
146  auto loc = FindUniform(uniform_name);
147  if (!ValidUniformHandle(loc)) return false;
148  SetUniform(loc, &value[0], N);
149  return true;
150  }
151 
152  /// @brief Set a non-standard uniform to a float value.
153  ///
154  /// Call this after Set().
155  ///
156  /// @param uniform_name The name of the uniform that will be set.
157  /// @param value The float to set the uniform to.
158  /// @return Returns true if the uniform was found and set, false otherwise.
159  bool SetUniform(const char *uniform_name, float value) {
160  auto loc = FindUniform(uniform_name);
161  if (!ValidUniformHandle(loc)) return false;
162  SetUniform(loc, &value, 1);
163  return true;
164  }
165 
166  /// @brief Set a non-standard uniform to a mat4 value.
167  ///
168  /// Call this after Set().
169  ///
170  /// @param uniform_name The name of the uniform that will be set.
171  /// @param value The mat4 to set the uniform to.
172  /// @return Returns true if the uniform was found and set, false otherwise.
173  bool SetUniform(const char *uniform_name, const mathfu::mat4 &value) {
174  auto loc = FindUniform(uniform_name);
175  if (!ValidUniformHandle(loc)) return false;
176  SetUniform(loc, &value[0], sizeof(value) / sizeof(float));
177  return true;
178  }
179 
180  void InitializeUniforms();
181 
182  ShaderHandle program() const { return program_; }
183 
184  bool HasDefine(const char *define) const {
185  return enabled_defines_.find(define) != enabled_defines_.end();
186  }
187 
188  bool IsDirty() const { return dirty_; }
189 
190  /// @brief Call to mark the shader as needing to be reloaded.
191  ///
192  /// Useful when you've changed the shader source and want to dynamically
193  /// re-compile the shader.
194  ///
195  /// @note Be sure to call ReloadIfDirty() on your render thread before
196  /// the shader is used. Otherwise an assert will be hit in Shader::Set().
197  void MarkDirty() { dirty_ = true; }
198 
199  // For internal use.
200  ShaderImpl *impl() { return impl_; }
201 
202  /// @brief Loads a .fplshader file from disk.
203  /// Used by the more convenient AssetManager interface, but can also be
204  /// used without it.
205  static Shader *LoadFromShaderDef(const char *filename);
206 
207  private:
208  friend class RendererBase;
209 
210  // Holds the source code of vertex shader and fragment shader.
211  struct ShaderSourcePair {
212  std::string vertex_shader;
213  std::string fragment_shader;
214  };
215 
216  // Used by constructor to init inner variables.
217  void Init(ShaderHandle program, ShaderHandle vs, ShaderHandle ps,
218  const std::vector<std::string> &defines, Renderer *renderer);
219 
220  /// @brief Clear the Shader and reset everything to null.
221  void Clear();
222 
223  void Reset(ShaderHandle program, ShaderHandle vs, ShaderHandle ps);
224 
225  bool ReloadInternal();
226 
227  ShaderSourcePair *LoadSourceFile();
228 
229  // Backend-specific create and destroy calls. These just call new and delete
230  // on the platform-specific impl structs.
231  static ShaderImpl *CreateShaderImpl();
232  static void DestroyShaderImpl(ShaderImpl *impl);
233 
234  ShaderImpl *impl_;
235 
236  ShaderHandle program_;
237  ShaderHandle vs_;
238  ShaderHandle ps_;
239 
240  UniformHandle uniform_model_view_projection_;
241  UniformHandle uniform_model_;
242  UniformHandle uniform_color_;
243  UniformHandle uniform_light_pos_;
244  UniformHandle uniform_camera_pos_;
245  UniformHandle uniform_time_;
246  UniformHandle uniform_bone_transforms_;
247 
248  Renderer *renderer_;
249 
250  // Defines that are set by default. In UpdateDefines(), these are modified
251  // by the global defines to create `enabled_defines` below.
252  std::vector<std::string> local_defines_;
253 
254  // Defines that are actually enabled for this shader.
255  // The shader files are preprocessed with this list of defines.
256  std::set<std::string> enabled_defines_;
257 
258  // If true, means this shader needs to be reloaded.
259  bool dirty_;
260 };
261 
262 /// @}
263 } // namespace fplbase
264 
265 #endif // FPLBASE_SHADER_H
bool IsValid()
Whether this object loaded and finalized correctly. Call after Finalize has been called (by AssetMana...
Definition: shader.h:97
void MarkDirty()
Call to mark the shader as needing to be reloaded.
Definition: shader.h:197
Represents a shader consisting of a vertex and pixel shader.
Definition: shader.h:42
const std::string & filename() const
The name of the file associated with the resource.
Definition: async_loader.h:107
bool SetUniform(const char *uniform_name, const mathfu::mat4 &value)
Set a non-standard uniform to a mat4 value.
Definition: shader.h:173
void SetUniform(UniformHandle uniform_loc, const float *value, size_t num_components)
Raw call to set any uniform (with 1/2/3/4/16 components).
virtual bool Finalize()
Creates a Shader from data_.
virtual void Load()
Loads and unpacks the Shader from filename_ into data_.
bool SetUniform(const char *uniform_name, const mathfu::Vector< float, N > &value)
Convenience call that does a Lookup and a Set if found.
Definition: shader.h:144
bool ReloadIfDirty()
If the shader has been marked dirty, reload it and clear the dirty flag.
bool SetUniform(const char *uniform_name, float value)
Set a non-standard uniform to a float value.
Definition: shader.h:159
void UpdateGlobalDefines(const std::vector< std::string > &global_defines_to_add, const std::vector< std::string > &global_defines_to_omit)
Recalculates the defines of this shader, and marks dirty if they differ from the last Reload()...
void Set(const Renderer &renderer) const
Activate this shader for subsequent draw calls.
static Shader * LoadFromShaderDef(const char *filename)
Loads a .fplshader file from disk. Used by the more convenient AssetManager interface, but can also be used without it.
AsyncAsset()
Default constructor for an empty AsyncAsset.
Definition: async_loader.h:54
UniformHandle FindUniform(const char *uniform_name)
Find a non-standard uniform by name.
Renderer is the main API class for rendering commands.
Definition: renderer.h:310
Definition: handles.h:24
Definition: async_loader.h:48
void SetUniform(UniformHandle uniform_loc, const mathfu::Vector< float, N > &value)
Set an non-standard uniform to a vec2/3/4 value.
Definition: shader.h:131