1 /+
2 The MIT License (MIT)
3 
4     Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)>
5 
6     Permission is hereby granted, free of charge, to any person obtaining a copy
7     of this software and associated documentation files (the "Software"), to deal
8     in the Software without restriction, including without limitation the rights
9     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10     copies of the Software, and to permit persons to whom the Software is
11     furnished to do so, subject to the following conditions:
12 
13     The above copyright notice and this permission notice shall be included in
14     all copies or substantial portions of the Software.
15 
16     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22     THE SOFTWARE.
23 +/
24 
25 module des.gl.base.texture;
26 
27 import std.string;
28 
29 public import derelict.opengl3.gl3;
30 
31 import des.gl.base.type;
32 
33 import des.il;
34 
35 import std.algorithm;
36 import des.util.stdext.algorithm;
37 
38 ///
39 class GLTextureException : DesGLException 
40 { 
41     ///
42     this( string msg, string file=__FILE__, size_t line=__LINE__ ) @safe pure nothrow
43     { super( msg, file, line ); } 
44 }
45 
46 ///
47 class GLTexture : DesObject
48 {
49     mixin DES;
50     mixin ClassLogger;
51 private:
52     uint _id;
53 
54 protected:
55     ///
56     texsize_t img_size;
57 
58     override void selfDestroy()
59     {
60         unbind();
61         checkGLCall!glDeleteTextures( 1, &_id );
62     }
63 
64     ///
65     Target _target;
66 
67     ///
68     nothrow @property GLenum gltype() const { return cast(GLenum)_target; }
69 
70     ///
71     InternalFormat liformat;
72     ///
73     Format lformat;
74     ///
75     Type ltype;
76 
77 public:
78 
79     alias SizeVector!3 texsize_t; 
80 
81     ///
82     @property Target target() const { return _target; }
83 
84     ///
85     enum Target
86     {
87         T1D                   = GL_TEXTURE_1D,                   /// `GL_TEXTURE_1D`
88         T2D                   = GL_TEXTURE_2D,                   /// `GL_TEXTURE_2D`
89         T3D                   = GL_TEXTURE_3D,                   /// `GL_TEXTURE_3D`
90         T1D_ARRAY             = GL_TEXTURE_1D_ARRAY,             /// `GL_TEXTURE_1D_ARRAY`
91         T2D_ARRAY             = GL_TEXTURE_2D_ARRAY,             /// `GL_TEXTURE_2D_ARRAY`
92         RECTANGLE             = GL_TEXTURE_RECTANGLE,            /// `GL_TEXTURE_RECTANGLE`
93         CUBE_MAP              = GL_TEXTURE_CUBE_MAP,             /// `GL_TEXTURE_CUBE_MAP`
94         CUBE_MAP_ARRAY        = GL_TEXTURE_CUBE_MAP_ARRAY,       /// `GL_TEXTURE_CUBE_MAP_ARRAY`
95 
96         BUFFER                = GL_TEXTURE_BUFFER,               /// `GL_TEXTURE_BUFFER`
97         T2D_MULTISAMPLE       = GL_TEXTURE_2D_MULTISAMPLE,       /// `GL_TEXTURE_2D_MULTISAMPLE`
98         T2D_MULTISAMPLE_ARRAY = GL_TEXTURE_2D_MULTISAMPLE_ARRAY, /// `GL_TEXTURE_2D_MULTISAMPLE_ARRAY`
99 
100         CUBE_MAP_POSITIVE_X   = GL_TEXTURE_CUBE_MAP_POSITIVE_X,  /// `GL_TEXTURE_CUBE_MAP_POSITIVE_X`
101         CUBE_MAP_NEGATIVE_X   = GL_TEXTURE_CUBE_MAP_NEGATIVE_X,  /// `GL_TEXTURE_CUBE_MAP_NEGATIVE_X`
102         CUBE_MAP_POSITIVE_Y   = GL_TEXTURE_CUBE_MAP_POSITIVE_Y,  /// `GL_TEXTURE_CUBE_MAP_POSITIVE_Y`
103         CUBE_MAP_NEGATIVE_Y   = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,  /// `GL_TEXTURE_CUBE_MAP_NEGATIVE_Y`
104         CUBE_MAP_POSITIVE_Z   = GL_TEXTURE_CUBE_MAP_POSITIVE_Z,  /// `GL_TEXTURE_CUBE_MAP_POSITIVE_Z`
105         CUBE_MAP_NEGATIVE_Z   = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z   /// `GL_TEXTURE_CUBE_MAP_NEGATIVE_Z`
106     }
107 
108     ///
109     enum Parameter
110     {
111         DEPTH_STENCIL_TEXTURE_MODE = GL_DEPTH_STENCIL_TEXTURE_MODE, /// `GL_DEPTH_STENCIL_TEXTURE_MODE`
112         BASE_LEVEL                 = GL_TEXTURE_BASE_LEVEL,         /// `GL_TEXTURE_BASE_LEVEL`
113         BORDER_COLOR               = GL_TEXTURE_BORDER_COLOR,       /// `GL_TEXTURE_BORDER_COLOR`
114         COMPARE_FUNC               = GL_TEXTURE_COMPARE_FUNC,       /// `GL_TEXTURE_COMPARE_FUNC`
115         COMPARE_MODE               = GL_TEXTURE_COMPARE_MODE,       /// `GL_TEXTURE_COMPARE_MODE`
116         LOD_BIAS                   = GL_TEXTURE_LOD_BIAS,           /// `GL_TEXTURE_LOD_BIAS`
117         MIN_FILTER                 = GL_TEXTURE_MIN_FILTER,         /// `GL_TEXTURE_MIN_FILTER`
118         MAG_FILTER                 = GL_TEXTURE_MAG_FILTER,         /// `GL_TEXTURE_MAG_FILTER`
119         MIN_LOD                    = GL_TEXTURE_MIN_LOD,            /// `GL_TEXTURE_MIN_LOD`
120         MAX_LOD                    = GL_TEXTURE_MAX_LOD,            /// `GL_TEXTURE_MAX_LOD`
121         MAX_LEVEL                  = GL_TEXTURE_MAX_LEVEL,          /// `GL_TEXTURE_MAX_LEVEL`
122         SWIZZLE_R                  = GL_TEXTURE_SWIZZLE_R,          /// `GL_TEXTURE_SWIZZLE_R`
123         SWIZZLE_G                  = GL_TEXTURE_SWIZZLE_G,          /// `GL_TEXTURE_SWIZZLE_G`
124         SWIZZLE_B                  = GL_TEXTURE_SWIZZLE_B,          /// `GL_TEXTURE_SWIZZLE_B`
125         SWIZZLE_A                  = GL_TEXTURE_SWIZZLE_A,          /// `GL_TEXTURE_SWIZZLE_A`
126         SWIZZLE_RGBA               = GL_TEXTURE_SWIZZLE_RGBA,       /// `GL_TEXTURE_SWIZZLE_RGBA`
127         WRAP_S                     = GL_TEXTURE_WRAP_S,             /// `GL_TEXTURE_WRAP_S`
128         WRAP_T                     = GL_TEXTURE_WRAP_T,             /// `GL_TEXTURE_WRAP_T`
129         WRAP_R                     = GL_TEXTURE_WRAP_R              /// `GL_TEXTURE_WRAP_R`
130     }
131 
132     ///
133     enum DepthStencilTextureMode
134     {
135         DEPTH   = GL_DEPTH_COMPONENT,   /// `GL_DEPTH_COMPONENT`
136         STENCIL = GL_STENCIL_COMPONENTS /// `GL_STENCIL_COMPONENTS`
137     }
138 
139     ///
140     enum CompareFunc
141     {
142         LEQUAL   = GL_LEQUAL,   /// `GL_LEQUAL`
143         GEQUAL   = GL_GEQUAL,   /// `GL_GEQUAL`
144         LESS     = GL_LESS,     /// `GL_LESS`
145         GREATER  = GL_GREATER,  /// `GL_GREATER`
146         EQUAL    = GL_EQUAL,    /// `GL_EQUAL`
147         NOTEQUAL = GL_NOTEQUAL, /// `GL_NOTEQUAL`
148         ALWAYS   = GL_ALWAYS,   /// `GL_ALWAYS`
149         NEVER    = GL_NEVER     /// `GL_NEVER`
150     }
151 
152     ///
153     enum CompareMode
154     {
155         REF_TO_TEXTURE = GL_COMPARE_REF_TO_TEXTURE, /// `GL_COMPARE_REF_TO_TEXTURE`
156         NONE = GL_NONE /// `GL_NONE`
157     }
158 
159     ///
160     enum Filter
161     {
162         NEAREST                = GL_NEAREST,                /// `GL_NEAREST`
163         LINEAR                 = GL_LINEAR,                 /// `GL_LINEAR`
164         NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST, /// `GL_NEAREST_MIPMAP_NEAREST`
165         LINEAR_MIPMAP_NEAREST  = GL_LINEAR_MIPMAP_NEAREST,  /// `GL_LINEAR_MIPMAP_NEAREST`
166         NEAREST_MIPMAP_LINEAR  = GL_NEAREST_MIPMAP_LINEAR,  /// `GL_NEAREST_MIPMAP_LINEAR`
167         LINEAR_MIPMAP_LINEAR   = GL_LINEAR_MIPMAP_LINEAR    /// `GL_LINEAR_MIPMAP_LINEAR`
168     }
169 
170     ///
171     enum Swizzle
172     {
173         RED   = GL_RED,  /// `GL_RED`
174         GREEN = GL_GREEN,/// `GL_GREEN`
175         BLUE  = GL_BLUE, /// `GL_BLUE`
176         ALPHA = GL_ALPHA,/// `GL_ALPHA`
177         ZERO  = GL_ZERO  /// `GL_ZERO`
178     }
179 
180     ///
181     enum Wrap
182     {
183         CLAMP_TO_EDGE   = GL_CLAMP_TO_EDGE,   /// `GL_CLAMP_TO_EDGE`
184         CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER, /// `GL_CLAMP_TO_BORDER`
185         MIRRORED_REPEAT = GL_MIRRORED_REPEAT, /// `GL_MIRRORED_REPEAT`
186         REPEAT          = GL_REPEAT           /// `GL_REPEAT`
187     }
188 
189     ///
190     enum InternalFormat
191     {
192         COMPRESSED_RED        = GL_COMPRESSED_RED,        /// `GL_COMPRESSED_RED`
193         COMPRESSED_RG         = GL_COMPRESSED_RG,         /// `GL_COMPRESSED_RG`
194         COMPRESSED_RGB        = GL_COMPRESSED_RGB,        /// `GL_COMPRESSED_RGB`
195         COMPRESSED_RGBA       = GL_COMPRESSED_RGBA,       /// `GL_COMPRESSED_RGBA`
196         COMPRESSED_SRGB       = GL_COMPRESSED_SRGB,       /// `GL_COMPRESSED_SRGB`
197         COMPRESSED_SRGB_ALPHA = GL_COMPRESSED_SRGB_ALPHA, /// `GL_COMPRESSED_SRGB_ALPHA`
198         DEPTH_COMPONENT       = GL_DEPTH_COMPONENT,       /// `GL_DEPTH_COMPONENT`
199         DEPTH_COMPONENT16     = GL_DEPTH_COMPONENT16,     /// `GL_DEPTH_COMPONENT16`
200         DEPTH_COMPONENT24     = GL_DEPTH_COMPONENT24,     /// `GL_DEPTH_COMPONENT24`
201         DEPTH_COMPONENT32     = GL_DEPTH_COMPONENT32,     /// `GL_DEPTH_COMPONENT32`
202         DEPTH_COMPONENT32F    = GL_DEPTH_COMPONENT32F,    /// `GL_DEPTH_COMPONENT32F`
203         R3_G3_B2              = GL_R3_G3_B2,              /// `GL_R3_G3_B2`
204         RED                   = GL_RED,                   /// `GL_RED`
205         RG                    = GL_RG,                    /// `GL_RG`
206         RGB                   = GL_RGB,                   /// `GL_RGB`
207         RGB4                  = GL_RGB4,                  /// `GL_RGB4`
208         RGB5                  = GL_RGB5,                  /// `GL_RGB5`
209         RGB8                  = GL_RGB8,                  /// `GL_RGB8`
210         RGB10                 = GL_RGB10,                 /// `GL_RGB10`
211         RGB12                 = GL_RGB12,                 /// `GL_RGB12`
212         RGB16                 = GL_RGB16,                 /// `GL_RGB16`
213         RGBA                  = GL_RGBA,                  /// `GL_RGBA`
214         RGBA2                 = GL_RGBA2,                 /// `GL_RGBA2`
215         RGBA4                 = GL_RGBA4,                 /// `GL_RGBA4`
216         RGB5_A1               = GL_RGB5_A1,               /// `GL_RGB5_A1`
217         RGBA8                 = GL_RGBA8,                 /// `GL_RGBA8`
218         RGB10_A2              = GL_RGB10_A2,              /// `GL_RGB10_A2`
219         RGBA12                = GL_RGBA12,                /// `GL_RGBA12`
220         RGBA16                = GL_RGBA16,                /// `GL_RGBA16`
221         SRGB                  = GL_SRGB,                  /// `GL_SRGB`
222         SRGB8                 = GL_SRGB8,                 /// `GL_SRGB8`
223         SRGB_ALPHA            = GL_SRGB_ALPHA,            /// `GL_SRGB_ALPHA`
224         SRGB8_ALPHA8          = GL_SRGB8_ALPHA8           /// `GL_SRGB8_ALPHA8`
225     }
226 
227     ///
228     enum Format
229     {
230         RED  = GL_RED,  /// `GL_RED`
231         RG   = GL_RG,   /// `GL_RG`
232         RGB  = GL_RGB,  /// `GL_RGB`
233         RGBA = GL_RGBA, /// `GL_RGBA`
234 
235         BGR  = GL_BGR,  /// `GL_BGR`
236         BGRA = GL_BGRA, /// `GL_BGRA`
237 
238         DEPTH = GL_DEPTH_COMPONENT, /// `GL_DEPTH_COMPONENT`
239         DEPTH_STENCIL = GL_DEPTH_STENCIL /// `GL_DEPTH_STENCIL`
240     }
241 
242     ///
243     enum Type
244     {
245         UNSIGNED_BYTE  = GL_UNSIGNED_BYTE,  /// `GL_UNSIGNED_BYTE`
246         BYTE           = GL_BYTE,           /// `GL_BYTE`
247         UNSIGNED_SHORT = GL_UNSIGNED_SHORT, /// `GL_UNSIGNED_SHORT`
248         SHORT          = GL_SHORT,          /// `GL_SHORT`
249         UNSIGNED_INT   = GL_UNSIGNED_INT,   /// `GL_UNSIGNED_INT`
250         INT            = GL_INT,            /// `GL_INT`
251         HALF_FLOAT     = GL_HALF_FLOAT,     /// `GL_HALF_FLOAT`
252         FLOAT          = GL_FLOAT,          /// `GL_FLOAT`
253 
254         UNSIGNED_BYTE_3_3_2             = GL_UNSIGNED_BYTE_3_3_2,           /// `GL_UNSIGNED_BYTE_3_3_2`
255         UNSIGNED_BYTE_2_3_3_REV         = GL_UNSIGNED_BYTE_2_3_3_REV,       /// `GL_UNSIGNED_BYTE_2_3_3_REV`
256         UNSIGNED_SHORT_5_6_5            = GL_UNSIGNED_SHORT_5_6_5,          /// `GL_UNSIGNED_SHORT_5_6_5`
257         UNSIGNED_SHORT_5_6_5_REV        = GL_UNSIGNED_SHORT_5_6_5_REV,      /// `GL_UNSIGNED_SHORT_5_6_5_REV`
258         UNSIGNED_SHORT_4_4_4_4          = GL_UNSIGNED_SHORT_4_4_4_4,        /// `GL_UNSIGNED_SHORT_4_4_4_4`
259         UNSIGNED_SHORT_4_4_4_4_REV      = GL_UNSIGNED_SHORT_4_4_4_4_REV,    /// `GL_UNSIGNED_SHORT_4_4_4_4_REV`
260         UNSIGNED_SHORT_5_5_5_1          = GL_UNSIGNED_SHORT_5_5_5_1,        /// `GL_UNSIGNED_SHORT_5_5_5_1`
261         UNSIGNED_SHORT_1_5_5_5_REV      = GL_UNSIGNED_SHORT_1_5_5_5_REV,    /// `GL_UNSIGNED_SHORT_1_5_5_5_REV`
262         UNSIGNED_INT_8_8_8_8            = GL_UNSIGNED_INT_8_8_8_8,          /// `GL_UNSIGNED_INT_8_8_8_8`
263         UNSIGNED_INT_8_8_8_8_REV        = GL_UNSIGNED_INT_8_8_8_8_REV,      /// `GL_UNSIGNED_INT_8_8_8_8_REV`
264         UNSIGNED_INT_10_10_10_2         = GL_UNSIGNED_INT_10_10_10_2,       /// `GL_UNSIGNED_INT_10_10_10_2`
265         UNSIGNED_INT_2_10_10_10_REV     = GL_UNSIGNED_INT_2_10_10_10_REV,   /// `GL_UNSIGNED_INT_2_10_10_10_REV`
266         UNSIGNED_INT_24_8               = GL_UNSIGNED_INT_24_8,             /// `GL_UNSIGNED_INT_24_8`
267         UNSIGNED_INT_10F_11F_11F_REV    = GL_UNSIGNED_INT_10F_11F_11F_REV,  /// `GL_UNSIGNED_INT_10F_11F_11F_REV`
268         UNSIGNED_INT_5_9_9_9_REV        = GL_UNSIGNED_INT_5_9_9_9_REV,      /// `GL_UNSIGNED_INT_5_9_9_9_REV`
269         FLOAT_32_UNSIGNED_INT_24_8_REV  = GL_FLOAT_32_UNSIGNED_INT_24_8_REV /// `GL_FLOAT_32_UNSIGNED_INT_24_8_REV`
270     }
271 
272     ///
273     this( Target tg )
274     in { assert( isBase(tg) ); } body
275     {
276         checkGLCall!glGenTextures( 1, &_id );
277         logger = new InstanceLogger( this, format( "%d", _id ) );
278         _target = tg;
279         logger.Debug( "with target [%s]", _target );
280     }
281 
282     ///
283     final pure const @property uint id() { return _id; }
284 
285     /// bind, glGenerateMipmap
286     void genMipmap()
287     in { assert( isMipmapable(_target) ); } body
288     {
289         bind();
290         checkGLCall!glGenerateMipmap(gltype);
291         logger.Debug( "with target [%s]", _target );
292     }
293 
294     ///
295     void setParameter(T)( Parameter pname, T[] val... )
296         if( is(T==int) || is(T==float) || isParameterEnum!T )
297     in
298     {
299         assert( val.length > 0 );
300         assert( isParametric(_target) );
301         static if( !is(T==float) )
302             assert( checkPosibleIntParamValues( pname, amap!(a=>cast(int)(a))(val) ) );
303         else
304             assert( checkPosibleFloatParamValues( pname, val ) );
305     }
306     body
307     {
308         bind();
309         enum ts = is(T==float) ? "f" : "i";
310         enum cs = is(T==float) ? "float" : "int";
311         if( val.length == 1 )
312             mixin( format("glTexParameter%s( gltype, cast(GLenum)pname, cast(%s)val[0] );", ts, cs) );
313         else 
314             mixin( format("glTexParameter%sv( gltype, cast(GLenum)pname, cast(%s*)val.ptr );", ts, cs) ); 
315 
316         debug checkGL;
317         logger.Debug( "[%s]: %s", pname, val );
318     }
319 
320     final nothrow
321     {
322         /// glActiveTexture, glBindTexture
323         void bind( ubyte n=0 )
324         {
325             ntCheckGLCall!glActiveTexture( GL_TEXTURE0 + n );
326             ntCheckGLCall!glBindTexture( gltype, _id );
327             debug logger.trace( "pass" );
328         }
329 
330         ///
331         void unbind()
332         {
333             ntCheckGLCall!glBindTexture( gltype, 0 );
334             debug logger.trace( "pass" );
335         }
336 
337         ///
338         texsize_t size() const { return img_size; }
339     }
340 
341     ///
342     void resize(T)( in T sz )
343         if( isCompatibleVector!(1,size_t,T) || isCompatibleVector!(2,size_t,T) || isCompatibleVector!(3,size_t,T) )
344     { image( sz, liformat, lformat, ltype ); }
345 
346     /// set image
347     void image(T)( in T sz, InternalFormat internal_format, 
348             Format data_format, Type data_type, in void* data=null )
349         if( isCompatibleVector!(1,size_t,T) || isCompatibleVector!(2,size_t,T) || isCompatibleVector!(3,size_t,T) )
350     {
351         enum N = sz.length;
352         img_size = texsize_t( sz, [1,1][0 .. 3-N] );
353 
354         liformat = internal_format;
355         lformat = data_format;
356         ltype = data_type;
357 
358         bind();
359         mixin( format(`
360         glTexImage%1dD( gltype, 0, cast(int)internal_format, %s, 0,
361                         cast(GLenum)data_format, cast(GLenum)data_type, data );
362         `, N, accessVecFields!(sz) ) );
363 
364         debug checkGL;
365         debug logger.trace( "[%d]: size %s, internal format [%s], format [%s], type [%s], with data [%s]",
366                 _id, sz.data.dup, internal_format, data_format, data_type, data?true:false );
367     }
368 
369     /// ditto
370     final void image(size_t N)( in Image!N img ) if( N >= 1 && N <= 3 )
371     in
372     {
373         switch( N )
374         {
375             case 1: assert( target == Target.T1D ); break;
376             case 2: assert( target == Target.T2D ); break;
377             case 3: assert( target == Target.T3D ); break;
378             default: assert(0);
379         }
380     }
381     body
382     {
383         Type type = typeFromImageDataType( img.info.comp );
384         auto fmt = formatFromImageChanelsCount( img.info.channels );
385         image( img.size, fmt[0], fmt[1], type, img.data.ptr );
386     }
387 
388     ///
389     final void getImage( ref Image!2 img )
390     in { assert( _target == Target.T2D ); } body
391     { getImage( img, ltype ); }
392 
393     ///
394     final void getImage( ref Image!2 img, Type type )
395     in { assert( _target == Target.T2D ); } body
396     {
397         enum uint level = 0;
398 
399         bind();
400         debug checkGL;
401         int w, h;
402         glGetTexLevelParameteriv( GL_TEXTURE_2D, level, GL_TEXTURE_WIDTH, &(w));
403         debug checkGL;
404         glGetTexLevelParameteriv( GL_TEXTURE_2D, level, GL_TEXTURE_HEIGHT, &(h));
405         debug checkGL;
406 
407         auto elemSize = formatElemCount(lformat) * sizeofType(type);
408 
409         auto dsize = w * h * elemSize;
410 
411         if( img.size != SizeVector!2(w,h) || img.info.bpe != elemSize )
412         {
413             img.size = ivec2( w, h );
414             img.info = imageElemInfo( lformat, type );
415         }
416 
417         glGetTexImage( GL_TEXTURE_2D, level, cast(GLenum)lformat, cast(GLenum)type, img.data.ptr );
418         debug checkGL;
419         unbind();
420         debug checkGL;
421         debug logger.trace( "[%d] size [%d,%d], format [%s], type [%s]", _id, w,h, lformat, type );
422     }
423 
424     protected static
425     {
426         ///
427         bool isBase( Target trg )
428         {
429             switch(trg)
430             {
431             case Target.T1D:
432             case Target.T2D:
433             case Target.T3D:
434             case Target.T1D_ARRAY:
435             case Target.T2D_ARRAY:
436             case Target.RECTANGLE:
437             case Target.CUBE_MAP:
438             case Target.CUBE_MAP_ARRAY: return true;
439             default: return false;
440             }
441         }
442 
443         ///
444         bool isParametric( Target trg )
445         {
446             switch(trg)
447             {
448             case Target.T1D:
449             case Target.T2D:
450             case Target.T3D:
451             case Target.T1D_ARRAY:
452             case Target.T2D_ARRAY:
453             case Target.RECTANGLE:
454             case Target.CUBE_MAP: return true;
455             default: return false;
456             }
457         }
458 
459         ///
460         bool isMipmapable( Target trg )
461         {
462             switch(trg)
463             {
464             case Target.T1D:
465             case Target.T2D:
466             case Target.T3D:
467             case Target.T1D_ARRAY:
468             case Target.T2D_ARRAY:
469             case Target.CUBE_MAP: return true;
470             default: return false;
471             }
472         }
473 
474         ///
475         bool checkPosibleIntParamValues( Parameter pname, int[] valbuf... )
476         {
477             if( valbuf.length == 0 ) return false;
478 
479             size_t count = valbuf.length;
480             bool single = count == 1;
481             auto val = valbuf[0];
482 
483             final switch(pname)
484             {
485             case Parameter.DEPTH_STENCIL_TEXTURE_MODE: return single && oneOf!DepthStencilTextureMode(val);
486             case Parameter.BASE_LEVEL:   return single && val >= 0;
487             case Parameter.BORDER_COLOR: return count == 4 && all!(a=>a>=0)(valbuf);
488             case Parameter.COMPARE_FUNC: return single && oneOf!CompareFunc(val);
489             case Parameter.COMPARE_MODE: return single && oneOf!CompareMode(val);
490             case Parameter.LOD_BIAS:     return false; // is float
491             case Parameter.MIN_FILTER:   return single && oneOf!Filter(val);
492             case Parameter.MAG_FILTER:   return single && oneOf( [Filter.NEAREST,Filter.LINEAR], val );
493             case Parameter.MIN_LOD:      return false; // is float
494             case Parameter.MAX_LOD:      return false; // is float
495             case Parameter.MAX_LEVEL:    return single;  // initial is 1000, no info in documentation
496 
497             case Parameter.SWIZZLE_R: 
498             case Parameter.SWIZZLE_G: 
499             case Parameter.SWIZZLE_B: 
500             case Parameter.SWIZZLE_A:
501                 return single && oneOf!Swizzle(val);
502 
503             case Parameter.SWIZZLE_RGBA: return count == 4 && all!(a=>oneOf!Swizzle(a))(valbuf);
504 
505             case Parameter.WRAP_S:
506             case Parameter.WRAP_T:
507             case Parameter.WRAP_R:
508                 return single && oneOf!Wrap(val);
509             }
510         }
511 
512         ///
513         bool checkPosibleFloatParamValues( Parameter pname, float[] valbuf... )
514         {
515             if( valbuf.length == 0 ) return false;
516 
517             size_t count = valbuf.length;
518             bool single = count == 1;
519             auto val = valbuf[0];
520 
521             switch(pname)
522             {
523             case Parameter.LOD_BIAS:
524             case Parameter.MIN_LOD:
525             case Parameter.MAX_LOD:
526                 return single;
527             case Parameter.BORDER_COLOR: return count == 4;
528             default: return false; // is integer;
529             }
530         }
531 
532         ///
533         size_t formatElemCount( Format fmt )
534         {
535             final switch(fmt)
536             {
537                 case Format.RED: return 1;
538                 case Format.RG:  return 2;
539 
540                 case Format.RGB:
541                 case Format.BGR:
542                     return 3;
543 
544                 case Format.RGBA:
545                 case Format.BGRA:
546                     return 4;
547 
548                 case Format.DEPTH:
549                     return 1;
550 
551                 case Format.DEPTH_STENCIL:
552                     return 2;
553             }
554         }
555 
556         ///
557         size_t sizeofType( Type type )
558         {
559             final switch(type)
560             {
561             case Type.BYTE:          
562             case Type.UNSIGNED_BYTE:
563             case Type.UNSIGNED_BYTE_3_3_2:
564             case Type.UNSIGNED_BYTE_2_3_3_REV:
565                 return byte.sizeof;
566 
567             case Type.SHORT:
568             case Type.UNSIGNED_SHORT:
569             case Type.UNSIGNED_SHORT_5_6_5:
570             case Type.UNSIGNED_SHORT_5_6_5_REV:
571             case Type.UNSIGNED_SHORT_4_4_4_4:
572             case Type.UNSIGNED_SHORT_4_4_4_4_REV:
573             case Type.UNSIGNED_SHORT_5_5_5_1:
574             case Type.UNSIGNED_SHORT_1_5_5_5_REV:
575                 return short.sizeof;
576 
577             case Type.INT:
578             case Type.UNSIGNED_INT:
579             case Type.UNSIGNED_INT_8_8_8_8:
580             case Type.UNSIGNED_INT_8_8_8_8_REV:
581             case Type.UNSIGNED_INT_10_10_10_2:
582             case Type.UNSIGNED_INT_2_10_10_10_REV:
583             case Type.UNSIGNED_INT_24_8:
584             case Type.UNSIGNED_INT_10F_11F_11F_REV:
585             case Type.UNSIGNED_INT_5_9_9_9_REV:
586             case Type.FLOAT_32_UNSIGNED_INT_24_8_REV:
587                 return int.sizeof;
588 
589             case Type.HALF_FLOAT: return float.sizeof / 2;
590             case Type.FLOAT: return float.sizeof;
591             }
592         }
593 
594         ///
595         auto imageElemInfo( Format fmt, Type type )
596         {
597             auto cnt = formatElemCount(fmt);
598             auto ict = imageDataType(type);
599             if( ict == DataType.RAWBYTE )
600                 return ElemInfo( sizeofType(type) * cnt );
601             else
602                 return ElemInfo( ict, cnt );
603         }
604 
605         ///
606         DataType imageDataType( Type type )
607         {
608             switch( type )
609             {
610                 case Type.BYTE:           return DataType.BYTE;
611                 case Type.UNSIGNED_BYTE:  return DataType.UBYTE;
612                 case Type.SHORT:          return DataType.SHORT;
613                 case Type.UNSIGNED_SHORT: return DataType.USHORT;
614                 case Type.INT:            return DataType.INT;
615                 case Type.UNSIGNED_INT:   return DataType.UINT;
616                 case Type.FLOAT:          return DataType.FLOAT;
617                 default:                  return DataType.RAWBYTE;
618             }
619         }
620 
621         ///
622         @property bool isParameterEnum(T)()
623         {
624             return is(T==DepthStencilTextureMode) ||
625                    is(T==CompareFunc) ||
626                    is(T==CompareMode) ||
627                    is(T==Filter) ||
628                    is(T==Swizzle) ||
629                    is(T==Wrap);
630         }
631 
632         ///
633         Type typeFromImageDataType( DataType ctype )
634         {
635             switch( ctype )
636             {
637                 case DataType.BYTE:     return Type.BYTE;
638                 case DataType.UBYTE:
639                 case DataType.RAWBYTE:  return Type.UNSIGNED_BYTE;
640                 case DataType.SHORT:    return Type.SHORT;
641                 case DataType.USHORT:   return Type.UNSIGNED_SHORT;
642                 case DataType.INT:      return Type.INT;
643                 case DataType.UINT:     return Type.UNSIGNED_INT;
644                 case DataType.NORM_FIXED: return Type.INT;
645                 case DataType.UNORM_FIXED: return Type.UNSIGNED_INT;
646                 case DataType.FLOAT:    return Type.FLOAT;
647                 default:
648                     throw new GLTextureException( "uncompatible image component type" );
649             }
650         }
651 
652         ///
653         auto formatFromImageChanelsCount( size_t channels )
654         {
655             switch( channels )
656             {
657                 case 1: return tuple(InternalFormat.RED,  Format.RED  );
658                 case 2: return tuple(InternalFormat.RG,   Format.RG   );
659                 case 3: return tuple(InternalFormat.RGB,  Format.RGB  );
660                 case 4: return tuple(InternalFormat.RGBA, Format.RGBA );
661                 default:
662                     throw new GLTextureException( "uncompatible image chanels count" );
663             }
664         }
665     }
666 }
667 
668 private @property string accessVecFields(alias T)()
669 {
670     string[] ret;
671     foreach( i; 0 .. T.length )
672         ret ~= format( "cast(int)(%s[%d])", T.stringof, i );
673     return ret.join(",");
674 }