SuperTuxKart
sp_shader.hpp
1 // SuperTuxKart - a fun racing game with go-kart
2 // Copyright (C) 2018 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 HEADER_SP_SHADER_HPP
19 #define HEADER_SP_SHADER_HPP
20 
21 #include "graphics/gl_headers.hpp"
22 #include "graphics/sp/sp_per_object_uniform.hpp"
23 #include "utils/log.hpp"
24 #include "utils/no_copy.hpp"
25 
26 #include <array>
27 #include <cstring>
28 #include <functional>
29 #include <ostream>
30 #include <map>
31 #include <memory>
32 #include <string>
33 #include <typeinfo>
34 #include <typeindex>
35 #include <unordered_map>
36 #include <vector>
37 
38 namespace SP
39 {
40 
41 enum SamplerType: unsigned int
42 {
43  ST_NEAREST,
44  ST_NEAREST_CLAMPED,
45  ST_TRILINEAR,
46  ST_TRILINEAR_CLAMPED,
47  ST_BILINEAR,
48  ST_BILINEAR_CLAMPED,
49  ST_SEMI_TRILINEAR,
50  ST_SHADOW,
51  ST_TEXTURE_BUFFER,
52  ST_COUNT
53 };
54 
55 enum RenderPass: unsigned int
56 {
57  RP_1ST = 0,
58  RP_SHADOW,
59  RP_RESERVED,
60  RP_COUNT
61 };
62 
63 inline std::ostream& operator<<(std::ostream& os, const RenderPass& rp)
64 {
65  switch (rp)
66  {
67  case RP_1ST:
68  return os << "first pass";
69  case RP_SHADOW:
70  return os << "shadow pass";
71  case RP_RESERVED:
72  return os << "reserved pass";
73  default:
74  return os;
75  }
76 }
77 
78 class SPUniformAssigner;
79 
80 class SPShader : public NoCopy, public SPPerObjectUniform
81 {
82 private:
83  std::string m_name;
84 
85  std::vector<std::shared_ptr<GLuint> > m_shader_files;
86 
87  GLuint m_program[RP_COUNT];
88 
89  std::map<unsigned, unsigned> m_samplers[RP_COUNT];
90 
91  std::vector<std::tuple<unsigned, std::string, SamplerType,
92  GLuint> >m_prefilled_samplers[RP_COUNT];
93 
94  std::unordered_map<std::string, SPUniformAssigner*> m_uniforms[RP_COUNT];
95 
96  std::unordered_map<std::string, std::function<GLuint()> >
97  m_custom_prefilled_getter[RP_COUNT];
98 
99  std::function<void()> m_use_function[RP_COUNT], m_unuse_function[RP_COUNT];
100 
101  const std::function<void(SPShader*)> m_init_function;
102 
103  const int m_drawing_priority;
104 
105  const bool m_transparent_shader;
106 
107  const bool m_use_alpha_channel;
108 
109  const bool m_use_tangents;
110 
111  const std::array<bool, 6> m_srgb;
112 
113 public:
114  // ------------------------------------------------------------------------
115  static bool m_sp_shader_debug;
116  static std::map<std::string, std::pair<unsigned, SamplerType> >
117  m_prefilled_names;
118  // ------------------------------------------------------------------------
119  SPShader(const std::string& name,
120  const std::function<void(SPShader*)>& init_func,
121  bool transparent_shader = false, int drawing_priority = 0,
122  bool use_alpha_channel = false, bool use_tangents = false,
123  const std::array<bool, 6>& srgb =
124  {{ true, true, false, false, false, false }});
125  // ------------------------------------------------------------------------
126  ~SPShader()
127  {
128  unload();
129  }
130  // ------------------------------------------------------------------------
131  bool hasShader(RenderPass rp) { return m_program[rp] != 0; }
132  // ------------------------------------------------------------------------
133  GLuint getShaderProgram(RenderPass rp) { return m_program[rp]; }
134  // ------------------------------------------------------------------------
135  void use(RenderPass rp = RP_1ST)
136  {
137  if (m_use_function[rp] != NULL)
138  {
139  m_use_function[rp]();
140  }
141 #ifndef SERVER_ONLY
142  glUseProgram(m_program[rp]);
143 #endif
144  }
145  // ------------------------------------------------------------------------
146  void unuse(RenderPass rp = RP_1ST)
147  {
148  if (m_unuse_function[rp] != NULL)
149  {
150  m_unuse_function[rp]();
151  }
152  }
153  // ------------------------------------------------------------------------
154  void addShaderFile(const std::string& name,
155  GLint shader_type, RenderPass rp = RP_1ST);
156  // ------------------------------------------------------------------------
157  void linkShaderFiles(RenderPass rp = RP_1ST);
158  // ------------------------------------------------------------------------
159  void addAllTextures(RenderPass rp = RP_1ST);
160  // ------------------------------------------------------------------------
161  void addAllUniforms(RenderPass rp = RP_1ST);
162  // ------------------------------------------------------------------------
163  void addCustomPrefilledTextures(SamplerType st, GLuint texture_type,
164  const std::string& name,
165  std::function<GLuint()> func,
166  RenderPass rp = RP_1ST);
167  // ------------------------------------------------------------------------
168  void bindPrefilledTextures(RenderPass rp = RP_1ST) const;
169  // ------------------------------------------------------------------------
170  void bindTextures(const std::array<GLuint, 6>& tex,
171  RenderPass rp = RP_1ST) const;
172  // ------------------------------------------------------------------------
173  void addBasicUniforms(RenderPass rp = RP_1ST)
174  {
175 #ifndef SERVER_ONLY
176  // Assign ubo indices
177  GLuint block_index = glGetUniformBlockIndex(m_program[rp],
178  "Matrices");
179  if (block_index != GL_INVALID_INDEX)
180  glUniformBlockBinding(m_program[rp], block_index, 0);
181  block_index = glGetUniformBlockIndex(m_program[rp], "SPFogData");
182  if (block_index != GL_INVALID_INDEX)
183  glUniformBlockBinding(m_program[rp], block_index, 2);
184 #endif
185  }
186  // ------------------------------------------------------------------------
187  const std::string& getName() const { return m_name; }
188  // ------------------------------------------------------------------------
189  SPUniformAssigner* getUniformAssigner(const std::string& name,
190  RenderPass rp = RP_1ST) const;
191  // ------------------------------------------------------------------------
192  void setUniformsPerObject(SPPerObjectUniform* sppou,
193  std::vector<SPUniformAssigner*>* ua_used,
194  RenderPass rp = RP_1ST);
195  // ------------------------------------------------------------------------
196  void setUseFunction(std::function<void()> func, RenderPass rp = RP_1ST)
197  {
198  m_use_function[rp] = func;
199  }
200  // ------------------------------------------------------------------------
201  void setUnuseFunction(std::function<void()> func, RenderPass rp = RP_1ST)
202  {
203  m_unuse_function[rp] = func;
204  }
205  // ------------------------------------------------------------------------
206  bool isTransparent() const { return m_transparent_shader; }
207  // ------------------------------------------------------------------------
208  bool useAlphaChannel() const { return m_use_alpha_channel; }
209  // ------------------------------------------------------------------------
210  int getDrawingPriority() const { return m_drawing_priority; }
211  // ------------------------------------------------------------------------
212  bool samplerLess(RenderPass rp = RP_1ST) const
213  { return m_samplers[rp].empty(); }
214  // ------------------------------------------------------------------------
215  void unload();
216  // ------------------------------------------------------------------------
217  void init()
218  {
219  if (!m_shader_files.empty())
220  {
221  return;
222  }
223  m_init_function(this);
224  }
225  // ------------------------------------------------------------------------
226  bool isSrgbForTextureLayer(unsigned layer) const;
227  // ------------------------------------------------------------------------
228  bool useTangents() const { return m_use_tangents; }
229  // ------------------------------------------------------------------------
230  bool hasTextureLayer(unsigned layer)
231  {
232  for (unsigned rp = RP_1ST; rp < RP_COUNT; rp++)
233  {
234  if (m_samplers[rp].find(layer) != m_samplers[rp].end())
235  {
236  return true;
237  }
238  }
239  return false;
240  }
241 };
242 
243 }
244 
245 #endif
Utility class, you can inherit from this class to disallow the assignment operator and copy construct...
Definition: no_copy.hpp:26
Definition: sp_per_object_uniform.hpp:31
Definition: sp_shader.hpp:81
Definition: sp_uniform_assigner.hpp:43