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
operator <<(std::ostream & os,const RenderPass & rp)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 // ------------------------------------------------------------------------
~SPShader()126 ~SPShader()
127 {
128 unload();
129 }
130 // ------------------------------------------------------------------------
hasShader(RenderPass rp)131 bool hasShader(RenderPass rp) { return m_program[rp] != 0; }
132 // ------------------------------------------------------------------------
getShaderProgram(RenderPass rp)133 GLuint getShaderProgram(RenderPass rp) { return m_program[rp]; }
134 // ------------------------------------------------------------------------
use(RenderPass rp=RP_1ST)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 // ------------------------------------------------------------------------
unuse(RenderPass rp=RP_1ST)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 // ------------------------------------------------------------------------
addBasicUniforms(RenderPass rp=RP_1ST)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 // ------------------------------------------------------------------------
getName() const187 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 // ------------------------------------------------------------------------
setUseFunction(std::function<void ()> func,RenderPass rp=RP_1ST)196 void setUseFunction(std::function<void()> func, RenderPass rp = RP_1ST)
197 {
198 m_use_function[rp] = func;
199 }
200 // ------------------------------------------------------------------------
setUnuseFunction(std::function<void ()> func,RenderPass rp=RP_1ST)201 void setUnuseFunction(std::function<void()> func, RenderPass rp = RP_1ST)
202 {
203 m_unuse_function[rp] = func;
204 }
205 // ------------------------------------------------------------------------
isTransparent() const206 bool isTransparent() const { return m_transparent_shader; }
207 // ------------------------------------------------------------------------
useAlphaChannel() const208 bool useAlphaChannel() const { return m_use_alpha_channel; }
209 // ------------------------------------------------------------------------
getDrawingPriority() const210 int getDrawingPriority() const { return m_drawing_priority; }
211 // ------------------------------------------------------------------------
samplerLess(RenderPass rp=RP_1ST) const212 bool samplerLess(RenderPass rp = RP_1ST) const
213 { return m_samplers[rp].empty(); }
214 // ------------------------------------------------------------------------
215 void unload();
216 // ------------------------------------------------------------------------
init()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 // ------------------------------------------------------------------------
useTangents() const228 bool useTangents() const { return m_use_tangents; }
229 // ------------------------------------------------------------------------
hasTextureLayer(unsigned layer)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
246