1 module gfmod.opengl.uniform;
2 
3 import std.algorithm,
4        std.conv,
5        std.exception,
6        std..string,
7        core.stdc..string;
8 
9 import derelict.opengl3.gl3;
10 
11 import gfmod.opengl.opengl,
12        gfmod.opengl.program;
13 
14 
15 // TODO: (WISHLIST) eventually refactor/simplify GLUniform to be templated with uniform type,
16 // so e.g. set() will be generated just for that type without runtime checks.  2014-08-13
17 
18 import std.traits;
19 import std.typetuple;
20 
21 import gl3n_extra.linalg;
22 
23 /// Checks if Spec is a valid uniform specification.
24 ///
25 /// Uses static asserts for better compile-time error messages.
26 bool isUniformSpec(Spec)()
27 {
28     // All supported uniform types.
29     alias GLSLTypes = TypeTuple!(float,  vec2,   vec3,   vec4,
30                                  double, vec2d,  vec3d,  vec4d,
31                                  int,    vec2i,  vec3i,  vec4i,
32                                  uint,   vec2u,  vec3u,  vec4u,
33                                  mat2,   mat3,   mat4,
34                                  mat32,  mat42,  mat23,  mat43,  mat24, mat34,
35                                  mat2d,  mat3d,  mat4d,
36                                  mat32d, mat42d, mat23d, mat43d, mat24d, mat34d);
37 
38     foreach(Field; FieldTypeTuple!Spec)
39     {
40         static assert(staticIndexOf!(Field, GLSLTypes) >= 0,
41                      "Field of uniform spec %s has type %s which is not a supported "
42                      " GL uniform type".format(Spec.stringof, Field.stringof));
43     }
44     return true;
45 }
46 
47 // Manually copied from tharsis-core to avoid a dependency.
48 /// Get a compile-time tuple containing names of all fields in a struct.
49 package template FieldNamesTuple(S)
50     if(is(S == struct))
51 {
52     /// Determine if a member with specified name is a field of S.
53     template isField(string memberName)
54     {
55         // For some reason, checking if 'S.this.offsetof' compiles is a compiler
56         // error.
57         static if(memberName == "this")
58         {
59             enum bool isField = false;
60         }
61         else
62         {
63             mixin(q{enum bool isField = __traits(compiles, S.%s.offsetof);}.format(memberName));
64         }
65     }
66 
67     alias FieldNamesTuple = Filter!(isField, __traits(allMembers, S));
68 }
69 
70 
71 /** A type-safe API for manipulating GLSL uniform variables.
72  *
73  * 'Uniforms specification' struct Spec specifies types and names of uniforms in
74  * a program. GLUniforms!Spec has properties with names matching fields of Spec.
75  * Uniforms in a program can be set by setting these properties.
76  *
77  * Example:
78  * 
79  * We have a vertex shader with source such as this:
80  *
81  * --------------------
82  * #version 130
83  *
84  * uniform mat4 projection;
85  * uniform mat4 modelView;
86  * in vec3 position;
87  * 
88  * void main()
89  * {
90  *     gl_Position = projection * modelView *  vec4(position, 1.0);
91  * }
92  * --------------------
93  *
94  * We have the following uniforms specification struct:
95  *
96  * --------------------
97  * struct Uniforms
98  * {
99  *     import gl3n.linalg;
100  *     mat4 projection;
101  *     mat4 modelView;
102  * }
103  * --------------------
104  *
105  * $(B NOTE:) Array uniforms are not supported at the moment, but will be supported in
106  * future.
107  *
108  * The vertex shader above is used by a GLProgram $(D program).
109  *
110  * The following code builds a GLUniforms struct:
111  *
112  * Example:
113  * --------------------
114  * try
115  * {
116  *     auto uniforms = GLUniforms!Uniforms(program);
117  * }
118  * catch(OpenGLException e)
119  * {
120  *     writeln("ERROR: uniforms in a program have unexpected types: ", e);
121  *     return;
122  * }
123  * --------------------
124  *
125  * The GLUniforms constructor enforces that types of uniforms in $(D program) match
126  * types in $(D Uniforms) - the uniforms specification struct. Note that if 
127  * $(D program) is missing any uniform, there is no error, only a logged warning, and
128  * a dummy uniform is created. This is because some GPU drivers agressively optimize
129  * and remove uniforms, and we don't want to trigger an error just because a user is
130  * running our program on a GPU we didn't test.
131  *
132  * Finally, the following code sets the uniforms through $(D uniforms).
133  *
134  * --------------------
135  * // mat4 projectionMatrix, modelViewMatrix
136  * uniforms.projection = projectionMatrix;
137  * uniforms.modelView  = modelViewMatrix;
138  * --------------------
139  */
140 struct GLUniforms(Spec)
141     if(isUniformSpec!Spec)
142 {
143 private:
144     // Names of fields in Spec.
145     enum fieldNames = [FieldNamesTuple!Spec];
146 
147     // Types of fields in Spec.
148     alias fieldTypes = FieldTypeTuple!Spec;
149 
150     // Generate GLUniform data members used internally to access uniforms.
151     static string uniformsInternal()
152     {
153         return fieldNames.map!(n => q{GLUniform %s_;}.format(n)).join("\n");
154     }
155 
156     // Generate setters that set each uniform.
157     static string setters()
158     {
159         string[] setters;
160         foreach(i, T; fieldTypes)
161         {
162             enum name = fieldNames[i];
163             setters ~= q{
164             // GLUniform ensures the value can be set even while the program is not
165             // bound.
166             void %s(%s rhs) @safe nothrow { %s_.set(rhs); }
167             }.format(name, T.stringof, name);
168         }
169 
170         return setters.join("\n\n");
171     }
172 
173     // GLSL program owning the uniforms.
174     GLProgram program_;
175 
176     // pragma(msg, uniformsInternal());
177     mixin(uniformsInternal());
178 
179 public:
180     /// Construct GLUniforms to access uniforms in a GLProgram.
181     ///
182     /// If any uniform present in Spec is missing in program, a fake uniform will be
183     /// created to avoid an error. See GLUniforms documentation top for why we avoid
184     /// throwing an exception in that case.
185     ///
186     /// OpenGLException if types of uniforms in the program don't match types in Spec.
187     this(GLProgram program) @safe
188     {
189         program_ = program;
190         foreach(i, T; fieldTypes)
191         {
192             enum name = fieldNames[i];
193 
194             // Initialize the uniform
195             mixin(q{
196             %s_ = program_.uniform(name);
197             // Fake uniforms are automatically ignored as they have no type.
198             if(%s_.isFake) { continue; }
199             // Check that the uniform has type from the spec.
200             const compliant = %s_.typeIsCompliant!T;
201             }.format(name, name, name));
202 
203             enum msg = "Uniform %s is not compatible with type %s."
204                        .format(name, T.stringof);
205             enforce(compliant, new OpenGLException(msg));
206         }
207     };
208 
209     // pragma(msg, setters());
210     mixin(setters());
211 }
212 
213 /// Represents an OpenGL program uniform. Owned by a GLProgram.
214 /// Both uniform locations and values are cached, to minimize OpenGL calls.
215 package final class GLUniform
216 {
217     public
218     {
219         /// Creates a GLUniform.
220         /// This is done automatically after linking a GLProgram.
221         /// See_also: GLProgram.
222         /// Throws: $(D OpenGLException) on error.
223         this(OpenGL gl, GLuint program, GLenum type, string name, GLsizei size)
224         {
225             _gl = gl;
226             _type = type;
227             _size = size;
228             _name = name;
229 
230             _location = glGetUniformLocation(program, toStringz(_name));
231             if (_location == -1)
232             {
233                 // probably rare: the driver said explicitely this variable was active, and there it's not.
234                 throw new OpenGLException(format("can't get uniform %s location", _name));
235             }
236 
237             size_t cacheSize = sizeOfUniformType(type) * size;
238             if (cacheSize > 0)
239             {
240                 _value = new ubyte[cacheSize]; // relying on zero initialization here
241                 _valueChanged = false;
242 
243                 _firstSet = true;
244                 _disabled = false;
245             }
246             else
247             {
248                 _gl._logger.warningf("uniform %s is unrecognized or has size 0, disabled", _name);
249                 _disabled = true;
250             }
251         }
252 
253         /// Creates a fake disabled uniform variable, designed to cope with variables
254         /// that have been optimized out by the OpenGL driver, or those which do not exist.
255         this(OpenGL gl, string name) @safe nothrow
256         {
257             _gl       = gl;
258             _disabled = true;
259             _fake     = true;
260             _gl._logger.warningf("creating fake uniform '%s' which either does not "
261                                  "exist in the shader program, or was discarded by the"
262                                  "driver as unused", name).assumeWontThrow;
263         }
264 
265         /// Sets a uniform variable value.
266         /// T should be the exact type needed, checked at runtime.
267         /// Throws: $(D OpenGLException) on error.
268         void set(T)(T newValue) @trusted
269         {
270             set!T(&newValue, 1u);
271         }
272 
273         /// Sets multiple uniform variables.
274         /// Throws: $(D OpenGLException) on error.
275         void set(T)(T[] newValues) @safe
276         {
277             set!T(newValues.ptr, newValues.length);
278         }
279 
280         /// Sets multiple uniform variables.
281         /// Throws: $(D OpenGLException) on error.
282         void set(T)(T* newValues, size_t count) @trusted nothrow
283         {
284             if (_disabled)
285                 return;
286 
287             assert(typeIsCompliant!T,
288                    "Can't use type %s to set uniform '%s' which has GLSL type %s.\n"
289                    "Use GLUniform.isTypeCompliant() to check if the type matches".
290                    format(T.stringof, _name, GLSLTypeNameArray(_type, _size))
291                    .assumeWontThrow);
292             assert(count == _size,
293                    "Can't set uniform '%s' of size %s with a value of size %s.\n"
294                    "Use GLUniform.size() to check the uniform's size."
295                    .format(_name, _size, count).assumeWontThrow);
296 
297 
298             // if first time or different value incoming
299             if (_firstSet || (0 != memcmp(newValues, _value.ptr, _value.length)))
300             {
301                 memcpy(_value.ptr, newValues, _value.length);
302                 _valueChanged = true;
303 
304                 if (_shouldUpdateImmediately)
305                     update();
306             }
307 
308             _firstSet = false;
309         }
310 
311         /// Is this a "fake" uniform?
312         ///
313         /// Fake uniforms are created to avoid errors when a uniform is optimized out
314         /// by the driver. A fake uniform has no type and will silently do nothing
315         /// without failing when set.
316         bool isFake() @safe pure nothrow const @nogc
317         {
318             return _fake;
319         }
320 
321         /// Get the size (number of elements) of the uniform.
322         size_t size() @safe pure nothrow const @nogc
323         {
324             return _size;
325         }
326 
327         /// Called when the program owning this uniform is used.
328         void use() nothrow
329         {
330             // When in use, any changes to the uniform must trigger an immediate update.
331             _shouldUpdateImmediately = true;
332             update();
333         }
334 
335         /// Called when the program owning this uniform is unused.
336         void unuse() @safe pure nothrow @nogc
337         {
338             // When not in use, we can wait with updating the uniform till we're being
339             // used.
340             _shouldUpdateImmediately = false;
341         }
342     }
343 
344     private
345     {
346         OpenGL _gl;
347         GLint _location;
348         GLenum _type;
349         GLsizei _size;
350         ubyte[] _value;
351         bool _valueChanged;
352         bool _firstSet; // force update to ensure we do not relie on the driver initializing uniform to zero
353         bool _disabled; // allow transparent usage while not doing anything
354         bool _fake;     // Extra flag for fake uniforms used when a uniform is optimized out.
355         bool _shouldUpdateImmediately;
356         string _name;
357 
358         void update() nothrow
359         {
360             if (_disabled)
361                 return;
362 
363             // safety check to prevent defaults values in uniforms
364             if (_firstSet)
365             {
366                 _gl._logger.warningf("uniform '%s' left to default value, driver will probably zero it", _name)
367                            .assumeWontThrow();
368                 _firstSet = false;
369             }
370 
371             // has value changed?
372             // if so, set OpenGL value
373             if (_valueChanged)
374             {
375                 // _gl._logger.info(*cast(mat4*)_value.ptr).assumeWontThrow;
376                 setUniform();
377                 _valueChanged = false;
378             }
379         }
380 
381         void setUniform() @trusted nothrow @nogc
382         {
383             switch(_type)
384             {
385                 case GL_FLOAT:             glUniform1fv(_location, _size, cast(GLfloat*)_value); break;
386                 case GL_FLOAT_VEC2:        glUniform2fv(_location, _size, cast(GLfloat*)_value); break;
387                 case GL_FLOAT_VEC3:        glUniform3fv(_location, _size, cast(GLfloat*)_value); break;
388                 case GL_FLOAT_VEC4:        glUniform4fv(_location, _size, cast(GLfloat*)_value); break;
389                 case GL_DOUBLE:            glUniform1dv(_location, _size, cast(GLdouble*)_value); break;
390                 case GL_DOUBLE_VEC2:       glUniform2dv(_location, _size, cast(GLdouble*)_value); break;
391                 case GL_DOUBLE_VEC3:       glUniform3dv(_location, _size, cast(GLdouble*)_value); break;
392                 case GL_DOUBLE_VEC4:       glUniform4dv(_location, _size, cast(GLdouble*)_value); break;
393                 case GL_INT:               glUniform1iv(_location, _size, cast(GLint*)_value); break;
394                 case GL_INT_VEC2:          glUniform2iv(_location, _size, cast(GLint*)_value); break;
395                 case GL_INT_VEC3:          glUniform3iv(_location, _size, cast(GLint*)_value); break;
396                 case GL_INT_VEC4:          glUniform4iv(_location, _size, cast(GLint*)_value); break;
397                 case GL_UNSIGNED_INT:      glUniform1uiv(_location, _size, cast(GLuint*)_value); break;
398                 case GL_UNSIGNED_INT_VEC2: glUniform2uiv(_location, _size, cast(GLuint*)_value); break;
399                 case GL_UNSIGNED_INT_VEC3: glUniform3uiv(_location, _size, cast(GLuint*)_value); break;
400                 case GL_UNSIGNED_INT_VEC4: glUniform4uiv(_location, _size, cast(GLuint*)_value); break;
401                 case GL_BOOL:              glUniform1iv(_location, _size, cast(GLint*)_value); break;
402                 case GL_BOOL_VEC2:         glUniform2iv(_location, _size, cast(GLint*)_value); break;
403                 case GL_BOOL_VEC3:         glUniform3iv(_location, _size, cast(GLint*)_value); break;
404                 case GL_BOOL_VEC4:         glUniform4iv(_location, _size, cast(GLint*)_value); break;
405                 case GL_FLOAT_MAT2:        glUniformMatrix2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
406                 case GL_FLOAT_MAT3:        glUniformMatrix3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
407                 case GL_FLOAT_MAT4:        glUniformMatrix4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
408                 case GL_FLOAT_MAT2x3:      glUniformMatrix2x3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
409                 case GL_FLOAT_MAT2x4:      glUniformMatrix3x2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
410                 case GL_FLOAT_MAT3x2:      glUniformMatrix2x4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
411                 case GL_FLOAT_MAT3x4:      glUniformMatrix4x2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
412                 case GL_FLOAT_MAT4x2:      glUniformMatrix3x4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
413                 case GL_FLOAT_MAT4x3:      glUniformMatrix4x3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
414                 case GL_DOUBLE_MAT2:       glUniformMatrix2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
415                 case GL_DOUBLE_MAT3:       glUniformMatrix3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
416                 case GL_DOUBLE_MAT4:       glUniformMatrix4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
417                 case GL_DOUBLE_MAT2x3:     glUniformMatrix2x3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
418                 case GL_DOUBLE_MAT2x4:     glUniformMatrix3x2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
419                 case GL_DOUBLE_MAT3x2:     glUniformMatrix2x4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
420                 case GL_DOUBLE_MAT3x4:     glUniformMatrix4x2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
421                 case GL_DOUBLE_MAT4x2:     glUniformMatrix3x4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
422                 case GL_DOUBLE_MAT4x3:     glUniformMatrix4x3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
423 
424                 // image samplers
425                 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
426                     glUniform1iv(_location, _size, cast(GLint*)_value);
427                     break;
428 
429                 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
430                     glUniform1uiv(_location, _size, cast(GLuint*)_value);
431                     break;
432 
433                 case GL_SAMPLER_1D:
434                 case GL_SAMPLER_2D:
435                 case GL_SAMPLER_3D:
436                 case GL_SAMPLER_CUBE:
437                 case GL_SAMPLER_1D_SHADOW:
438                 case GL_SAMPLER_2D_SHADOW:
439                 case GL_SAMPLER_1D_ARRAY:
440                 case GL_SAMPLER_2D_ARRAY:
441                 case GL_SAMPLER_1D_ARRAY_SHADOW:
442                 case GL_SAMPLER_2D_ARRAY_SHADOW:
443                 case GL_SAMPLER_2D_MULTISAMPLE:
444                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
445                 case GL_SAMPLER_CUBE_SHADOW:
446                 case GL_SAMPLER_BUFFER:
447                 case GL_SAMPLER_2D_RECT:
448                 case GL_SAMPLER_2D_RECT_SHADOW:
449                 case GL_INT_SAMPLER_1D:
450                 case GL_INT_SAMPLER_2D:
451                 case GL_INT_SAMPLER_3D:
452                 case GL_INT_SAMPLER_CUBE:
453                 case GL_INT_SAMPLER_1D_ARRAY:
454                 case GL_INT_SAMPLER_2D_ARRAY:
455                 case GL_INT_SAMPLER_2D_MULTISAMPLE:
456                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
457                 case GL_INT_SAMPLER_BUFFER:
458                 case GL_INT_SAMPLER_2D_RECT:
459                 case GL_UNSIGNED_INT_SAMPLER_1D:
460                 case GL_UNSIGNED_INT_SAMPLER_2D:
461                 case GL_UNSIGNED_INT_SAMPLER_3D:
462                 case GL_UNSIGNED_INT_SAMPLER_CUBE:
463                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
464                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
465                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
466                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
467                 case GL_UNSIGNED_INT_SAMPLER_BUFFER:
468                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
469                     glUniform1iv(_location, _size, cast(GLint*)_value);
470                     break;
471 
472                 default:
473                     break;
474             }
475         }
476 
477         public bool typeIsCompliant(T)() @safe pure nothrow const @nogc
478         {
479             switch (_type)
480             {
481                 case GL_FLOAT:             return is(T == float);
482                 case GL_FLOAT_VEC2:        return is(T == vec2);
483                 case GL_FLOAT_VEC3:        return is(T == vec3);
484                 case GL_FLOAT_VEC4:        return is(T == vec4);
485                 case GL_DOUBLE:            return is(T == double);
486                 case GL_DOUBLE_VEC2:       return is(T == vec2d);
487                 case GL_DOUBLE_VEC3:       return is(T == vec3d);
488                 case GL_DOUBLE_VEC4:       return is(T == vec4d);
489                 case GL_INT:               return is(T == int);
490                 case GL_INT_VEC2:          return is(T == vec2i);
491                 case GL_INT_VEC3:          return is(T == vec3i);
492                 case GL_INT_VEC4:          return is(T == vec4i);
493                 case GL_UNSIGNED_INT:      return is(T == uint);
494                 case GL_UNSIGNED_INT_VEC2: return is(T == vec2u);
495                 case GL_UNSIGNED_INT_VEC3: return is(T == vec3u);
496                 case GL_UNSIGNED_INT_VEC4: return is(T == vec4u);
497                 case GL_BOOL:              return is(T == int); // int because bool type is 1 byte
498                 case GL_BOOL_VEC2:         return is(T == vec2i);
499                 case GL_BOOL_VEC3:         return is(T == vec3i);
500                 case GL_BOOL_VEC4:         return is(T == vec4i);
501                 case GL_FLOAT_MAT2:        return is(T == mat2);
502                 case GL_FLOAT_MAT3:        return is(T == mat3);
503                 case GL_FLOAT_MAT4:        return is(T == mat4);
504                 case GL_FLOAT_MAT2x3:      return is(T == mat32);
505                 case GL_FLOAT_MAT2x4:      return is(T == mat42);
506                 case GL_FLOAT_MAT3x2:      return is(T == mat23);
507                 case GL_FLOAT_MAT3x4:      return is(T == mat43);
508                 case GL_FLOAT_MAT4x2:      return is(T == mat24);
509                 case GL_FLOAT_MAT4x3:      return is(T == mat34);
510                 case GL_DOUBLE_MAT2:       return is(T == mat2d);
511                 case GL_DOUBLE_MAT3:       return is(T == mat3d);
512                 case GL_DOUBLE_MAT4:       return is(T == mat4d);
513                 case GL_DOUBLE_MAT2x3:     return is(T == mat32d);
514                 case GL_DOUBLE_MAT2x4:     return is(T == mat42d);
515                 case GL_DOUBLE_MAT3x2:     return is(T == mat23d);
516                 case GL_DOUBLE_MAT3x4:     return is(T == mat43d);
517                 case GL_DOUBLE_MAT4x2:     return is(T == mat24d);
518                 case GL_DOUBLE_MAT4x3:     return is(T == mat34d);
519 
520                     // image samplers
521                 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
522                     return is(T == int);
523 
524                 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
525                     return is(T == uint);
526 
527                 case GL_SAMPLER_1D:
528                 case GL_SAMPLER_2D:
529                 case GL_SAMPLER_3D:
530                 case GL_SAMPLER_CUBE:
531                 case GL_SAMPLER_1D_SHADOW:
532                 case GL_SAMPLER_2D_SHADOW:
533                 case GL_SAMPLER_1D_ARRAY:
534                 case GL_SAMPLER_2D_ARRAY:
535                 case GL_SAMPLER_1D_ARRAY_SHADOW:
536                 case GL_SAMPLER_2D_ARRAY_SHADOW:
537                 case GL_SAMPLER_2D_MULTISAMPLE:
538                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
539                 case GL_SAMPLER_CUBE_SHADOW:
540                 case GL_SAMPLER_BUFFER:
541                 case GL_SAMPLER_2D_RECT:
542                 case GL_SAMPLER_2D_RECT_SHADOW:
543                 case GL_INT_SAMPLER_1D:
544                 case GL_INT_SAMPLER_2D:
545                 case GL_INT_SAMPLER_3D:
546                 case GL_INT_SAMPLER_CUBE:
547                 case GL_INT_SAMPLER_1D_ARRAY:
548                 case GL_INT_SAMPLER_2D_ARRAY:
549                 case GL_INT_SAMPLER_2D_MULTISAMPLE:
550                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
551                 case GL_INT_SAMPLER_BUFFER:
552                 case GL_INT_SAMPLER_2D_RECT:
553                 case GL_UNSIGNED_INT_SAMPLER_1D:
554                 case GL_UNSIGNED_INT_SAMPLER_2D:
555                 case GL_UNSIGNED_INT_SAMPLER_3D:
556                 case GL_UNSIGNED_INT_SAMPLER_CUBE:
557                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
558                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
559                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
560                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
561                 case GL_UNSIGNED_INT_SAMPLER_BUFFER:
562                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
563                     return is(T == int);
564 
565                 default:
566                     // unrecognized type, in release mode return true
567                     debug
568                     {
569                         assert(false);
570                     }
571                     else
572                     {
573                         return true;
574                     }
575             }
576         }
577 
578         public static size_t sizeOfUniformType(GLenum type) @safe pure nothrow @nogc 
579         {
580             switch (type)
581             {
582                 case GL_FLOAT:             return float.sizeof;
583                 case GL_FLOAT_VEC2:        return vec2.sizeof;
584                 case GL_FLOAT_VEC3:        return vec3.sizeof;
585                 case GL_FLOAT_VEC4:        return vec4.sizeof;
586                 case GL_DOUBLE:            return double.sizeof;
587                 case GL_DOUBLE_VEC2:       return vec2d.sizeof;
588                 case GL_DOUBLE_VEC3:       return vec3d.sizeof;
589                 case GL_DOUBLE_VEC4:       return vec4d.sizeof;
590                 case GL_INT:               return int.sizeof;
591                 case GL_INT_VEC2:          return vec2i.sizeof;
592                 case GL_INT_VEC3:          return vec3i.sizeof;
593                 case GL_INT_VEC4:          return vec4i.sizeof;
594                 case GL_UNSIGNED_INT:      return uint.sizeof;
595                 case GL_UNSIGNED_INT_VEC2: return vec2u.sizeof;
596                 case GL_UNSIGNED_INT_VEC3: return vec3u.sizeof;
597                 case GL_UNSIGNED_INT_VEC4: return vec4u.sizeof;
598                 case GL_BOOL:              return int.sizeof; // int because D bool type is 1 byte
599                 case GL_BOOL_VEC2:         return vec2i.sizeof;
600                 case GL_BOOL_VEC3:         return vec3i.sizeof;
601                 case GL_BOOL_VEC4:         return vec4i.sizeof;
602                 case GL_FLOAT_MAT2:        return mat2.sizeof;
603                 case GL_FLOAT_MAT3:        return mat3.sizeof;
604                 case GL_FLOAT_MAT4:        return mat4.sizeof;
605                 case GL_FLOAT_MAT2x3:      return mat32.sizeof;
606                 case GL_FLOAT_MAT2x4:      return mat42.sizeof;
607                 case GL_FLOAT_MAT3x2:      return mat23.sizeof;
608                 case GL_FLOAT_MAT3x4:      return mat43.sizeof;
609                 case GL_FLOAT_MAT4x2:      return mat24.sizeof;
610                 case GL_FLOAT_MAT4x3:      return mat34.sizeof;
611                 case GL_DOUBLE_MAT2:       return mat2d.sizeof;
612                 case GL_DOUBLE_MAT3:       return mat3d.sizeof;
613                 case GL_DOUBLE_MAT4:       return mat4d.sizeof;
614                 case GL_DOUBLE_MAT2x3:     return mat32d.sizeof;
615                 case GL_DOUBLE_MAT2x4:     return mat42d.sizeof;
616                 case GL_DOUBLE_MAT3x2:     return mat23d.sizeof;
617                 case GL_DOUBLE_MAT3x4:     return mat43d.sizeof;
618                 case GL_DOUBLE_MAT4x2:     return mat24d.sizeof;
619                 case GL_DOUBLE_MAT4x3:     return mat34d.sizeof;
620 
621                     // image samplers
622                 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
623                     return int.sizeof;
624 
625                 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
626                     return uint.sizeof;
627 
628                 case GL_SAMPLER_1D:
629                 case GL_SAMPLER_2D:
630                 case GL_SAMPLER_3D:
631                 case GL_SAMPLER_CUBE:
632                 case GL_SAMPLER_1D_SHADOW:
633                 case GL_SAMPLER_2D_SHADOW:
634                 case GL_SAMPLER_1D_ARRAY:
635                 case GL_SAMPLER_2D_ARRAY:
636                 case GL_SAMPLER_1D_ARRAY_SHADOW:
637                 case GL_SAMPLER_2D_ARRAY_SHADOW:
638                 case GL_SAMPLER_2D_MULTISAMPLE:
639                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
640                 case GL_SAMPLER_CUBE_SHADOW:
641                 case GL_SAMPLER_BUFFER:
642                 case GL_SAMPLER_2D_RECT:
643                 case GL_SAMPLER_2D_RECT_SHADOW:
644                 case GL_INT_SAMPLER_1D:
645                 case GL_INT_SAMPLER_2D:
646                 case GL_INT_SAMPLER_3D:
647                 case GL_INT_SAMPLER_CUBE:
648                 case GL_INT_SAMPLER_1D_ARRAY:
649                 case GL_INT_SAMPLER_2D_ARRAY:
650                 case GL_INT_SAMPLER_2D_MULTISAMPLE:
651                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
652                 case GL_INT_SAMPLER_BUFFER:
653                 case GL_INT_SAMPLER_2D_RECT:
654                 case GL_UNSIGNED_INT_SAMPLER_1D:
655                 case GL_UNSIGNED_INT_SAMPLER_2D:
656                 case GL_UNSIGNED_INT_SAMPLER_3D:
657                 case GL_UNSIGNED_INT_SAMPLER_CUBE:
658                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
659                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
660                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
661                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
662                 case GL_UNSIGNED_INT_SAMPLER_BUFFER:
663                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
664                     return int.sizeof;
665 
666                 default:
667                     // unrecognized type
668                     // in debug mode assert, in release mode return 0 to disable this uniform
669                     debug
670                     {
671                         assert(false);
672                     }
673                     else
674                     {
675                         return 0;
676                     }
677             }
678         }
679 
680         static string GLSLTypeName(GLenum type) @safe pure nothrow @nogc 
681         {
682             switch (type)
683             {
684                 case GL_FLOAT:                                     return "float";
685                 case GL_FLOAT_VEC2:                                return "vec2";
686                 case GL_FLOAT_VEC3:                                return "vec3";
687                 case GL_FLOAT_VEC4:                                return "vec4";
688                 case GL_DOUBLE:                                    return "double";
689                 case GL_DOUBLE_VEC2:                               return "dvec2";
690                 case GL_DOUBLE_VEC3:                               return "dvec3";
691                 case GL_DOUBLE_VEC4:                               return "dvec4";
692                 case GL_INT:                                       return "int";
693                 case GL_INT_VEC2:                                  return "ivec2";
694                 case GL_INT_VEC3:                                  return "ivec3";
695                 case GL_INT_VEC4:                                  return "ivec4";
696                 case GL_UNSIGNED_INT:                              return "uint";
697                 case GL_UNSIGNED_INT_VEC2:                         return "uvec2";
698                 case GL_UNSIGNED_INT_VEC3:                         return "uvec3";
699                 case GL_UNSIGNED_INT_VEC4:                         return "uvec4";
700                 case GL_BOOL:                                      return "bool";
701                 case GL_BOOL_VEC2:                                 return "bvec2";
702                 case GL_BOOL_VEC3:                                 return "bvec3";
703                 case GL_BOOL_VEC4:                                 return "bvec4";
704                 case GL_FLOAT_MAT2:                                return "mat2";
705                 case GL_FLOAT_MAT3:                                return "mat3";
706                 case GL_FLOAT_MAT4:                                return "mat4";
707                 case GL_FLOAT_MAT2x3:                              return "mat2x3";
708                 case GL_FLOAT_MAT2x4:                              return "mat2x4";
709                 case GL_FLOAT_MAT3x2:                              return "mat3x2";
710                 case GL_FLOAT_MAT3x4:                              return "mat3x4";
711                 case GL_FLOAT_MAT4x2:                              return "mat4x2";
712                 case GL_FLOAT_MAT4x3:                              return "mat4x3";
713                 case GL_DOUBLE_MAT2:                               return "dmat2";
714                 case GL_DOUBLE_MAT3:                               return "dmat3";
715                 case GL_DOUBLE_MAT4:                               return "dmat4";
716                 case GL_DOUBLE_MAT2x3:                             return "dmat2x3";
717                 case GL_DOUBLE_MAT2x4:                             return "dmat2x4";
718                 case GL_DOUBLE_MAT3x2:                             return "dmat3x2";
719                 case GL_DOUBLE_MAT3x4:                             return "dmat3x4";
720                 case GL_DOUBLE_MAT4x2:                             return "dmat4x2";
721                 case GL_DOUBLE_MAT4x3:                             return "dmat4x3";
722                 case GL_SAMPLER_1D:                                return "sampler1D";
723                 case GL_SAMPLER_2D:                                return "sampler2D";
724                 case GL_SAMPLER_3D:                                return "sampler3D";
725                 case GL_SAMPLER_CUBE:                              return "samplerCube";
726                 case GL_SAMPLER_1D_SHADOW:                         return "sampler1DShadow";
727                 case GL_SAMPLER_2D_SHADOW:                         return "sampler2DShadow";
728                 case GL_SAMPLER_1D_ARRAY:                          return "sampler1DArray";
729                 case GL_SAMPLER_2D_ARRAY:                          return "sampler2DArray";
730                 case GL_SAMPLER_1D_ARRAY_SHADOW:                   return "sampler1DArrayShadow";
731                 case GL_SAMPLER_2D_ARRAY_SHADOW:                   return "sampler2DArrayShadow";
732                 case GL_SAMPLER_2D_MULTISAMPLE:                    return "sampler2DMS";
733                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:              return "sampler2DMSArray";
734                 case GL_SAMPLER_CUBE_SHADOW:                       return "samplerCubeShadow";
735                 case GL_SAMPLER_BUFFER:                            return "samplerBuffer";
736                 case GL_SAMPLER_2D_RECT:                           return "sampler2DRect";
737                 case GL_SAMPLER_2D_RECT_SHADOW:                    return "sampler2DRectShadow";
738                 case GL_INT_SAMPLER_1D:                            return "isampler1D";
739                 case GL_INT_SAMPLER_2D:                            return "isampler2D";
740                 case GL_INT_SAMPLER_3D:                            return "isampler3D";
741                 case GL_INT_SAMPLER_CUBE:                          return "isamplerCube";
742                 case GL_INT_SAMPLER_1D_ARRAY:                      return "isampler1DArray";
743                 case GL_INT_SAMPLER_2D_ARRAY:                      return "isampler2DArray";
744                 case GL_INT_SAMPLER_2D_MULTISAMPLE:                return "isampler2DMS";
745                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:          return "isampler2DMSArray";
746                 case GL_INT_SAMPLER_BUFFER:                        return "isamplerBuffer";
747                 case GL_INT_SAMPLER_2D_RECT:                       return "isampler2DRect";
748                 case GL_UNSIGNED_INT_SAMPLER_1D:                   return "usampler1D";
749                 case GL_UNSIGNED_INT_SAMPLER_2D:                   return "usampler2D";
750                 case GL_UNSIGNED_INT_SAMPLER_3D:                   return "usampler3D";
751                 case GL_UNSIGNED_INT_SAMPLER_CUBE:                 return "usamplerCube";
752                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:             return "usampler2DArray";
753                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:             return "usampler2DArray";
754                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:       return "usampler2DMS";
755                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "usampler2DMSArray";
756                 case GL_UNSIGNED_INT_SAMPLER_BUFFER:               return "usamplerBuffer";
757                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:              return "usampler2DRect";
758                 case GL_IMAGE_1D:                                  return "image1D";
759                 case GL_IMAGE_2D:                                  return "image2D";
760                 case GL_IMAGE_3D:                                  return "image3D";
761                 case GL_IMAGE_2D_RECT:                             return "image2DRect";
762                 case GL_IMAGE_CUBE:                                return "imageCube";
763                 case GL_IMAGE_BUFFER:                              return "imageBuffer";
764                 case GL_IMAGE_1D_ARRAY:                            return "image1DArray";
765                 case GL_IMAGE_2D_ARRAY:                            return "image2DArray";
766                 case GL_IMAGE_2D_MULTISAMPLE:                      return "image2DMS";
767                 case GL_IMAGE_2D_MULTISAMPLE_ARRAY:                return "image2DMSArray";
768                 case GL_INT_IMAGE_1D:                              return "iimage1D";
769                 case GL_INT_IMAGE_2D:                              return "iimage2D";
770                 case GL_INT_IMAGE_3D:                              return "iimage3D";
771                 case GL_INT_IMAGE_2D_RECT:                         return "iimage2DRect";
772                 case GL_INT_IMAGE_CUBE:                            return "iimageCube";
773                 case GL_INT_IMAGE_BUFFER:                          return "iimageBuffer";
774                 case GL_INT_IMAGE_1D_ARRAY:                        return "iimage1DArray";
775                 case GL_INT_IMAGE_2D_ARRAY:                        return "iimage2DArray";
776                 case GL_INT_IMAGE_2D_MULTISAMPLE:                  return "iimage2DMS";
777                 case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:            return "iimage2DMSArray";
778                 case GL_UNSIGNED_INT_IMAGE_1D:                     return "uimage1D";
779                 case GL_UNSIGNED_INT_IMAGE_2D:                     return "uimage2D";
780                 case GL_UNSIGNED_INT_IMAGE_3D:                     return "uimage3D";
781                 case GL_UNSIGNED_INT_IMAGE_2D_RECT:                return "uimage2DRect";
782                 case GL_UNSIGNED_INT_IMAGE_CUBE:                   return "uimageCube";
783                 case GL_UNSIGNED_INT_IMAGE_BUFFER:                 return "uimageBuffer";
784                 case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:               return "uimage1DArray";
785                 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:               return "uimage2DArray";
786                 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:         return "uimage2DMS";
787                 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:   return "uimage2DMSArray";
788                 case GL_UNSIGNED_INT_ATOMIC_COUNTER:               return "atomic_uint";
789                 default:
790                     return "unknown";
791             }
792         }
793 
794         static string GLSLTypeNameArray(GLenum type, size_t multiplicity)
795         {
796             assert(multiplicity > 0);
797             if (multiplicity == 1)
798                 return GLSLTypeName(type);
799             else
800                 return format("%s[%s]", GLSLTypeName(type), multiplicity);
801         }
802     }
803 }
804 
805 static assert(is(GLint == int));
806 static assert(is(GLuint == uint));
807 static assert(is(GLfloat == float));
808 static assert(is(GLdouble == double));