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