1 module gfm.opengl.uniform;
2 
3 import std.conv,
4        std..string,
5        std.experimental.logger,
6        core.stdc..string;
7 
8 import bindbc.opengl;
9 
10 import gfm.math.vector,
11        gfm.math.matrix,
12        gfm.opengl.opengl;
13 
14 alias vec2ui = vec2!uint;
15 alias vec3ui = vec3!uint;
16 alias vec4ui = vec4!uint;
17 alias mat3x2f = mat3x2!float;
18 alias mat4x2f = mat4x2!float;
19 alias mat2x3f = mat2x3!float;
20 alias mat4x3f = mat4x3!float;
21 alias mat2x4f = mat2x4!float;
22 alias mat3x4f = mat3x4!float;
23 alias mat3x2d = mat3x2!double;
24 alias mat4x2d = mat4x2!double;
25 alias mat2x3d = mat2x3!double;
26 alias mat4x3d = mat4x3!double;
27 alias mat2x4d = mat2x4!double;
28 alias mat3x4d = mat3x4!double;
29 
30 
31 /// Represents an OpenGL program uniform. Owned by a GLProgram.
32 /// Both uniform locations and values are cached, to minimize OpenGL calls.
33 final class GLUniform
34 {
35     public
36     {
37         /// Creates a GLUniform.
38         /// This is done automatically after linking a GLProgram.
39         /// See_also: GLProgram.
40         /// Throws: $(D OpenGLException) on error.
41         this(GLuint program, GLenum type, string name, GLsizei size)
42         {
43             _type = type;
44             _size = size;
45             _name = name;
46 
47             _location = glGetUniformLocation(program, toStringz(name));
48             if (_location == -1)
49             {
50                 // probably rare: the driver said explicitely this variable was active, and there it's not.
51                 throw new OpenGLException(format("can't get uniform %s location", name));
52             }
53 
54             size_t cacheSize = sizeOfUniformType(type) * size;
55             if (cacheSize > 0)
56             {
57                 _value = new ubyte[cacheSize]; // relying on zero initialization here
58                 _valueChanged = false;
59 
60                 _firstSet = true;
61                 _disabled = false;
62             }
63             else
64             {
65                 if (_logger) _logger.warningf("uniform %s is unrecognized or has size 0, disabled", _name);
66                 _disabled = true;
67             }
68         }
69 
70         /// Creates a fake disabled uniform variable, designed to cope with variables
71         /// that have been optimized out by the OpenGL driver, or those which do not exist.
72         this(string name)
73         {
74             _disabled = true;
75             if (_logger) _logger.warningf("Faking uniform '%s' which either does not exist in the shader program, or was discarded by the driver as unused", name);
76         }
77 
78         /// Sets a uniform variable value.
79         /// T should be the exact type needed, checked at runtime.
80         /// Throws: $(D OpenGLException) on error.
81         void set(T)(T newValue)
82         {
83             set!T(&newValue, 1u);
84         }
85 
86         /// Sets multiple uniform variables.
87         /// Throws: $(D OpenGLException) on error.
88         void set(T)(T[] newValues)
89         {
90             set!T(newValues.ptr, newValues.length);
91         }
92 
93         /// Sets multiple uniform variables.
94         /// Throws: $(D OpenGLException) on error.
95         void set(T)(T* newValues, size_t count)
96         {
97             if (_disabled)
98                 return;
99 
100             // special case so that GL_BOOL variable can be assigned when T is bool
101             static if (is(T == bool))
102             {
103                 assert(_type == GL_BOOL); // else we would have thrown
104                 assert(count == 1);  // else we would have thrown
105                 set!int( cast(int)(*newValues) );
106                 return;
107             }
108             else
109             {
110                 if (!typeIsCompliant!T(_type))
111                     throw new OpenGLException(format("using type %s for setting uniform '%s' which has GLSL type '%s'",
112                                                      T.stringof, _name, GLSLTypeNameArray(_type, _size)));
113 
114                 if (count != _size)
115                     throw new OpenGLException(format("cannot set uniform '%s' of size %s with a value of size %s",
116                                                      _name, _size, count));
117 
118                 // if first time or different value incoming
119                 if (_firstSet || (0 != memcmp(newValues, _value.ptr, _value.length)))
120                 {
121                     memcpy(_value.ptr, newValues, _value.length);
122                     _valueChanged = true;
123 
124                     if (_shouldUpdateImmediately)
125                         update();
126                 }
127 
128                 _firstSet = false;
129             }
130         }
131 
132         /// Updates the uniform value.
133         void use()
134         {
135             _shouldUpdateImmediately = true;
136             update();
137         }
138 
139         /// Unuses this uniform.
140         void unuse()
141         {
142             _shouldUpdateImmediately = false;
143         }
144 
145         /// Returns: Uniform name.
146         string name()
147         {
148             return _name;
149         }
150 
151         /// Sets a logger for the program. That allows additional output
152         /// besides error reporting.
153         void logger(Logger l) pure nothrow { _logger = l; }
154     }
155 
156     private
157     {
158         Logger _logger;
159         GLint _location;
160         GLenum _type;
161         GLsizei _size;
162         ubyte[] _value;
163         bool _valueChanged;
164         bool _firstSet; // force update to ensure we do not relie on the driver initializing uniform to zero
165         bool _disabled; // allow transparent usage while not doing anything
166         bool _shouldUpdateImmediately;
167         string _name;
168 
169         void update()
170         {
171             if (_disabled)
172                 return;
173 
174             // safety check to prevent defaults values in uniforms
175             if (_firstSet)
176             {
177                 if (_logger) _logger.warningf("uniform '%s' left to default value, driver will probably zero it", _name);
178                 _firstSet = false;
179             }
180 
181             // has value changed?
182             // if so, set OpenGL value
183             if (_valueChanged)
184             {
185                 setUniform();
186                 _valueChanged = false;
187             }
188         }
189 
190         void setUniform()
191         {
192             switch(_type)
193             {
194                 case GL_FLOAT:      glUniform1fv(_location, _size, cast(GLfloat*)_value); break;
195                 case GL_FLOAT_VEC2: glUniform2fv(_location, _size, cast(GLfloat*)_value); break;
196                 case GL_FLOAT_VEC3: glUniform3fv(_location, _size, cast(GLfloat*)_value); break;
197                 case GL_FLOAT_VEC4: glUniform4fv(_location, _size, cast(GLfloat*)_value); break;
198                 case GL_DOUBLE:      glUniform1dv(_location, _size, cast(GLdouble*)_value); break;
199                 case GL_DOUBLE_VEC2: glUniform2dv(_location, _size, cast(GLdouble*)_value); break;
200                 case GL_DOUBLE_VEC3: glUniform3dv(_location, _size, cast(GLdouble*)_value); break;
201                 case GL_DOUBLE_VEC4: glUniform4dv(_location, _size, cast(GLdouble*)_value); break;
202                 case GL_INT:      glUniform1iv(_location, _size, cast(GLint*)_value); break;
203                 case GL_INT_VEC2: glUniform2iv(_location, _size, cast(GLint*)_value); break;
204                 case GL_INT_VEC3: glUniform3iv(_location, _size, cast(GLint*)_value); break;
205                 case GL_INT_VEC4: glUniform4iv(_location, _size, cast(GLint*)_value); break;
206                 case GL_UNSIGNED_INT:      glUniform1uiv(_location, _size, cast(GLuint*)_value); break;
207                 case GL_UNSIGNED_INT_VEC2: glUniform2uiv(_location, _size, cast(GLuint*)_value); break;
208                 case GL_UNSIGNED_INT_VEC3: glUniform3uiv(_location, _size, cast(GLuint*)_value); break;
209                 case GL_UNSIGNED_INT_VEC4: glUniform4uiv(_location, _size, cast(GLuint*)_value); break;
210                 case GL_BOOL:      glUniform1iv(_location, _size, cast(GLint*)_value); break;
211                 case GL_BOOL_VEC2: glUniform2iv(_location, _size, cast(GLint*)_value); break;
212                 case GL_BOOL_VEC3: glUniform3iv(_location, _size, cast(GLint*)_value); break;
213                 case GL_BOOL_VEC4: glUniform4iv(_location, _size, cast(GLint*)_value); break;
214                 case GL_FLOAT_MAT2:   glUniformMatrix2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
215                 case GL_FLOAT_MAT3:   glUniformMatrix3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
216                 case GL_FLOAT_MAT4:   glUniformMatrix4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
217                 case GL_FLOAT_MAT2x3: glUniformMatrix2x3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
218                 case GL_FLOAT_MAT2x4: glUniformMatrix3x2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
219                 case GL_FLOAT_MAT3x2: glUniformMatrix2x4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
220                 case GL_FLOAT_MAT3x4: glUniformMatrix4x2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
221                 case GL_FLOAT_MAT4x2: glUniformMatrix3x4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
222                 case GL_FLOAT_MAT4x3: glUniformMatrix4x3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
223                 case GL_DOUBLE_MAT2:   glUniformMatrix2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
224                 case GL_DOUBLE_MAT3:   glUniformMatrix3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
225                 case GL_DOUBLE_MAT4:   glUniformMatrix4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
226                 case GL_DOUBLE_MAT2x3: glUniformMatrix2x3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
227                 case GL_DOUBLE_MAT2x4: glUniformMatrix3x2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
228                 case GL_DOUBLE_MAT3x2: glUniformMatrix2x4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
229                 case GL_DOUBLE_MAT3x4: glUniformMatrix4x2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
230                 case GL_DOUBLE_MAT4x2: glUniformMatrix3x4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
231                 case GL_DOUBLE_MAT4x3: glUniformMatrix4x3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
232 
233                 // image samplers
234                 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
235                     glUniform1iv(_location, _size, cast(GLint*)_value);
236                     break;
237 
238                 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
239                     glUniform1uiv(_location, _size, cast(GLuint*)_value);
240                     break;
241 
242                 case GL_SAMPLER_1D:
243                 case GL_SAMPLER_2D:
244                 case GL_SAMPLER_3D:
245                 case GL_SAMPLER_CUBE:
246                 case GL_SAMPLER_1D_SHADOW:
247                 case GL_SAMPLER_2D_SHADOW:
248                 case GL_SAMPLER_1D_ARRAY:
249                 case GL_SAMPLER_2D_ARRAY:
250                 case GL_SAMPLER_1D_ARRAY_SHADOW:
251                 case GL_SAMPLER_2D_ARRAY_SHADOW:
252                 case GL_SAMPLER_2D_MULTISAMPLE:
253                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
254                 case GL_SAMPLER_CUBE_SHADOW:
255                 case GL_SAMPLER_BUFFER:
256                 case GL_SAMPLER_2D_RECT:
257                 case GL_SAMPLER_2D_RECT_SHADOW:
258                 case GL_INT_SAMPLER_1D:
259                 case GL_INT_SAMPLER_2D:
260                 case GL_INT_SAMPLER_3D:
261                 case GL_INT_SAMPLER_CUBE:
262                 case GL_INT_SAMPLER_1D_ARRAY:
263                 case GL_INT_SAMPLER_2D_ARRAY:
264                 case GL_INT_SAMPLER_2D_MULTISAMPLE:
265                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
266                 case GL_INT_SAMPLER_BUFFER:
267                 case GL_INT_SAMPLER_2D_RECT:
268                 case GL_UNSIGNED_INT_SAMPLER_1D:
269                 case GL_UNSIGNED_INT_SAMPLER_2D:
270                 case GL_UNSIGNED_INT_SAMPLER_3D:
271                 case GL_UNSIGNED_INT_SAMPLER_CUBE:
272                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
273                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
274                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
275                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
276                 case GL_UNSIGNED_INT_SAMPLER_BUFFER:
277                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
278                     glUniform1iv(_location, _size, cast(GLint*)_value);
279                     break;
280 
281                 default:
282                     break;
283             }
284             runtimeCheck();
285         }
286 
287         public static bool typeIsCompliant(T)(GLenum type)
288         {
289             switch (type)
290             {
291                 case GL_FLOAT:      return is(T == float);
292                 case GL_FLOAT_VEC2: return is(T == vec2f);
293                 case GL_FLOAT_VEC3: return is(T == vec3f);
294                 case GL_FLOAT_VEC4: return is(T == vec4f);
295                 case GL_DOUBLE:      return is(T == double);
296                 case GL_DOUBLE_VEC2: return is(T == vec2d);
297                 case GL_DOUBLE_VEC3: return is(T == vec3d);
298                 case GL_DOUBLE_VEC4: return is(T == vec4d);
299                 case GL_INT:      return is(T == int);
300                 case GL_INT_VEC2: return is(T == vec2i);
301                 case GL_INT_VEC3: return is(T == vec3i);
302                 case GL_INT_VEC4: return is(T == vec4i);
303                 case GL_UNSIGNED_INT:      return is(T == uint);
304                 case GL_UNSIGNED_INT_VEC2: return is(T == vec2ui);
305                 case GL_UNSIGNED_INT_VEC3: return is(T == vec3ui);
306                 case GL_UNSIGNED_INT_VEC4: return is(T == vec4ui);
307                 case GL_BOOL:      return is(T == int) || is(T == bool); // int because bool type is 1 byte
308                 case GL_BOOL_VEC2: return is(T == vec2i);
309                 case GL_BOOL_VEC3: return is(T == vec3i);
310                 case GL_BOOL_VEC4: return is(T == vec4i);
311                 case GL_FLOAT_MAT2: return is(T == mat2f);
312                 case GL_FLOAT_MAT3: return is(T == mat3f);
313                 case GL_FLOAT_MAT4: return is(T == mat4f);
314                 case GL_FLOAT_MAT2x3: return is(T == mat3x2f);
315                 case GL_FLOAT_MAT2x4: return is(T == mat4x2f);
316                 case GL_FLOAT_MAT3x2: return is(T == mat2x3f);
317                 case GL_FLOAT_MAT3x4: return is(T == mat4x3f);
318                 case GL_FLOAT_MAT4x2: return is(T == mat2x4f);
319                 case GL_FLOAT_MAT4x3: return is(T == mat3x4f);
320                 case GL_DOUBLE_MAT2: return is(T == mat2d);
321                 case GL_DOUBLE_MAT3: return is(T == mat3d);
322                 case GL_DOUBLE_MAT4: return is(T == mat4d);
323                 case GL_DOUBLE_MAT2x3: return is(T == mat3x2d);
324                 case GL_DOUBLE_MAT2x4: return is(T == mat4x2d);
325                 case GL_DOUBLE_MAT3x2: return is(T == mat2x3d);
326                 case GL_DOUBLE_MAT3x4: return is(T == mat4x3d);
327                 case GL_DOUBLE_MAT4x2: return is(T == mat2x4d);
328                 case GL_DOUBLE_MAT4x3: return is(T == mat3x4d);
329 
330                     // image samplers
331                 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
332                     return is(T == int);
333 
334                 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
335                     return is(T == uint);
336 
337                 case GL_SAMPLER_1D:
338                 case GL_SAMPLER_2D:
339                 case GL_SAMPLER_3D:
340                 case GL_SAMPLER_CUBE:
341                 case GL_SAMPLER_1D_SHADOW:
342                 case GL_SAMPLER_2D_SHADOW:
343                 case GL_SAMPLER_1D_ARRAY:
344                 case GL_SAMPLER_2D_ARRAY:
345                 case GL_SAMPLER_1D_ARRAY_SHADOW:
346                 case GL_SAMPLER_2D_ARRAY_SHADOW:
347                 case GL_SAMPLER_2D_MULTISAMPLE:
348                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
349                 case GL_SAMPLER_CUBE_SHADOW:
350                 case GL_SAMPLER_BUFFER:
351                 case GL_SAMPLER_2D_RECT:
352                 case GL_SAMPLER_2D_RECT_SHADOW:
353                 case GL_INT_SAMPLER_1D:
354                 case GL_INT_SAMPLER_2D:
355                 case GL_INT_SAMPLER_3D:
356                 case GL_INT_SAMPLER_CUBE:
357                 case GL_INT_SAMPLER_1D_ARRAY:
358                 case GL_INT_SAMPLER_2D_ARRAY:
359                 case GL_INT_SAMPLER_2D_MULTISAMPLE:
360                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
361                 case GL_INT_SAMPLER_BUFFER:
362                 case GL_INT_SAMPLER_2D_RECT:
363                 case GL_UNSIGNED_INT_SAMPLER_1D:
364                 case GL_UNSIGNED_INT_SAMPLER_2D:
365                 case GL_UNSIGNED_INT_SAMPLER_3D:
366                 case GL_UNSIGNED_INT_SAMPLER_CUBE:
367                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
368                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
369                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
370                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
371                 case GL_UNSIGNED_INT_SAMPLER_BUFFER:
372                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
373                     return is(T == int);
374 
375                 default:
376                     // unrecognized type, in release mode return true
377                     debug
378                     {
379                         assert(false);
380                     }
381                     else
382                     {
383                         return true;
384                     }
385             }
386         }
387 
388         public static size_t sizeOfUniformType(GLenum type)
389         {
390             switch (type)
391             {
392                 case GL_FLOAT:      return float.sizeof;
393                 case GL_FLOAT_VEC2: return vec2f.sizeof;
394                 case GL_FLOAT_VEC3: return vec3f.sizeof;
395                 case GL_FLOAT_VEC4: return vec4f.sizeof;
396                 case GL_DOUBLE:      return double.sizeof;
397                 case GL_DOUBLE_VEC2: return vec2d.sizeof;
398                 case GL_DOUBLE_VEC3: return vec3d.sizeof;
399                 case GL_DOUBLE_VEC4: return vec4d.sizeof;
400                 case GL_INT:      return int.sizeof;
401                 case GL_INT_VEC2: return vec2i.sizeof;
402                 case GL_INT_VEC3: return vec3i.sizeof;
403                 case GL_INT_VEC4: return vec4i.sizeof;
404                 case GL_UNSIGNED_INT:      return uint.sizeof;
405                 case GL_UNSIGNED_INT_VEC2: return vec2ui.sizeof;
406                 case GL_UNSIGNED_INT_VEC3: return vec3ui.sizeof;
407                 case GL_UNSIGNED_INT_VEC4: return vec4ui.sizeof;
408                 case GL_BOOL:      return int.sizeof; // int because D bool type is 1 byte
409                 case GL_BOOL_VEC2: return vec2i.sizeof;
410                 case GL_BOOL_VEC3: return vec3i.sizeof;
411                 case GL_BOOL_VEC4: return vec4i.sizeof;
412                 case GL_FLOAT_MAT2: return mat2f.sizeof;
413                 case GL_FLOAT_MAT3: return mat3f.sizeof;
414                 case GL_FLOAT_MAT4: return mat4f.sizeof;
415                 case GL_FLOAT_MAT2x3: return mat3x2f.sizeof;
416                 case GL_FLOAT_MAT2x4: return mat4x2f.sizeof;
417                 case GL_FLOAT_MAT3x2: return mat2x3f.sizeof;
418                 case GL_FLOAT_MAT3x4: return mat4x3f.sizeof;
419                 case GL_FLOAT_MAT4x2: return mat2x4f.sizeof;
420                 case GL_FLOAT_MAT4x3: return mat3x4f.sizeof;
421                 case GL_DOUBLE_MAT2: return mat2d.sizeof;
422                 case GL_DOUBLE_MAT3: return mat3d.sizeof;
423                 case GL_DOUBLE_MAT4: return mat4d.sizeof;
424                 case GL_DOUBLE_MAT2x3: return mat3x2d.sizeof;
425                 case GL_DOUBLE_MAT2x4: return mat4x2d.sizeof;
426                 case GL_DOUBLE_MAT3x2: return mat2x3d.sizeof;
427                 case GL_DOUBLE_MAT3x4: return mat4x3d.sizeof;
428                 case GL_DOUBLE_MAT4x2: return mat2x4d.sizeof;
429                 case GL_DOUBLE_MAT4x3: return mat3x4d.sizeof;
430 
431                     // image samplers
432                 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
433                     return int.sizeof;
434 
435                 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
436                     return uint.sizeof;
437 
438                 case GL_SAMPLER_1D:
439                 case GL_SAMPLER_2D:
440                 case GL_SAMPLER_3D:
441                 case GL_SAMPLER_CUBE:
442                 case GL_SAMPLER_1D_SHADOW:
443                 case GL_SAMPLER_2D_SHADOW:
444                 case GL_SAMPLER_1D_ARRAY:
445                 case GL_SAMPLER_2D_ARRAY:
446                 case GL_SAMPLER_1D_ARRAY_SHADOW:
447                 case GL_SAMPLER_2D_ARRAY_SHADOW:
448                 case GL_SAMPLER_2D_MULTISAMPLE:
449                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
450                 case GL_SAMPLER_CUBE_SHADOW:
451                 case GL_SAMPLER_BUFFER:
452                 case GL_SAMPLER_2D_RECT:
453                 case GL_SAMPLER_2D_RECT_SHADOW:
454                 case GL_INT_SAMPLER_1D:
455                 case GL_INT_SAMPLER_2D:
456                 case GL_INT_SAMPLER_3D:
457                 case GL_INT_SAMPLER_CUBE:
458                 case GL_INT_SAMPLER_1D_ARRAY:
459                 case GL_INT_SAMPLER_2D_ARRAY:
460                 case GL_INT_SAMPLER_2D_MULTISAMPLE:
461                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
462                 case GL_INT_SAMPLER_BUFFER:
463                 case GL_INT_SAMPLER_2D_RECT:
464                 case GL_UNSIGNED_INT_SAMPLER_1D:
465                 case GL_UNSIGNED_INT_SAMPLER_2D:
466                 case GL_UNSIGNED_INT_SAMPLER_3D:
467                 case GL_UNSIGNED_INT_SAMPLER_CUBE:
468                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
469                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
470                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
471                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
472                 case GL_UNSIGNED_INT_SAMPLER_BUFFER:
473                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
474                     return int.sizeof;
475 
476                 default:
477                     // unrecognized type
478                     // in debug mode assert, in release mode return 0 to disable this uniform
479                     debug
480                     {
481                         assert(false);
482                     }
483                     else
484                     {
485                         return 0;
486                     }
487             }
488         }
489 
490         static string GLSLTypeName(GLenum type)
491         {
492             switch (type)
493             {
494                 case GL_FLOAT: return "float";
495                 case GL_FLOAT_VEC2: return "vec2";
496                 case GL_FLOAT_VEC3: return "vec3";
497                 case GL_FLOAT_VEC4: return "vec4";
498                 case GL_DOUBLE: return "double";
499                 case GL_DOUBLE_VEC2: return "dvec2";
500                 case GL_DOUBLE_VEC3: return "dvec3";
501                 case GL_DOUBLE_VEC4: return "dvec4";
502                 case GL_INT: return "int";
503                 case GL_INT_VEC2: return "ivec2";
504                 case GL_INT_VEC3: return "ivec3";
505                 case GL_INT_VEC4: return "ivec4";
506                 case GL_UNSIGNED_INT: return "uint";
507                 case GL_UNSIGNED_INT_VEC2: return "uvec2";
508                 case GL_UNSIGNED_INT_VEC3: return "uvec3";
509                 case GL_UNSIGNED_INT_VEC4: return "uvec4";
510                 case GL_BOOL: return "bool";
511                 case GL_BOOL_VEC2: return "bvec2";
512                 case GL_BOOL_VEC3: return "bvec3";
513                 case GL_BOOL_VEC4: return "bvec4";
514                 case GL_FLOAT_MAT2: return "mat2";
515                 case GL_FLOAT_MAT3: return "mat3";
516                 case GL_FLOAT_MAT4: return "mat4";
517                 case GL_FLOAT_MAT2x3: return "mat2x3";
518                 case GL_FLOAT_MAT2x4: return "mat2x4";
519                 case GL_FLOAT_MAT3x2: return "mat3x2";
520                 case GL_FLOAT_MAT3x4: return "mat3x4";
521                 case GL_FLOAT_MAT4x2: return "mat4x2";
522                 case GL_FLOAT_MAT4x3: return "mat4x3";
523                 case GL_DOUBLE_MAT2: return "dmat2";
524                 case GL_DOUBLE_MAT3: return "dmat3";
525                 case GL_DOUBLE_MAT4: return "dmat4";
526                 case GL_DOUBLE_MAT2x3: return "dmat2x3";
527                 case GL_DOUBLE_MAT2x4: return "dmat2x4";
528                 case GL_DOUBLE_MAT3x2: return "dmat3x2";
529                 case GL_DOUBLE_MAT3x4: return "dmat3x4";
530                 case GL_DOUBLE_MAT4x2: return "dmat4x2";
531                 case GL_DOUBLE_MAT4x3: return "dmat4x3";
532                 case GL_SAMPLER_1D: return "sampler1D";
533                 case GL_SAMPLER_2D: return "sampler2D";
534                 case GL_SAMPLER_3D: return "sampler3D";
535                 case GL_SAMPLER_CUBE: return "samplerCube";
536                 case GL_SAMPLER_1D_SHADOW: return "sampler1DShadow";
537                 case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow";
538                 case GL_SAMPLER_1D_ARRAY: return "sampler1DArray";
539                 case GL_SAMPLER_2D_ARRAY: return "sampler2DArray";
540                 case GL_SAMPLER_1D_ARRAY_SHADOW: return "sampler1DArrayShadow";
541                 case GL_SAMPLER_2D_ARRAY_SHADOW: return "sampler2DArrayShadow";
542                 case GL_SAMPLER_2D_MULTISAMPLE: return "sampler2DMS";
543                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return "sampler2DMSArray";
544                 case GL_SAMPLER_CUBE_SHADOW: return "samplerCubeShadow";
545                 case GL_SAMPLER_BUFFER: return "samplerBuffer";
546                 case GL_SAMPLER_2D_RECT: return "sampler2DRect";
547                 case GL_SAMPLER_2D_RECT_SHADOW: return "sampler2DRectShadow";
548                 case GL_INT_SAMPLER_1D: return "isampler1D";
549                 case GL_INT_SAMPLER_2D: return "isampler2D";
550                 case GL_INT_SAMPLER_3D: return "isampler3D";
551                 case GL_INT_SAMPLER_CUBE: return "isamplerCube";
552                 case GL_INT_SAMPLER_1D_ARRAY: return "isampler1DArray";
553                 case GL_INT_SAMPLER_2D_ARRAY: return "isampler2DArray";
554                 case GL_INT_SAMPLER_2D_MULTISAMPLE: return "isampler2DMS";
555                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "isampler2DMSArray";
556                 case GL_INT_SAMPLER_BUFFER: return "isamplerBuffer";
557                 case GL_INT_SAMPLER_2D_RECT: return "isampler2DRect";
558                 case GL_UNSIGNED_INT_SAMPLER_1D: return "usampler1D";
559                 case GL_UNSIGNED_INT_SAMPLER_2D: return "usampler2D";
560                 case GL_UNSIGNED_INT_SAMPLER_3D: return "usampler3D";
561                 case GL_UNSIGNED_INT_SAMPLER_CUBE: return "usamplerCube";
562                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return "usampler2DArray";
563                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return "usampler2DArray";
564                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return "usampler2DMS";
565                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "usampler2DMSArray";
566                 case GL_UNSIGNED_INT_SAMPLER_BUFFER: return "usamplerBuffer";
567                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT: return "usampler2DRect";
568                 case GL_IMAGE_1D: return "image1D";
569                 case GL_IMAGE_2D: return "image2D";
570                 case GL_IMAGE_3D: return "image3D";
571                 case GL_IMAGE_2D_RECT: return "image2DRect";
572                 case GL_IMAGE_CUBE: return "imageCube";
573                 case GL_IMAGE_BUFFER: return "imageBuffer";
574                 case GL_IMAGE_1D_ARRAY: return "image1DArray";
575                 case GL_IMAGE_2D_ARRAY: return "image2DArray";
576                 case GL_IMAGE_2D_MULTISAMPLE: return "image2DMS";
577                 case GL_IMAGE_2D_MULTISAMPLE_ARRAY: return "image2DMSArray";
578                 case GL_INT_IMAGE_1D: return "iimage1D";
579                 case GL_INT_IMAGE_2D: return "iimage2D";
580                 case GL_INT_IMAGE_3D: return "iimage3D";
581                 case GL_INT_IMAGE_2D_RECT: return "iimage2DRect";
582                 case GL_INT_IMAGE_CUBE: return "iimageCube";
583                 case GL_INT_IMAGE_BUFFER: return "iimageBuffer";
584                 case GL_INT_IMAGE_1D_ARRAY: return "iimage1DArray";
585                 case GL_INT_IMAGE_2D_ARRAY: return "iimage2DArray";
586                 case GL_INT_IMAGE_2D_MULTISAMPLE: return "iimage2DMS";
587                 case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "iimage2DMSArray";
588                 case GL_UNSIGNED_INT_IMAGE_1D: return "uimage1D";
589                 case GL_UNSIGNED_INT_IMAGE_2D: return "uimage2D";
590                 case GL_UNSIGNED_INT_IMAGE_3D: return "uimage3D";
591                 case GL_UNSIGNED_INT_IMAGE_2D_RECT: return "uimage2DRect";
592                 case GL_UNSIGNED_INT_IMAGE_CUBE: return "uimageCube";
593                 case GL_UNSIGNED_INT_IMAGE_BUFFER: return "uimageBuffer";
594                 case GL_UNSIGNED_INT_IMAGE_1D_ARRAY: return "uimage1DArray";
595                 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: return "uimage2DArray";
596                 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: return "uimage2DMS";
597                 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "uimage2DMSArray";
598                 case GL_UNSIGNED_INT_ATOMIC_COUNTER: return "atomic_uint";
599                 default:
600                     return "unknown";
601             }
602         }
603 
604         static string GLSLTypeNameArray(GLenum type, size_t multiplicity)
605         {
606             assert(multiplicity > 0);
607             if (multiplicity == 1)
608                 return GLSLTypeName(type);
609             else
610                 return format("%s[%s]", GLSLTypeName(type), multiplicity);
611         }
612     }
613 }
614 
615 static assert(is(GLint == int));
616 static assert(is(GLuint == uint));
617 static assert(is(GLfloat == float));
618 static assert(is(GLdouble == double));