SuperTuxKart
shader.hpp
1 // SuperTuxKart - a fun racing game with go-kart
2 // Copyright (C) 2014-2015 SuperTuxKart-Team
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 3
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 
18 #ifndef SERVER_ONLY
19 
20 #ifndef HEADER_SHADER_HPP
21 #define HEADER_SHADER_HPP
22 
23 #include "graphics/gl_headers.hpp"
24 #include "graphics/shader_files_manager.hpp"
25 #include "graphics/shared_gpu_objects.hpp"
26 #include "utils/singleton.hpp"
27 
28 #include <matrix4.h>
29 #include <SColor.h>
30 #include <vector3d.h>
31 #include <array>
32 
33 #include <string>
34 #include <vector>
35 
43 {
44 protected:
46  static std::vector<void (*)()> m_all_kill_functions;
47 
48  enum AttributeType
49  {
50  OBJECT,
51  PARTICLES_SIM,
52  PARTICLES_RENDERING,
53  SKINNED_MESH,
54  }; // AttributeType
55 
57  GLuint m_program;
58  std::vector<std::shared_ptr<GLuint> > m_shaders;
59 
60  // ========================================================================
62  template<typename ... Types>
64  {
65  return;
66  } // loadAndAttachShader
67  // ------------------------------------------------------------------------
68  template<typename ... Types>
69  void loadAndAttachShader(GLint shader_type, const std::string &name,
70  Types ... args)
71  {
72  auto shader_id = ShaderFilesManager::getInstance()
73  ->getShaderFile(name, shader_type);
74  if (shader_id)
75  {
76  m_shaders.push_back(shader_id);
77  glAttachShader(m_program, *shader_id);
78  }
79  loadAndAttachShader(args...);
80  } // loadAndAttachShader
81  // ------------------------------------------------------------------------
83  template<typename ... Types>
84  void loadAndAttachShader(GLint shader_type, const char *name,
85  Types ... args)
86  {
87  loadAndAttachShader(shader_type, std::string(name), args...);
88  } // loadAndAttachShader
89 
90 public:
91  ShaderBase();
92  ~ShaderBase()
93  {
94  glDeleteProgram(m_program);
95  }
96  int loadTFBProgram(const std::string &vertex_file_path,
97  const char **varyings,
98  unsigned varyingscount);
99  static void killShaders();
100  GLuint createVAO();
101  // ------------------------------------------------------------------------
103  void use() { glUseProgram(m_program); }
104  // ------------------------------------------------------------------------
105  GLuint getUniformLocation(const char *name)
106  {
107  return glGetUniformLocation(m_program, name);
108  } // getUniformLocation
109 }; // ShaderBase
110 
111 // ============================================================================
117 template<typename T, typename... Args>
118 class Shader : public ShaderBase, public Singleton<T>
119 {
120 private:
121  std::vector<GLuint> m_uniforms;
122 
124  void bindPoint(const char *name, int index)
125  {
126  GLuint block_index = glGetUniformBlockIndex(m_program, name);
127  if (block_index != GL_INVALID_INDEX)
128  glUniformBlockBinding(m_program, block_index, index);
129  } // bindPoint
130 
131 
132  // ========================================================================
133  // assignUniforms: Variadic Template
134 protected:
138  template<typename... U>
139  void assignUniforms(U... rest)
140  {
141  static_assert(sizeof...(rest) == sizeof...(Args),
142  "Count of Uniform's name mismatch");
143  assignUniformsImpl(rest...);
144  } // assignUniforms
145 private:
146  // ------------------------------------------------------------------------
149  {
150  bindPoint("Matrices", 0);
151  bindPoint("LightingData", 1);
152  bindPoint("SPFogData", 2);
153  } // assignUniformsImpl
154 
155  // ------------------------------------------------------------------------
160  template<typename... U>
161  void assignUniformsImpl(const char* name, U... rest)
162  {
163  m_uniforms.push_back(glGetUniformLocation(m_program, name));
164  assignUniformsImpl(rest...);
165  } // assignUniformsImpl
166 
167 
168  // ==============================================
169  // setUniforms: Variadic template implementation.
170 
171 public:
173  void setUniforms(const Args & ... args) const
174  {
175  setUniformsImpl(args...);
176  } // setUniforms
177  // ------------------------------------------------------------------------
178 private:
180  template<unsigned N = 0, typename... Args1>
181  void setUniformsImpl(const std::vector<float> &v, Args1... arg) const
182  {
183  glUniform1fv(m_uniforms[N], (int)v.size(), v.data());
184  setUniformsImpl<N + 1>(arg...);
185  } // setUniformsImpl
186 
187  // ------------------------------------------------------------------------
190  template<unsigned N = 0>
191  void setUniformsImpl() const
192  {
193  } // setUniformImpl
194 
195  // ------------------------------------------------------------------------
197  template<unsigned N = 0, typename... Args1>
198  void setUniformsImpl(const irr::core::matrix4 &mat, Args1... arg) const
199  {
200  glUniformMatrix4fv(m_uniforms[N], 1, GL_FALSE, mat.pointer());
201  setUniformsImpl<N + 1>(arg...);
202  } // setUniformImpl
203 
204  // ------------------------------------------------------------------------
206  template<unsigned N = 0, typename... Args1>
207  void setUniformsImpl(const irr::video::SColorf &col, Args1... arg) const
208  {
209  glUniform3f(m_uniforms[N], col.r, col.g, col.b);
210  setUniformsImpl<N + 1>(arg...);
211  } // setUniformsImpl
212 
213  // ------------------------------------------------------------------------
215  template<unsigned N = 0, typename... Args1>
216  void setUniformsImpl(const irr::video::SColor &col, Args1... arg) const
217  {
218  glUniform4i(m_uniforms[N], col.getRed(), col.getGreen(),
219  col.getBlue(), col.getAlpha());
220  setUniformsImpl<N + 1>(arg...);
221  } // setUniformsImpl
222 
223  // ------------------------------------------------------------------------
225  template<unsigned N = 0, typename... Args1>
226  void setUniformsImpl(const std::array<float, 4> &ff, Args1... arg) const
227  {
228  glUniform4f(m_uniforms[N], ff[0], ff[1], ff[2], ff[3]);
229  setUniformsImpl<N + 1>(arg...);
230  } // setUniformsImpl
231 
232  // ------------------------------------------------------------------------
234  template<unsigned N = 0, typename... Args1>
235  void setUniformsImpl(const irr::core::vector3df &v, Args1... arg) const
236  {
237  glUniform3f(m_uniforms[N], v.X, v.Y, v.Z);
238  setUniformsImpl<N + 1>(arg...);
239  } // setUniformsImpl
240 
241  // ------------------------------------------------------------------------
243  template<unsigned N = 0, typename... Args1>
244  void setUniformsImpl(const irr::core::vector2df &v, Args1... arg) const
245  {
246  glUniform2f(m_uniforms[N], v.X, v.Y);
247  setUniformsImpl<N + 1>(arg...);
248  } // setUniformsImpl
249 
250  // ------------------------------------------------------------------------
252  template<unsigned N = 0, typename... Args1>
253  void setUniformsImpl(const irr::core::dimension2df &v, Args1... arg) const
254  {
255  glUniform2f(m_uniforms[N], v.Width, v.Height);
256  setUniformsImpl<N + 1>(arg...);
257  } // setUniformsImpl
258 
259  // ------------------------------------------------------------------------
261  template<unsigned N = 0, typename... Args1>
262  void setUniformsImpl(float f, Args1... arg) const
263  {
264  glUniform1f(m_uniforms[N], f);
265  setUniformsImpl<N + 1>(arg...);
266  } // setUniformsImpl
267 
268  // ------------------------------------------------------------------------
270  template<unsigned N = 0, typename... Args1>
271  void setUniformsImpl(int f, Args1... arg) const
272  {
273  glUniform1i(m_uniforms[N], f);
274  setUniformsImpl<N + 1>(arg...);
275  } // setUniformsImpl
276 
277 
278  // printFileList: Variadic template for printing a list of shader filenames
279  // ========================================================================
285 protected:
286  template<typename ...Types>
287  void printFileList(GLint shader_type, const char *filepath, Types ... args)
288  {
289  Log::error("shader", filepath);
290  printFileList(args...);
291  } // printFileList
292 
293  // ------------------------------------------------------------------------
295 private:
296  template<typename ...Types>
298  {
299  return;
300  } // printFileList
301 
302 
303  // Variadic template implementation of assignTextureUnit
304  // ========================================================================
305 public:
312  template<typename... T1>
313  void assignTextureUnit(GLuint index, const char* uniform, T1... rest)
314  {
315  glUseProgram(m_program);
316  GLuint uniform_loc = glGetUniformLocation(m_program, uniform);
317  glUniform1i(uniform_loc, index);
318  // Avoid doing any additional glUseProgram for the remaining calls
319  assignTextureUnitNoUse(rest...);
320  glUseProgram(0);
321  } // assignTextureUnit
322 
323 private:
324  // ------------------------------------------------------------------------
327 
328  // ------------------------------------------------------------------------
331  template<typename... T1>
332  void assignTextureUnitNoUse(GLuint index, const char* uniform, T1... rest)
333  {
334  GLuint uniform_loc = glGetUniformLocation(m_program, uniform);
335  glUniform1i(uniform_loc, index);
336  assignTextureUnitNoUse(rest...);
337  } // assignTextureUnitNoUse
338 
339  // ========================================================================
340 
341 public:
342 
348  {
349  m_all_kill_functions.push_back(this->kill);
350  } // Shader
351 
352  // ------------------------------------------------------------------------
355  template<typename ... Types>
356  void loadProgram(AttributeType type, Types ... args)
357  {
358  m_program = glCreateProgram();
359  loadAndAttachShader(args...);
360  glLinkProgram(m_program);
361 
362  GLint Result = GL_FALSE;
363  glGetProgramiv(m_program, GL_LINK_STATUS, &Result);
364  if (Result == GL_FALSE)
365  {
366  int info_length;
367  Log::error("Shader", "Error when linking these shaders :");
368  printFileList(args...);
369  glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &info_length);
370  char *error_message = new char[info_length];
371  glGetProgramInfoLog(m_program, info_length, NULL, error_message);
372  Log::error("Shader", error_message);
373  delete[] error_message;
374  }
375  // After linking all shaders can be detached
376  for (auto shader : m_shaders)
377  {
378  glDetachShader(m_program, *shader);
379  }
380  } // loadProgram
381  // ------------------------------------------------------------------------
382  void drawFullScreenEffect(Args...args)
383  {
384  use();
385  glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO());
386  setUniforms(args...);
387  glDrawArrays(GL_TRIANGLES, 0, 3);
388  } // drawFullScreenEffect
389 
390 }; // Shader
391 
392 
393 #endif
394 
395 #endif // !SERVER_ONLY
396 
A simple non-templated base class.
Definition: shader.hpp:43
ShaderBase()
Constructor, which adds the shader to all instantiated shaders (for the reload-all-shaders debug opti...
Definition: shader.cpp:72
void use()
Activates the shader calling glUseProgram.
Definition: shader.hpp:103
void loadAndAttachShader(GLint shader_type, const char *name, Types ... args)
Convenience interface using const char.
Definition: shader.hpp:84
static std::vector< void(*)()> m_all_kill_functions
Maintains a list of all shaders.
Definition: shader.hpp:46
void loadAndAttachShader()
Ends recursion.
Definition: shader.hpp:63
GLuint m_program
OpenGL's program id.
Definition: shader.hpp:57
int loadTFBProgram(const std::string &vertex_file_path, const char **varyings, unsigned varyingscount)
Loads a transform feedback buffer shader with a given number of varying parameters.
Definition: shader.cpp:37
SharedShader getShaderFile(const std::string &file, unsigned type)
Get a shader file.
Definition: shader_files_manager.cpp:287
The main templated base class for all shaders that do not use textures.
Definition: shader.hpp:119
void printFileList(GLint shader_type, const char *filepath, Types ... args)
Variadic template to print a list of file names.
Definition: shader.hpp:287
void setUniformsImpl(float f, Args1... arg) const
Implementation for setUniforms for a float uniform.
Definition: shader.hpp:262
void bindPoint(const char *name, int index)
Finds the specified uniform block and assigns a binding point to it.
Definition: shader.hpp:124
void setUniformsImpl(const irr::core::vector3df &v, Args1... arg) const
Implementation for setUniforms for a vector3df uniform.
Definition: shader.hpp:235
void setUniformsImpl(const irr::core::vector2df &v, Args1... arg) const
Implementation for setUniforms for a vector2df uniform.
Definition: shader.hpp:244
void assignUniforms(U... rest)
This variadic template collects all names of uniforms in a std::vector.
Definition: shader.hpp:139
void setUniformsImpl() const
End of recursion for setUniforms implementation.
Definition: shader.hpp:191
void setUniformsImpl(const irr::core::matrix4 &mat, Args1... arg) const
Implementation for setUniforms for a matrix uniform.
Definition: shader.hpp:198
void setUniformsImpl(const irr::video::SColor &col, Args1... arg) const
Implementation for setUniforms for a SColor uniform.
Definition: shader.hpp:216
void assignTextureUnitNoUse(GLuint index, const char *uniform, T1... rest)
Recursive implementation of assignTextureUnit, but without the call to gluseProgram (which is done by...
Definition: shader.hpp:332
void setUniforms(const Args &... args) const
Sets the uniforms for this shader.
Definition: shader.hpp:173
void setUniformsImpl(const std::vector< float > &v, Args1... arg) const
Implementation for setUniforms for a vector<float> uniform.
Definition: shader.hpp:181
void assignUniformsImpl()
End of recursive implementation of assignUniforms.
Definition: shader.hpp:148
void setUniformsImpl(const std::array< float, 4 > &ff, Args1... arg) const
Implementation for setUniforms for a 4 floats uniform.
Definition: shader.hpp:226
void setUniformsImpl(const irr::core::dimension2df &v, Args1... arg) const
Implementation for setUniforms for a dimension2df uniform.
Definition: shader.hpp:253
void setUniformsImpl(const irr::video::SColorf &col, Args1... arg) const
Implementation for setUniforms for a matrix SColorF values.
Definition: shader.hpp:207
void setUniformsImpl(int f, Args1... arg) const
Implementation for setUniforms for an int uniform.
Definition: shader.hpp:271
Shader()
Constructor.
Definition: shader.hpp:347
void assignTextureUnit(GLuint index, const char *uniform, T1... rest)
Variadic top level/public interface.
Definition: shader.hpp:313
void assignUniformsImpl(const char *name, U... rest)
Recursive implementation of assignniforms.
Definition: shader.hpp:161
void assignTextureUnitNoUse()
End of recursion.
Definition: shader.hpp:326
void printFileList()
End recursion for variadic template.
Definition: shader.hpp:297
void loadProgram(AttributeType type, Types ... args)
Load a list of shaders and links them all together.
Definition: shader.hpp:356
Definition: singleton.hpp:87
static void kill()
Used to kill the singleton, if needed.
Definition: singleton.hpp:107
static ShaderFilesManager * getInstance()
Used to get the instance.
Definition: singleton.hpp:99