Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : /*
4 : : MIT License
5 : :
6 : : Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7 : :
8 : : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : of this software and associated documentation files (the "Software"), to deal
10 : : in the Software without restriction, including without limitation the rights
11 : : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : copies of the Software, and to permit persons to whom the Software is
13 : : furnished to do so, subject to the following conditions:
14 : :
15 : : The above copyright notice and this permission notice shall be included in all
16 : : copies or substantial portions of the Software.
17 : :
18 : : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : : SOFTWARE.
25 : : */
26 : :
27 : : // ezGL is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28 : :
29 : :
30 : : #include <vector>
31 : : #include <memory>
32 : : #include <string>
33 : : #include <cassert>
34 : : #include <functional>
35 : : #include "ezGL.hpp"
36 : :
37 : : namespace ez {
38 : : namespace gl {
39 : :
40 : : class Program;
41 : : typedef std::shared_ptr<Program> ProgramPtr;
42 : : typedef std::weak_ptr<Program> ProgramWeak;
43 : :
44 : : class Program {
45 : : public:
46 : : struct Uniform;
47 : : typedef std::map<GLenum, std::map<std::string, Uniform>> UniformPerShaderTypeContainer;
48 : : typedef std::function<void(FBOPipeLinePtr, Uniform&)> UniformPreUploadFunctor;
49 : : typedef std::function<bool(Uniform&)> UniformWidgetFunctor;
50 : : struct Uniform {
51 : : std::string name;
52 : : float* datas_f = nullptr; // float
53 : : int32_t* datas_i = nullptr; // int
54 : : uint32_t* datas_u = nullptr; // uint
55 : : bool* datas_b = nullptr; // bool
56 : : uint32_t* data_s2d = nullptr; // sampler2D
57 : : uint32_t* data_s2darr = nullptr; // sampler2DArray
58 : : int32_t matrix_size = 0; // matrixSize 2,3,4
59 : : GLint loc = -1;
60 : : GLuint channels = 0U;
61 : : GLuint elements = 0U;
62 : : bool canbeDirty = false; // to uplaod when needed and not each frames
63 : : bool dirty = false; // need a new upload
64 : : bool used = false;
65 : : bool showed = false;
66 : : BufferBlock** buffer_ptr = nullptr; // a buffer block ex: UBO /SSBO
67 : : int32_t bufferBinding = -1; // the binding point in the sahder of the buffer block
68 : : UniformWidgetFunctor widget_functor = nullptr;
69 : : };
70 : :
71 : : private:
72 : : ProgramWeak m_This;
73 : : GLuint m_ProgramId = 0U;
74 : : std::string m_ProgramName;
75 : : std::map<uintptr_t, ShaderWeak> m_Shaders; // a same shader object can be added two times
76 : : UniformPerShaderTypeContainer m_Uniforms;
77 : : UniformPreUploadFunctor m_UniformPreUploadFunctor = nullptr; // lanbda to execute just before the uniform upload
78 : :
79 : : public:
80 : 0 : static ProgramPtr create(const std::string& vProgramName) {
81 : 0 : auto res = std::make_shared<Program>();
82 : 0 : res->m_This = res;
83 : 0 : if (!res->init(vProgramName)) {
84 : 0 : res.reset();
85 : 0 : }
86 : 0 : return res;
87 : 0 : }
88 : :
89 : : public:
90 : : Program() = default;
91 : 0 : ~Program() { unit(); }
92 : 0 : bool init(const std::string& vProgramName) {
93 : 0 : assert(!vProgramName.empty());
94 : 0 : m_ProgramName = vProgramName;
95 : 0 : m_ProgramId = glCreateProgram();
96 : 0 : CheckGLErrors;
97 : 0 : if (m_ProgramId > 0U) {
98 : 0 : return true;
99 : 0 : }
100 : 0 : return false;
101 : 0 : }
102 : 0 : void unit() {
103 : 0 : if (m_ProgramId > 0U) {
104 : 0 : glDeleteProgram(m_ProgramId);
105 : 0 : CheckGLErrors;
106 : 0 : m_ProgramId = 0U;
107 : 0 : }
108 : 0 : }
109 : 0 : bool addShader(ShaderWeak vShader) {
110 : 0 : if (!vShader.expired()) {
111 : 0 : m_Shaders[(uintptr_t)vShader.lock().get()] = vShader;
112 : 0 : return true;
113 : 0 : }
114 : 0 : return false;
115 : 0 : }
116 : 0 : bool link() {
117 : 0 : bool res = false;
118 : 0 : if (m_ProgramId > 0U) {
119 : 0 : bool one_shader_at_least = false;
120 : 0 : for (auto& shader : m_Shaders) {
121 : 0 : auto ptr = shader.second.lock();
122 : 0 : if (ptr != nullptr) {
123 : 0 : one_shader_at_least = true;
124 : 0 : glAttachShader(m_ProgramId, ptr->getShaderId());
125 : 0 : CheckGLErrors;
126 : 0 : // we could delete shader id after linking,
127 : 0 : // but we dont since we can have many shader for the same program
128 : 0 : }
129 : 0 : }
130 : 0 : if (one_shader_at_least) {
131 : 0 : glLinkProgram(m_ProgramId);
132 : 0 : CheckGLErrors;
133 : 0 : glFinish();
134 : 0 : GLint linked = 0;
135 : 0 : glGetProgramiv(m_ProgramId, GL_LINK_STATUS, &linked);
136 : 0 : CheckGLErrors;
137 : 0 : if (!linked) {
138 : 0 : if (!printProgramLogs(m_ProgramName, "Link Errors")) {
139 : 0 : LogVarError("Program \"%s\" linking fail for unknown reason", m_ProgramName.c_str());
140 : 0 : }
141 : 0 : res = false;
142 : 0 : } else {
143 : 0 : printProgramLogs(m_ProgramName, "Link Warnings");
144 : 0 : res = true;
145 : 0 : }
146 : 0 : }
147 : 0 : }
148 : 0 : return res;
149 : 0 : }
150 : 0 : const char* getLabelName() { return m_ProgramName.c_str(); }
151 : 0 : void setUniformPreUploadFunctor(UniformPreUploadFunctor vUniformPreUploadFunctor) { m_UniformPreUploadFunctor = vUniformPreUploadFunctor; }
152 : 0 : void addBufferBlock(const GLenum vShaderType, const std::string& vBufferName, const int32_t vBinding, BufferBlock** vBufferPtr) {
153 : 0 : assert(vShaderType > 0);
154 : 0 : assert(!vBufferName.empty());
155 : 0 : assert(vBinding > -1);
156 : 0 : assert(vBufferPtr != nullptr);
157 : 0 : Uniform uni;
158 : 0 : uni.name = vBufferName;
159 : 0 : uni.bufferBinding = vBinding;
160 : 0 : uni.buffer_ptr = vBufferPtr;
161 : 0 : m_Uniforms[vShaderType][vBufferName] = uni;
162 : 0 : }
163 : : void addUniformFloat(
164 : : const GLenum vShaderType,
165 : : const std::string& vUniformName,
166 : : float* vUniformPtr,
167 : : const GLuint vCountChannels,
168 : : const GLuint vCountElements,
169 : : const bool vShowWidget,
170 : 0 : const UniformWidgetFunctor& vWidgetFunctor) {
171 : 0 : assert(vShaderType > 0);
172 : 0 : assert(!vUniformName.empty());
173 : 0 : assert(vUniformPtr != nullptr);
174 : 0 : assert(vCountChannels > 0U);
175 : 0 : assert(vCountElements > 0U);
176 : 0 : Uniform uni;
177 : 0 : uni.name = vUniformName;
178 : 0 : uni.datas_f = vUniformPtr;
179 : 0 : uni.showed = vShowWidget;
180 : 0 : uni.channels = vCountChannels;
181 : 0 : uni.elements = vCountElements;
182 : 0 : uni.widget_functor = vWidgetFunctor;
183 : 0 : m_Uniforms[vShaderType][vUniformName] = uni;
184 : 0 : }
185 : 0 : void setUniformFloatDatas(const GLenum vShaderType, const std::string& vUniformName, float* vUniformPtr) {
186 : 0 : auto itShaderType = m_Uniforms.find(vShaderType);
187 : 0 : assert(itShaderType != m_Uniforms.end());
188 : 0 : auto itUniformName = itShaderType->second.find(vUniformName);
189 : 0 : assert(itUniformName != itShaderType->second.end());
190 : 0 : itUniformName->second.datas_f = vUniformPtr;
191 : 0 : }
192 : : void addUniformMatrix(
193 : : const GLenum vShaderType,
194 : : const std::string& vUniformName,
195 : : float* vUniformPtr,
196 : : const int32_t vMatrixSize,
197 : : const GLuint vCountElements,
198 : : const bool vShowWidget,
199 : 0 : const UniformWidgetFunctor& vWidgetFunctor) {
200 : 0 : assert(vShaderType > 0);
201 : 0 : assert(!vUniformName.empty());
202 : 0 : assert(vUniformPtr != nullptr);
203 : 0 : assert((vMatrixSize == 2U) || (vMatrixSize == 3U) || (vMatrixSize == 4U));
204 : 0 : assert(vCountElements > 0U);
205 : 0 : Uniform uni;
206 : 0 : uni.name = vUniformName;
207 : 0 : uni.datas_f = vUniformPtr;
208 : 0 : uni.showed = vShowWidget;
209 : 0 : uni.matrix_size = vMatrixSize;
210 : 0 : uni.elements = vCountElements;
211 : 0 : uni.widget_functor = vWidgetFunctor;
212 : 0 : m_Uniforms[vShaderType][vUniformName] = uni;
213 : 0 : }
214 : 0 : void setUniformMatrixDatas(const GLenum vShaderType, const std::string& vUniformName, float* vUniformPtr) {
215 : 0 : auto itShaderType = m_Uniforms.find(vShaderType);
216 : 0 : assert(itShaderType != m_Uniforms.end());
217 : 0 : auto itUniformName = itShaderType->second.find(vUniformName);
218 : 0 : assert(itUniformName != itShaderType->second.end());
219 : 0 : itUniformName->second.datas_f = vUniformPtr;
220 : 0 : }
221 : : void addUniformInt(
222 : : const GLenum vShaderType,
223 : : const std::string& vUniformName,
224 : : int32_t* vUniformPtr,
225 : : const GLuint vCountChannels,
226 : : const GLuint vCountElements,
227 : : const bool vShowWidget,
228 : 0 : const UniformWidgetFunctor& vWidgetFunctor) {
229 : 0 : assert(vShaderType > 0);
230 : 0 : assert(!vUniformName.empty());
231 : 0 : assert(vUniformPtr != nullptr);
232 : 0 : assert(vCountChannels > 0U);
233 : 0 : assert(vCountElements > 0U);
234 : 0 : Uniform uni;
235 : 0 : uni.name = vUniformName;
236 : 0 : uni.datas_i = vUniformPtr;
237 : 0 : uni.showed = vShowWidget;
238 : 0 : uni.channels = vCountChannels;
239 : 0 : uni.elements = vCountElements;
240 : 0 : uni.widget_functor = vWidgetFunctor;
241 : 0 : m_Uniforms[vShaderType][vUniformName] = uni;
242 : 0 : }
243 : 0 : void setUniformIntDatas(const GLenum vShaderType, const std::string& vUniformName, int32_t* vUniformPtr) {
244 : 0 : auto itShaderType = m_Uniforms.find(vShaderType);
245 : 0 : assert(itShaderType != m_Uniforms.end());
246 : 0 : auto itUniformName = itShaderType->second.find(vUniformName);
247 : 0 : assert(itUniformName != itShaderType->second.end());
248 : 0 : itUniformName->second.datas_i = vUniformPtr;
249 : 0 : }
250 : : void addUniformUInt(
251 : : const GLenum vShaderType,
252 : : const std::string& vUniformName,
253 : : uint32_t* vUniformPtr,
254 : : const GLuint vCountChannels,
255 : : const GLuint vCountElements,
256 : : const bool vShowWidget,
257 : 0 : const UniformWidgetFunctor& vWidgetFunctor) {
258 : 0 : assert(vShaderType > 0);
259 : 0 : assert(!vUniformName.empty());
260 : 0 : assert(vUniformPtr != nullptr);
261 : 0 : assert(vCountChannels > 0U);
262 : 0 : assert(vCountElements > 0U);
263 : 0 : Uniform uni;
264 : 0 : uni.name = vUniformName;
265 : 0 : uni.datas_u = vUniformPtr;
266 : 0 : uni.showed = vShowWidget;
267 : 0 : uni.channels = vCountChannels;
268 : 0 : uni.elements = vCountElements;
269 : 0 : uni.widget_functor = vWidgetFunctor;
270 : 0 : m_Uniforms[vShaderType][vUniformName] = uni;
271 : 0 : }
272 : 0 : void setUniformUIntDatas(const GLenum vShaderType, const std::string& vUniformName, uint32_t* vUniformPtr) {
273 : 0 : auto itShaderType = m_Uniforms.find(vShaderType);
274 : 0 : assert(itShaderType != m_Uniforms.end());
275 : 0 : auto itUniformName = itShaderType->second.find(vUniformName);
276 : 0 : assert(itUniformName != itShaderType->second.end());
277 : 0 : itUniformName->second.datas_u = vUniformPtr;
278 : 0 : }
279 : : void addUniformBool(
280 : : const GLenum vShaderType,
281 : : const std::string& vUniformName,
282 : : bool* vUniformPtr,
283 : : const GLuint vCountChannels,
284 : : const GLuint vCountElements,
285 : : const bool vShowWidget,
286 : 0 : const UniformWidgetFunctor& vWidgetFunctor) {
287 : 0 : assert(vShaderType > 0);
288 : 0 : assert(!vUniformName.empty());
289 : 0 : assert(vUniformPtr != nullptr);
290 : 0 : assert(vCountChannels > 0U);
291 : 0 : assert(vCountElements > 0U);
292 : 0 : Uniform uni;
293 : 0 : uni.name = vUniformName;
294 : 0 : uni.datas_b = vUniformPtr;
295 : 0 : uni.showed = vShowWidget;
296 : 0 : uni.channels = vCountChannels;
297 : 0 : uni.elements = vCountElements;
298 : 0 : uni.widget_functor = vWidgetFunctor;
299 : 0 : m_Uniforms[vShaderType][vUniformName] = uni;
300 : 0 : }
301 : 0 : void setUniformBoolDatas(const GLenum vShaderType, const std::string& vUniformName, bool* vUniformPtr) {
302 : 0 : auto itShaderType = m_Uniforms.find(vShaderType);
303 : 0 : assert(itShaderType != m_Uniforms.end());
304 : 0 : auto itUniformName = itShaderType->second.find(vUniformName);
305 : 0 : assert(itUniformName != itShaderType->second.end());
306 : 0 : itUniformName->second.datas_b = vUniformPtr;
307 : 0 : }
308 : 0 : void addUniformSampler2D(const GLenum vShaderType, const std::string& vUniformName, uint32_t* vSampler2DPtr, const bool vShowWidget) {
309 : 0 : assert(vShaderType > 0);
310 : 0 : assert(!vUniformName.empty());
311 : 0 : // assert(vSampler2D != -1);, if the sampler must point on a buffer after, its normal to have it at -1
312 : 0 : Uniform uni;
313 : 0 : uni.name = vUniformName;
314 : 0 : uni.data_s2d = vSampler2DPtr;
315 : 0 : uni.channels = 0;
316 : 0 : uni.showed = vShowWidget;
317 : 0 : m_Uniforms[vShaderType][vUniformName] = uni;
318 : 0 : }
319 : 0 : void addUniformSampler2DArray(const GLenum vShaderType, const std::string& vUniformName, uint32_t* vSampler2DArrayPtr) {
320 : 0 : assert(vShaderType > 0);
321 : 0 : assert(!vUniformName.empty());
322 : 0 : // assert(vSampler2D != -1);, if the sampler must point on a buffer after, its normal to have it at -1
323 : 0 : Uniform uni;
324 : 0 : uni.name = vUniformName;
325 : 0 : uni.data_s2darr = vSampler2DArrayPtr;
326 : 0 : uni.channels = 0;
327 : 0 : uni.showed = false; // no way to display a texture 2d array
328 : 0 : m_Uniforms[vShaderType][vUniformName] = uni;
329 : 0 : }
330 : 0 : void uploadUniforms(FBOPipeLinePtr vFBOPipeLinePtr = nullptr) {
331 : 0 : #ifdef PROFILER_SCOPED
332 : 0 : PROFILER_SCOPED(m_ProgramName, "uploadUniforms");
333 : 0 : #endif
334 : 0 : int32_t textureSlotId = 0;
335 : 0 : for (auto& shader_type : m_Uniforms) {
336 : 0 : for (auto& uni : shader_type.second) {
337 : 0 : if (m_UniformPreUploadFunctor != nullptr && vFBOPipeLinePtr != nullptr) {
338 : 0 : m_UniformPreUploadFunctor(vFBOPipeLinePtr, uni.second);
339 : 0 : }
340 : 0 : if (uni.second.used) {
341 : 0 : #ifdef PROFILER_SCOPED_PTR
342 : 0 : auto name_c_str = uni.second.name.c_str(); // remove some warnings
343 : 0 : #endif
344 : 0 : if (uni.second.datas_f != nullptr) {
345 : 0 : switch (uni.second.channels) {
346 : 0 : case 1U: {
347 : 0 : #ifdef PROFILER_SCOPED_PTR
348 : 0 : PROFILER_SCOPED_PTR(&uni, "upload float", "%s", name_c_str);
349 : 0 : #endif
350 : 0 : glUniform1fv(uni.second.loc, uni.second.elements, uni.second.datas_f);
351 : 0 : } break;
352 : 0 : case 2U: {
353 : 0 : #ifdef PROFILER_SCOPED_PTR
354 : 0 : PROFILER_SCOPED_PTR(&uni, "upload vec2", "%s", name_c_str);
355 : 0 : #endif
356 : 0 : glUniform2fv(uni.second.loc, uni.second.elements, uni.second.datas_f);
357 : 0 : } break;
358 : 0 : case 3U: {
359 : 0 : #ifdef PROFILER_SCOPED_PTR
360 : 0 : PROFILER_SCOPED_PTR(&uni, "upload vec3", "%s", name_c_str);
361 : 0 : #endif
362 : 0 : glUniform3fv(uni.second.loc, uni.second.elements, uni.second.datas_f);
363 : 0 : } break;
364 : 0 : case 4U: {
365 : 0 : #ifdef PROFILER_SCOPED_PTR
366 : 0 : PROFILER_SCOPED_PTR(&uni, "upload vec4", "%s", name_c_str);
367 : 0 : #endif
368 : 0 : glUniform4fv(uni.second.loc, uni.second.elements, uni.second.datas_f);
369 : 0 : } break;
370 : 0 : }
371 : 0 : switch (uni.second.matrix_size) {
372 : 0 : case 2U: {
373 : 0 : #ifdef PROFILER_SCOPED_PTR
374 : 0 : PROFILER_SCOPED_PTR(&uni, "upload mat2", "%s", name_c_str);
375 : 0 : #endif
376 : 0 : glUniformMatrix2fv(uni.second.loc, uni.second.elements, GL_FALSE, uni.second.datas_f);
377 : 0 : } break;
378 : 0 : case 3U: {
379 : 0 : #ifdef PROFILER_SCOPED_PTR
380 : 0 : PROFILER_SCOPED_PTR(&uni, "upload mat3", "%s", name_c_str);
381 : 0 : #endif
382 : 0 : glUniformMatrix3fv(uni.second.loc, uni.second.elements, GL_FALSE, uni.second.datas_f);
383 : 0 : } break;
384 : 0 : case 4U: {
385 : 0 : #ifdef PROFILER_SCOPED_PTR
386 : 0 : PROFILER_SCOPED_PTR(&uni, "upload mat4", "%s", name_c_str);
387 : 0 : #endif
388 : 0 : glUniformMatrix4fv(uni.second.loc, uni.second.elements, GL_FALSE, uni.second.datas_f);
389 : 0 : } break;
390 : 0 : }
391 : 0 : CheckGLErrors;
392 : 0 : } else if (uni.second.datas_i != nullptr) {
393 : 0 : switch (uni.second.channels) {
394 : 0 : case 1U: {
395 : 0 : #ifdef PROFILER_SCOPED_PTR
396 : 0 : PROFILER_SCOPED_PTR(&uni, "upload int", "%s", name_c_str);
397 : 0 : #endif
398 : 0 : glUniform1iv(uni.second.loc, uni.second.elements, uni.second.datas_i);
399 : 0 : } break;
400 : 0 : case 2U: {
401 : 0 : #ifdef PROFILER_SCOPED_PTR
402 : 0 : PROFILER_SCOPED_PTR(&uni, "upload iec2", "%s", name_c_str);
403 : 0 : #endif
404 : 0 : glUniform2iv(uni.second.loc, uni.second.elements, uni.second.datas_i);
405 : 0 : } break;
406 : 0 : case 3U: {
407 : 0 : #ifdef PROFILER_SCOPED_PTR
408 : 0 : PROFILER_SCOPED_PTR(&uni, "upload ivec3", "%s", name_c_str);
409 : 0 : #endif
410 : 0 : glUniform3iv(uni.second.loc, uni.second.elements, uni.second.datas_i);
411 : 0 : } break;
412 : 0 : case 4U: {
413 : 0 : #ifdef PROFILER_SCOPED_PTR
414 : 0 : PROFILER_SCOPED_PTR(&uni, "upload ivec4", "%s", name_c_str);
415 : 0 : #endif
416 : 0 : glUniform4iv(uni.second.loc, uni.second.elements, uni.second.datas_i);
417 : 0 : } break;
418 : 0 : }
419 : 0 : CheckGLErrors;
420 : 0 : } else if (uni.second.datas_u != nullptr) {
421 : 0 : switch (uni.second.channels) {
422 : 0 : case 1U: {
423 : 0 : #ifdef PROFILER_SCOPED_PTR
424 : 0 : PROFILER_SCOPED_PTR(&uni, "upload uint", "%s", name_c_str);
425 : 0 : #endif
426 : 0 : glUniform1uiv(uni.second.loc, uni.second.elements, uni.second.datas_u);
427 : 0 : } break;
428 : 0 : case 2U: {
429 : 0 : #ifdef PROFILER_SCOPED_PTR
430 : 0 : PROFILER_SCOPED_PTR(&uni, "upload uvec2", "%s", name_c_str);
431 : 0 : #endif
432 : 0 : glUniform2uiv(uni.second.loc, uni.second.elements, uni.second.datas_u);
433 : 0 : } break;
434 : 0 : case 3U: {
435 : 0 : #ifdef PROFILER_SCOPED_PTR
436 : 0 : PROFILER_SCOPED_PTR(&uni, "upload uvec3", "%s", name_c_str);
437 : 0 : #endif
438 : 0 : glUniform3uiv(uni.second.loc, uni.second.elements, uni.second.datas_u);
439 : 0 : } break;
440 : 0 : case 4U: {
441 : 0 : #ifdef PROFILER_SCOPED_PTR
442 : 0 : PROFILER_SCOPED_PTR(&uni, "upload uvec4", "%s", name_c_str);
443 : 0 : #endif
444 : 0 : glUniform4uiv(uni.second.loc, uni.second.elements, uni.second.datas_u);
445 : 0 : } break;
446 : 0 : }
447 : 0 : CheckGLErrors;
448 : 0 : } else if (uni.second.data_s2d != nullptr) {
449 : 0 : #ifdef PROFILER_SCOPED_PTR
450 : 0 : PROFILER_SCOPED_PTR(&uni, "upload sampler2D", "%s", name_c_str);
451 : 0 : #endif
452 : 0 : glActiveTexture(GL_TEXTURE0 + textureSlotId);
453 : 0 : CheckGLErrors;
454 : 0 : glBindTexture(GL_TEXTURE_2D, *uni.second.data_s2d);
455 : 0 : CheckGLErrors;
456 : 0 : glUniform1i(uni.second.loc, textureSlotId);
457 : 0 : CheckGLErrors;
458 : 0 : ++textureSlotId;
459 : 0 : } else if (uni.second.data_s2darr != nullptr) {
460 : 0 : #ifdef PROFILER_SCOPED_PTR
461 : 0 : PROFILER_SCOPED_PTR(&uni, "upload sampler2DArray", "%s", name_c_str);
462 : 0 : #endif
463 : 0 : glActiveTexture(GL_TEXTURE0 + textureSlotId);
464 : 0 : CheckGLErrors;
465 : 0 : glBindTexture(GL_TEXTURE_2D_ARRAY, *uni.second.data_s2darr);
466 : 0 : CheckGLErrors;
467 : 0 : glUniform1i(uni.second.loc, textureSlotId);
468 : 0 : CheckGLErrors;
469 : 0 : ++textureSlotId;
470 : 0 : }
471 : 0 : }
472 : 0 : // buffer have no widgets, and no use infos
473 : 0 : if (uni.second.bufferBinding > -1 && //
474 : 0 : uni.second.buffer_ptr != nullptr && //
475 : 0 : *uni.second.buffer_ptr != nullptr && //
476 : 0 : (*uni.second.buffer_ptr)->id() > 0U) {
477 : 0 : (*uni.second.buffer_ptr)->bind(uni.second.bufferBinding);
478 : 0 : }
479 : 0 : }
480 : 0 : }
481 : 0 : }
482 : : #ifdef IMGUI_INCLUDE
483 : : bool drawUniformWidgetsLight() {
484 : : bool ret = false;
485 : : ImGui::PushID(m_ProgramName.c_str());
486 : : for (auto& shader_type : m_Uniforms) {
487 : : for (auto& uni : shader_type.second) {
488 : : if (uni.second.showed && uni.second.used) {
489 : : if (uni.second.widget_functor != nullptr) {
490 : : ret |= uni.second.widget_functor(uni.second);
491 : : }
492 : : }
493 : : }
494 : : }
495 : : ImGui::PopID();
496 : : return ret;
497 : : }
498 : : bool drawUniformWidgets(bool vShowCollapsingHeader = true) {
499 : : bool ret = false;
500 : : ImGui::PushID(m_ProgramName.c_str());
501 : : bool opened = true;
502 : : if (vShowCollapsingHeader) {
503 : : opened = ImGui::CollapsingHeader(m_ProgramName.c_str(), ImGuiTreeNodeFlags_DefaultOpen);
504 : : }
505 : : if (opened) {
506 : : ImGui::Indent();
507 : : for (auto& shader_type : m_Uniforms) {
508 : : switch (shader_type.first) {
509 : : case GL_VERTEX_SHADER: ImGui::Text("%s", "Stage Vertex"); break;
510 : : case GL_FRAGMENT_SHADER: ImGui::Text("%s", "Stage Fragment"); break;
511 : : case GL_TESS_EVALUATION_SHADER: ImGui::Text("%s", "Stage Tesselation Evaluation"); break;
512 : : case GL_TESS_CONTROL_SHADER: ImGui::Text("%s", "Stage Tesselation Control"); break;
513 : : }
514 : : ImGui::Indent();
515 : : for (auto& uni : shader_type.second) {
516 : : if (uni.second.showed && uni.second.used) {
517 : : if (uni.second.widget_functor != nullptr) {
518 : : ret |= uni.second.widget_functor(uni.second);
519 : : } else {
520 : : if (uni.second.datas_f != nullptr) {
521 : : for (GLuint i = 0; i < uni.second.elements; ++i) {
522 : : switch (uni.second.channels) {
523 : : case 1U: ret |= ImGui::DragFloat(uni.second.name.c_str(), uni.second.datas_f + i); break;
524 : : case 2U: ret |= ImGui::DragFloat2(uni.second.name.c_str(), uni.second.datas_f + i); break;
525 : : case 3U: ret |= ImGui::DragFloat3(uni.second.name.c_str(), uni.second.datas_f + i); break;
526 : : case 4U: ret |= ImGui::DragFloat4(uni.second.name.c_str(), uni.second.datas_f + i); break;
527 : : }
528 : : }
529 : : } else if (uni.second.datas_i != nullptr) {
530 : : for (GLuint i = 0; i < uni.second.elements; ++i) {
531 : : switch (uni.second.channels) {
532 : : case 1U: ret |= ImGui::DragInt(uni.second.name.c_str(), uni.second.datas_i + i); break;
533 : : case 2U: ret |= ImGui::DragInt2(uni.second.name.c_str(), uni.second.datas_i + i); break;
534 : : case 3U: ret |= ImGui::DragInt3(uni.second.name.c_str(), uni.second.datas_i + i); break;
535 : : case 4U: ret |= ImGui::DragInt4(uni.second.name.c_str(), uni.second.datas_i + i); break;
536 : : }
537 : : }
538 : : } else if (uni.second.data_s2d != 0U) {
539 : : ImGui::Text(uni.second.name.c_str());
540 : : ImGui::Indent();
541 : : ImGui::Image((ImTextureID)uni.second.data_s2d, ImVec2(64.0f, 64.0f));
542 : : ImGui::Unindent();
543 : : }
544 : : }
545 : : }
546 : : }
547 : : ImGui::Unindent();
548 : : }
549 : : ImGui::Unindent();
550 : : }
551 : : ImGui::PopID();
552 : : return ret;
553 : : }
554 : : #endif
555 : :
556 : 0 : UniformPerShaderTypeContainer getUniforms() const { return m_Uniforms; }
557 : 0 : UniformPerShaderTypeContainer& getUniformsRef() { return m_Uniforms; }
558 : :
559 : 0 : void locateUniforms() {
560 : 0 : assert(m_ProgramId > 0U);
561 : 0 : const char* stage_name = nullptr;
562 : 0 : for (auto& shader_type : m_Uniforms) {
563 : 0 : switch (shader_type.first) {
564 : 0 : case GL_VERTEX_SHADER: stage_name = "VERTEX"; break;
565 : 0 : case GL_FRAGMENT_SHADER: stage_name = "FRAGMENT"; break;
566 : 0 : case GL_TESS_EVALUATION_SHADER: stage_name = "TESSEVAL"; break;
567 : 0 : case GL_TESS_CONTROL_SHADER: stage_name = "TESSCTRL"; break;
568 : 0 : }
569 : 0 : for (auto& uni : shader_type.second) {
570 : 0 : if (uni.second.buffer_ptr == nullptr) { // BufferBlock are not classical uniforms so no widgets so no location detection needed
571 : 0 : uni.second.loc = glGetUniformLocation(m_ProgramId, uni.second.name.c_str());
572 : 0 : CheckGLErrors;
573 : 0 : uni.second.used = (uni.second.loc > -1);
574 : 0 : if (uni.second.loc == -1) {
575 : 0 : LogVarInfo("Program \'%s\' Stage \'%s\' is not using the uniform \'%s\'", m_ProgramName.c_str(), stage_name, uni.second.name.c_str());
576 : 0 : }
577 : 0 : }
578 : 0 : }
579 : 0 : }
580 : 0 : }
581 : 0 : bool use() {
582 : 0 : if (m_ProgramId > 0U) {
583 : 0 : glUseProgram(m_ProgramId);
584 : 0 : CheckGLErrors;
585 : 0 : return true;
586 : 0 : }
587 : 0 : return false;
588 : 0 : }
589 : 0 : void unuse() { glUseProgram(0); }
590 : :
591 : : private:
592 : 0 : bool printProgramLogs(const std::string& vProgramName, const std::string& vLogTypes) {
593 : 0 : assert(!vProgramName.empty());
594 : 0 : assert(!vLogTypes.empty());
595 : 0 : if (m_ProgramId > 0U) {
596 : 0 : GLint infoLen = 0;
597 : 0 : glGetProgramiv(m_ProgramId, GL_INFO_LOG_LENGTH, &infoLen);
598 : 0 : CheckGLErrors;
599 : 0 : if (infoLen > 1) {
600 : 0 : char* infoLog = new char[infoLen];
601 : 0 : glGetProgramInfoLog(m_ProgramId, infoLen, nullptr, infoLog);
602 : 0 : CheckGLErrors;
603 : 0 : LogVarLightInfo("#### PROGRAM %s ####", vProgramName.c_str());
604 : 0 : LogVarLightInfo("%s : %s", vLogTypes.c_str(), infoLog);
605 : 0 : delete[] infoLog;
606 : 0 : return true;
607 : 0 : }
608 : 0 : }
609 : 0 : return false;
610 : 0 : }
611 : : };
612 : :
613 : : } // namespace gl
614 : : } // namespace ez
|