1 module des.gl.texture;
2 
3 import std..string;
4 
5 import des.gl.general;
6 
7 public import des.il;
8 
9 import std.algorithm;
10 import des.util.stdext.algorithm;
11 
12 ///
13 class GLTextureException : DesGLException
14 {
15     ///
16     this( string msg, string file=__FILE__, size_t line=__LINE__ ) @safe pure nothrow
17     { super( msg, file, line ); }
18 }
19 
20 ///
21 abstract class GLTexture : GLObject!("Texture",false)
22 {
23     mixin DES;
24     mixin ClassLogger;
25 
26 protected:
27 
28     ///
29     InternalFormat liformat;
30     ///
31     Format lformat;
32     ///
33     Type ltype;
34 
35     /// texture unit
36     uint _unit;
37 
38     uivec3 _size;
39 
40 public:
41 
42     ///
43     enum InternalFormat
44     {
45         COMPRESSED_RED        = GL_COMPRESSED_RED,        /// `GL_COMPRESSED_RED`
46         COMPRESSED_RG         = GL_COMPRESSED_RG,         /// `GL_COMPRESSED_RG`
47         COMPRESSED_RGB        = GL_COMPRESSED_RGB,        /// `GL_COMPRESSED_RGB`
48         COMPRESSED_RGBA       = GL_COMPRESSED_RGBA,       /// `GL_COMPRESSED_RGBA`
49         COMPRESSED_SRGB       = GL_COMPRESSED_SRGB,       /// `GL_COMPRESSED_SRGB`
50         COMPRESSED_SRGB_ALPHA = GL_COMPRESSED_SRGB_ALPHA, /// `GL_COMPRESSED_SRGB_ALPHA`
51         DEPTH                 = GL_DEPTH_COMPONENT,       /// `GL_DEPTH_COMPONENT`
52         DEPTH16               = GL_DEPTH_COMPONENT16,     /// `GL_DEPTH_COMPONENT16`
53         DEPTH24               = GL_DEPTH_COMPONENT24,     /// `GL_DEPTH_COMPONENT24`
54         DEPTH32               = GL_DEPTH_COMPONENT32,     /// `GL_DEPTH_COMPONENT32`
55         DEPTH32F              = GL_DEPTH_COMPONENT32F,    /// `GL_DEPTH_COMPONENT32F`
56         DEPTH_STENCIL         = GL_DEPTH_STENCIL,         /// `GL_DEPTH_STENCIL`
57         R3_G3_B2              = GL_R3_G3_B2,              /// `GL_R3_G3_B2`
58         RED                   = GL_RED,                   /// `GL_RED`
59         RG                    = GL_RG,                    /// `GL_RG`
60         RGB                   = GL_RGB,                   /// `GL_RGB`
61         RGB4                  = GL_RGB4,                  /// `GL_RGB4`
62         RGB5                  = GL_RGB5,                  /// `GL_RGB5`
63         RGB8                  = GL_RGB8,                  /// `GL_RGB8`
64         RGB10                 = GL_RGB10,                 /// `GL_RGB10`
65         RGB12                 = GL_RGB12,                 /// `GL_RGB12`
66         RGB16                 = GL_RGB16,                 /// `GL_RGB16`
67         RGBA                  = GL_RGBA,                  /// `GL_RGBA`
68         RGBA2                 = GL_RGBA2,                 /// `GL_RGBA2`
69         RGBA4                 = GL_RGBA4,                 /// `GL_RGBA4`
70         RGB5_A1               = GL_RGB5_A1,               /// `GL_RGB5_A1`
71         RGBA8                 = GL_RGBA8,                 /// `GL_RGBA8`
72         RGB10_A2              = GL_RGB10_A2,              /// `GL_RGB10_A2`
73         RGBA12                = GL_RGBA12,                /// `GL_RGBA12`
74         RGBA16                = GL_RGBA16,                /// `GL_RGBA16`
75         SRGB                  = GL_SRGB,                  /// `GL_SRGB`
76         SRGB8                 = GL_SRGB8,                 /// `GL_SRGB8`
77         SRGB_ALPHA            = GL_SRGB_ALPHA,            /// `GL_SRGB_ALPHA`
78         SRGB8_ALPHA8          = GL_SRGB8_ALPHA8           /// `GL_SRGB8_ALPHA8`
79     }
80 
81     enum Side
82     {
83         PX = GL_TEXTURE_CUBE_MAP_POSITIVE_X, /// `GL_TEXTURE_CUBE_MAP_POSITIVE_X`
84         NX = GL_TEXTURE_CUBE_MAP_NEGATIVE_X, /// `GL_TEXTURE_CUBE_MAP_NEGATIVE_X`
85         PY = GL_TEXTURE_CUBE_MAP_POSITIVE_Y, /// `GL_TEXTURE_CUBE_MAP_POSITIVE_Y`
86         NY = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, /// `GL_TEXTURE_CUBE_MAP_NEGATIVE_Y`
87         PZ = GL_TEXTURE_CUBE_MAP_POSITIVE_Z, /// `GL_TEXTURE_CUBE_MAP_POSITIVE_Z`
88         NZ = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z  /// `GL_TEXTURE_CUBE_MAP_NEGATIVE_Z`
89     }
90 
91     ///
92     enum Format
93     {
94         RED  = GL_RED,  /// `GL_RED`
95         RG   = GL_RG,   /// `GL_RG`
96         RGB  = GL_RGB,  /// `GL_RGB`
97         RGBA = GL_RGBA, /// `GL_RGBA`
98 
99         BGR  = GL_BGR,  /// `GL_BGR`
100         BGRA = GL_BGRA, /// `GL_BGRA`
101 
102         DEPTH = GL_DEPTH_COMPONENT, /// `GL_DEPTH_COMPONENT`
103         DEPTH_STENCIL = GL_DEPTH_STENCIL /// `GL_DEPTH_STENCIL`
104     }
105 
106     ///
107     enum Type
108     {
109         UNSIGNED_BYTE  = GL_UNSIGNED_BYTE,  /// `GL_UNSIGNED_BYTE`
110         BYTE           = GL_BYTE,           /// `GL_BYTE`
111         UNSIGNED_SHORT = GL_UNSIGNED_SHORT, /// `GL_UNSIGNED_SHORT`
112         SHORT          = GL_SHORT,          /// `GL_SHORT`
113         UNSIGNED_INT   = GL_UNSIGNED_INT,   /// `GL_UNSIGNED_INT`
114         INT            = GL_INT,            /// `GL_INT`
115         HALF_FLOAT     = GL_HALF_FLOAT,     /// `GL_HALF_FLOAT`
116         FLOAT          = GL_FLOAT,          /// `GL_FLOAT`
117 
118         UNSIGNED_BYTE_3_3_2             = GL_UNSIGNED_BYTE_3_3_2,           /// `GL_UNSIGNED_BYTE_3_3_2`
119         UNSIGNED_BYTE_2_3_3_REV         = GL_UNSIGNED_BYTE_2_3_3_REV,       /// `GL_UNSIGNED_BYTE_2_3_3_REV`
120         UNSIGNED_SHORT_5_6_5            = GL_UNSIGNED_SHORT_5_6_5,          /// `GL_UNSIGNED_SHORT_5_6_5`
121         UNSIGNED_SHORT_5_6_5_REV        = GL_UNSIGNED_SHORT_5_6_5_REV,      /// `GL_UNSIGNED_SHORT_5_6_5_REV`
122         UNSIGNED_SHORT_4_4_4_4          = GL_UNSIGNED_SHORT_4_4_4_4,        /// `GL_UNSIGNED_SHORT_4_4_4_4`
123         UNSIGNED_SHORT_4_4_4_4_REV      = GL_UNSIGNED_SHORT_4_4_4_4_REV,    /// `GL_UNSIGNED_SHORT_4_4_4_4_REV`
124         UNSIGNED_SHORT_5_5_5_1          = GL_UNSIGNED_SHORT_5_5_5_1,        /// `GL_UNSIGNED_SHORT_5_5_5_1`
125         UNSIGNED_SHORT_1_5_5_5_REV      = GL_UNSIGNED_SHORT_1_5_5_5_REV,    /// `GL_UNSIGNED_SHORT_1_5_5_5_REV`
126         UNSIGNED_INT_8_8_8_8            = GL_UNSIGNED_INT_8_8_8_8,          /// `GL_UNSIGNED_INT_8_8_8_8`
127         UNSIGNED_INT_8_8_8_8_REV        = GL_UNSIGNED_INT_8_8_8_8_REV,      /// `GL_UNSIGNED_INT_8_8_8_8_REV`
128         UNSIGNED_INT_10_10_10_2         = GL_UNSIGNED_INT_10_10_10_2,       /// `GL_UNSIGNED_INT_10_10_10_2`
129         UNSIGNED_INT_2_10_10_10_REV     = GL_UNSIGNED_INT_2_10_10_10_REV,   /// `GL_UNSIGNED_INT_2_10_10_10_REV`
130         UNSIGNED_INT_24_8               = GL_UNSIGNED_INT_24_8,             /// `GL_UNSIGNED_INT_24_8`
131         UNSIGNED_INT_10F_11F_11F_REV    = GL_UNSIGNED_INT_10F_11F_11F_REV,  /// `GL_UNSIGNED_INT_10F_11F_11F_REV`
132         UNSIGNED_INT_5_9_9_9_REV        = GL_UNSIGNED_INT_5_9_9_9_REV,      /// `GL_UNSIGNED_INT_5_9_9_9_REV`
133         FLOAT_32_UNSIGNED_INT_24_8_REV  = GL_FLOAT_32_UNSIGNED_INT_24_8_REV /// `GL_FLOAT_32_UNSIGNED_INT_24_8_REV`
134     }
135 
136     ///
137     this( GLenum tg, uint tu = 0 )
138     in
139     {
140         int max_tu;
141         checkGLCall!glGetIntegerv( GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_tu );
142         assert( tu < max_tu );
143     }
144     body
145     {
146         _unit = tu;
147         super( tg );
148         logger.Debug( "with target [%s] texture unit [%d]", toGLTextureTarget(target), tu );
149         setMinFilter( Filter.NEAREST );
150         setMagFilter( Filter.NEAREST );
151     }
152 
153     enum Dim { ONE=1, TWO=2, THREE=3 }
154 
155     pure nothrow @nogc @property
156     {
157         final
158         {
159             ///
160             uint unit() const { return _unit; }
161             ///
162             void unit( uint tu ) { _unit = tu; }
163         }
164 
165         uivec3 size() const
166         {
167             final switch( allocDim )
168             {
169                 case Dim.ONE: return uivec3( _size.x, 1, 1 );
170                 case Dim.TWO: return uivec3( _size.xy, 1 );
171                 case Dim.THREE: return _size;
172             }
173         }
174 
175         const
176         {
177             abstract bool mipmapable();
178             abstract bool isArray();
179             abstract Dim imageDim();
180             abstract Dim allocDim();
181         }
182     }
183 
184     ///
185     void genMipmap()
186     {
187         if( !mipmapable ) throw new GLTextureException( this.toString ~ " is not mipmapable" );
188         bind();
189         checkGLCall!glGenerateMipmap(target);
190         logger.Debug( "with target [%s]", target );
191     }
192 
193     ///
194     void setParam( GLenum param, int val )
195     {
196         bind();
197         checkGLCall!glTexParameteri( target, param, val );
198     }
199 
200     ///
201     void setParam( GLenum param, int[] val )
202     {
203         bind();
204         checkGLCall!glTexParameteriv( target, param, val.ptr );
205     }
206 
207     ///
208     void setParam( GLenum param, float val )
209     {
210         bind();
211         checkGLCall!glTexParameterf( target, param, val );
212     }
213 
214     ///
215     void setParam( GLenum param, float[] val )
216     {
217         bind();
218         checkGLCall!glTexParameterfv( target, param, val.ptr );
219     }
220 
221     ///
222     enum Filter
223     {
224         NEAREST                = GL_NEAREST,                /// `GL_NEAREST`
225         LINEAR                 = GL_LINEAR,                 /// `GL_LINEAR`
226         NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST, /// `GL_NEAREST_MIPMAP_NEAREST`
227         LINEAR_MIPMAP_NEAREST  = GL_LINEAR_MIPMAP_NEAREST,  /// `GL_LINEAR_MIPMAP_NEAREST`
228         NEAREST_MIPMAP_LINEAR  = GL_NEAREST_MIPMAP_LINEAR,  /// `GL_NEAREST_MIPMAP_LINEAR`
229         LINEAR_MIPMAP_LINEAR   = GL_LINEAR_MIPMAP_LINEAR    /// `GL_LINEAR_MIPMAP_LINEAR`
230     }
231 
232     ///
233     void setMinFilter( Filter filter )
234     {
235         setParam( GL_TEXTURE_MIN_FILTER, filter );
236         logger.Debug( "to [%s]", filter );
237     }
238 
239     ///
240     void setMagFilter( Filter filter )
241     {
242         setParam( GL_TEXTURE_MAG_FILTER, filter );
243         logger.Debug( "to [%s]", filter );
244     }
245 
246     ///
247     enum Wrap
248     {
249         CLAMP_TO_EDGE   = GL_CLAMP_TO_EDGE,   /// `GL_CLAMP_TO_EDGE`
250         CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER, /// `GL_CLAMP_TO_BORDER`
251         MIRRORED_REPEAT = GL_MIRRORED_REPEAT, /// `GL_MIRRORED_REPEAT`
252         REPEAT          = GL_REPEAT           /// `GL_REPEAT`
253     }
254 
255     ///
256     void setWrapS( Wrap wrap )
257     {
258         setParam( GL_TEXTURE_WRAP_S, wrap );
259         logger.Debug( "to [%s]", wrap );
260     }
261 
262     ///
263     void setWrapT( Wrap wrap )
264     {
265         setParam( GL_TEXTURE_WRAP_T, wrap );
266         logger.Debug( "to [%s]", wrap );
267     }
268 
269     ///
270     void setWrapR( Wrap wrap )
271     {
272         setParam( GL_TEXTURE_WRAP_R, wrap );
273         logger.Debug( "to [%s]", wrap );
274     }
275 
276     ///
277     void setMinLOD( float v )
278     {
279         setParam( GL_TEXTURE_MIN_LOD, v );
280         logger.Debug( "to [%f]", v );
281     }
282 
283     ///
284     void setMaxLOD( float v )
285     {
286         setParam( GL_TEXTURE_MAX_LOD, v );
287         logger.Debug( "to [%f]", v );
288     }
289 
290     ///
291     void setLODBais( float v )
292     {
293         setParam( GL_TEXTURE_LOD_BIAS, v );
294         logger.Debug( "to [%f]", v );
295     }
296 
297     ///
298     void setBaseLevel( int v )
299     {
300         setParam( GL_TEXTURE_BASE_LEVEL, v );
301         logger.Debug( "to [%d]", v );
302     }
303 
304     ///
305     void setMaxLevel( int v )
306     {
307         setParam( GL_TEXTURE_MAX_LEVEL, v );
308         logger.Debug( "to [%d]", v );
309     }
310 
311     ///
312     void setBorderColor( vec4 clr )
313     {
314         setParam( GL_TEXTURE_BORDER_COLOR, clr.data );
315         logger.Debug( "to [%f,%f,%f,%f]", clr.r, clr.g, clr.b, clr.a );
316     }
317 
318     ///
319     enum CompareFunc
320     {
321         LEQUAL   = GL_LEQUAL,   /// `GL_LEQUAL`
322         GEQUAL   = GL_GEQUAL,   /// `GL_GEQUAL`
323         LESS     = GL_LESS,     /// `GL_LESS`
324         GREATER  = GL_GREATER,  /// `GL_GREATER`
325         EQUAL    = GL_EQUAL,    /// `GL_EQUAL`
326         NOTEQUAL = GL_NOTEQUAL, /// `GL_NOTEQUAL`
327         ALWAYS   = GL_ALWAYS,   /// `GL_ALWAYS`
328         NEVER    = GL_NEVER     /// `GL_NEVER`
329     }
330 
331     ///
332     void setCompareFunc( CompareFunc cf )
333     {
334         setParam( GL_TEXTURE_COMPARE_FUNC, cf );
335         logger.Debug( "to [%s]", cf );
336     }
337 
338     ///
339     enum CompareMode
340     {
341         REF_TO_TEXTURE = GL_COMPARE_REF_TO_TEXTURE, /// `GL_COMPARE_REF_TO_TEXTURE`
342         NONE = GL_NONE /// `GL_NONE`
343     }
344 
345     ///
346     void setCompareMode( CompareMode cm )
347     {
348         setParam( GL_TEXTURE_COMPARE_MODE, cm );
349         logger.Debug( "to [%s]", cm );
350     }
351 
352     ///
353     enum Swizzle
354     {
355         RED   = GL_RED,  /// `GL_RED`
356         GREEN = GL_GREEN,/// `GL_GREEN`
357         BLUE  = GL_BLUE, /// `GL_BLUE`
358         ALPHA = GL_ALPHA,/// `GL_ALPHA`
359         ONE   = GL_ONE,  /// `GL_ONE`
360         ZERO  = GL_ZERO  /// `GL_ZERO`
361     }
362 
363     ///
364     void setSwizzleR( Swizzle s )
365     {
366         setParam( GL_TEXTURE_SWIZZLE_R, s );
367         logger.Debug( "to [%s]", s );
368     }
369 
370     ///
371     void setSwizzleG( Swizzle s )
372     {
373         setParam( GL_TEXTURE_SWIZZLE_G, s );
374         logger.Debug( "to [%s]", s );
375     }
376 
377     ///
378     void setSwizzleB( Swizzle s )
379     {
380         setParam( GL_TEXTURE_SWIZZLE_B, s );
381         logger.Debug( "to [%s]", s );
382     }
383 
384     ///
385     void setSwizzleA( Swizzle s )
386     {
387         setParam( GL_TEXTURE_SWIZZLE_A, s );
388         logger.Debug( "to [%s]", s );
389     }
390 
391     ///
392     void setSwizzleRGBA( Swizzle[4] s )
393     {
394         setParam( GL_TEXTURE_SWIZZLE_RGBA, to!(int[])(s) );
395         logger.Debug( "to %s", s );
396     }
397 
398     ///
399     enum DepthStencilTextureMode
400     {
401         DEPTH   = GL_DEPTH_COMPONENT,   /// `GL_DEPTH_COMPONENT`
402         STENCIL = GL_STENCIL_COMPONENTS /// `GL_STENCIL_COMPONENTS`
403     }
404 
405     ///
406     void setDepthStencilTextureMode( DepthStencilTextureMode dstm )
407     {
408         setParam( GL_DEPTH_STENCIL_TEXTURE_MODE, dstm );
409         logger.Debug( "to [%s]", dstm );
410     }
411 
412     final
413     {
414         /// glActiveTexture, glBindTexture
415         override void bind()
416         {
417             checkGLCall!glActiveTexture( GL_TEXTURE0 + _unit );
418             checkGLCall!glBindTexture( target, id );
419             debug logger.trace( "pass" );
420         }
421 
422         ///
423         override void unbind()
424         {
425             checkGLCall!glActiveTexture( GL_TEXTURE0 + _unit );
426             checkGLCall!glBindTexture( target, 0 );
427             debug logger.trace( "pass" );
428         }
429     }
430 
431 protected:
432 
433     ///
434     void setImageTrg( ubyte N, GLenum trg, in uivec3 sz, InternalFormat store_format,
435                    Format input_format, Type input_type, in void* data=null, uint level=0 )
436     in
437     {
438         assert( N == 1 || N == 2 || N == 3 );
439         assertNotCubeMap(trg);
440     }
441     body
442     {
443         bind();
444 
445         auto nsz = uivec3( redimSize( 3, N, sz.data ) );
446 
447         if( N == 1 )
448             checkGLCall!glTexImage1D( trg, level, store_format, nsz.x, 0,
449                                         input_format, input_type, data );
450         else if( N == 2 )
451             checkGLCall!glTexImage2D( trg, level, store_format, nsz.x, nsz.y, 0,
452                                         input_format, input_type, data );
453         else if( N == 3 )
454             checkGLCall!glTexImage3D( trg, level, store_format, nsz.x, nsz.y, nsz.z, 0,
455                                         input_format, input_type, data );
456 
457         logger.Debug( "to [%s], size %s, internal format [%s], format [%s], type [%s], with data [%s]",
458                 toGLTextureTarget(trg), sz, store_format, input_format, input_type, data?true:false );
459 
460         liformat = store_format;
461         lformat = input_format;
462         ltype = input_type;
463 
464         _size = nsz;
465     }
466 
467     ///
468     void setImageTrg( ubyte N, GLenum trg, in Image img, uint level=0 )
469     in
470     {
471         assert( N == 1 || N == 2 || N == 3 );
472         assertNotCubeMap(trg);
473     }
474     body
475     {
476         Type type = typeFromImageDataType( img.info.type );
477         auto fmt = formatFromImageCompCount( img.info.comp );
478         auto sz = uivec3( redimSize( 3, N, img.size ) );
479         setImageTrg( N, trg, sz, fmt[0], fmt[1], type, img.data.ptr, level );
480     }
481 
482     ///
483     Image getImageTrg( GLenum trg, Type type, uint level=0 )
484     {
485         bind();
486 
487         int w,h,d;
488 
489         checkGLCall!glGetTexLevelParameteriv( trg, level, GL_TEXTURE_WIDTH,  &w );
490         checkGLCall!glGetTexLevelParameteriv( trg, level, GL_TEXTURE_HEIGHT, &h );
491         checkGLCall!glGetTexLevelParameteriv( trg, level, GL_TEXTURE_DEPTH,  &d );
492 
493         w = max( 1, w );
494         h = max( 1, h );
495         d = max( 1, d );
496 
497         auto ret = Image( ivec3(w,h,d), imageElemInfo( lformat, type ) );
498 
499         checkGLCall!glGetTexImage( trg, level, lformat, type, ret.data.ptr );
500 
501         debug logger.trace( "from [%s], size %s, format [%s], type [%s]",
502                 toGLTextureTarget(trg), [w,h,d], lformat, type );
503 
504         return ret;
505     }
506 
507     ///
508     static Type typeFromImageDataType( DataType ctype )
509     {
510         switch( ctype )
511         {
512             case DataType.BYTE:     return Type.BYTE;
513             case DataType.UBYTE:
514             case DataType.RAWBYTE:  return Type.UNSIGNED_BYTE;
515             case DataType.SHORT:    return Type.SHORT;
516             case DataType.USHORT:   return Type.UNSIGNED_SHORT;
517             case DataType.INT:      return Type.INT;
518             case DataType.UINT:     return Type.UNSIGNED_INT;
519             case DataType.NORM_FIXED: return Type.INT;
520             case DataType.UNORM_FIXED: return Type.UNSIGNED_INT;
521             case DataType.FLOAT:    return Type.FLOAT;
522             default:
523                 throw new GLTextureException( "uncompatible image component type" );
524         }
525     }
526 
527     ///
528     static auto formatFromImageCompCount( size_t channels )
529     {
530         switch( channels )
531         {
532             case 1: return tuple( InternalFormat.RED,  Format.RED  );
533             case 2: return tuple( InternalFormat.RG,   Format.RG   );
534             case 3: return tuple( InternalFormat.RGB,  Format.RGB  );
535             case 4: return tuple( InternalFormat.RGBA, Format.RGBA );
536             default:
537                 throw new GLTextureException( "uncompatible image chanels count" );
538         }
539     }
540 
541     ///
542     static auto imageElemInfo( Format fmt, Type type )
543     {
544         auto cnt = formatElemCount(fmt);
545         auto ict = imageDataType(type);
546         if( ict == DataType.RAWBYTE )
547             return ElemInfo( sizeofType( type ) * cnt );
548         else
549             return ElemInfo( cnt, ict );
550     }
551 
552     ///
553     static size_t formatElemCount( Format fmt )
554     {
555         final switch(fmt)
556         {
557             case Format.RED: return 1;
558             case Format.RG: return 2;
559             case Format.RGB: case Format.BGR: return 3;
560             case Format.RGBA: case Format.BGRA: return 4;
561             case Format.DEPTH: return 1;
562             case Format.DEPTH_STENCIL: return 2;
563         }
564     }
565 
566     ///
567     static DataType imageDataType( Type type )
568     {
569         switch( type )
570         {
571             case Type.BYTE:           return DataType.BYTE;
572             case Type.UNSIGNED_BYTE:  return DataType.UBYTE;
573             case Type.SHORT:          return DataType.SHORT;
574             case Type.UNSIGNED_SHORT: return DataType.USHORT;
575             case Type.INT:            return DataType.INT;
576             case Type.UNSIGNED_INT:   return DataType.UINT;
577             case Type.FLOAT:          return DataType.FLOAT;
578             default:                  return DataType.RAWBYTE;
579         }
580     }
581 
582     ///
583     static size_t sizeofType( Type type )
584     {
585         final switch(type)
586         {
587         case Type.BYTE:
588         case Type.UNSIGNED_BYTE:
589         case Type.UNSIGNED_BYTE_3_3_2:
590         case Type.UNSIGNED_BYTE_2_3_3_REV:
591             return byte.sizeof;
592 
593         case Type.SHORT:
594         case Type.UNSIGNED_SHORT:
595         case Type.UNSIGNED_SHORT_5_6_5:
596         case Type.UNSIGNED_SHORT_5_6_5_REV:
597         case Type.UNSIGNED_SHORT_4_4_4_4:
598         case Type.UNSIGNED_SHORT_4_4_4_4_REV:
599         case Type.UNSIGNED_SHORT_5_5_5_1:
600         case Type.UNSIGNED_SHORT_1_5_5_5_REV:
601             return short.sizeof;
602 
603         case Type.INT:
604         case Type.UNSIGNED_INT:
605         case Type.UNSIGNED_INT_8_8_8_8:
606         case Type.UNSIGNED_INT_8_8_8_8_REV:
607         case Type.UNSIGNED_INT_10_10_10_2:
608         case Type.UNSIGNED_INT_2_10_10_10_REV:
609         case Type.UNSIGNED_INT_24_8:
610         case Type.UNSIGNED_INT_10F_11F_11F_REV:
611         case Type.UNSIGNED_INT_5_9_9_9_REV:
612         case Type.FLOAT_32_UNSIGNED_INT_24_8_REV:
613             return int.sizeof;
614 
615         case Type.HALF_FLOAT: return float.sizeof / 2;
616         case Type.FLOAT: return float.sizeof;
617         }
618     }
619 
620     static void assertNotCubeMap( GLenum trg ) pure nothrow
621     {
622         assert( trg != GL_TEXTURE_CUBE_MAP &&
623                 trg != GL_TEXTURE_CUBE_MAP_ARRAY,
624                 "is not cube map assert" );
625     }
626 }
627 
628 abstract class GLTextureBase(uint N) : GLTexture
629     if( N == 1 || N == 2 || N == 3 )
630 {
631 public:
632 
633     ///
634     this( GLenum trg, uint tu ) { super( trg, tu ); }
635 
636     @property
637     {
638         final override const pure nothrow @nogc
639         {
640             ///
641             Dim allocDim()
642             {
643                      static if( N == 1 ) return Dim.ONE;
644                 else static if( N == 2 ) return Dim.TWO;
645                 else static if( N == 3 ) return Dim.THREE;
646                 else static assert(0,"unsuported texture size");
647             }
648         }
649     }
650 }
651 
652 abstract class GLTextureImgBase(uint N) : GLTextureBase!N
653 {
654     ///
655     this( GLenum trg, uint tu ) { super( trg, tu ); }
656 
657     void size( in uivec3 sz ) @property { setImage( sz, liformat, lformat, ltype, null, 0 ); }
658 
659     ///
660     void setImage( in uivec3 sz, InternalFormat store_format,
661                    Format input_format, Type input_type, in void* data=null, uint level=0 )
662     { setImageTrg( N, target, sz, store_format, input_format, input_type, data, level ); }
663 
664     ///
665     void setImage( in Image img, uint level=0 ) { setImageTrg( N, target, img, level ); }
666 
667     ///
668     Image getImage( Type type, uint level=0 )
669     { return getImageTrg( target, type, level ); }
670 
671     ///
672     Image getImage( uint level=0 ) { return getImage( ltype, level ); }
673 }
674 
675 ///
676 class GLTexture1D : GLTextureImgBase!1
677 {
678     ///
679     this( uint tu ) { super( GL_TEXTURE_1D, tu ); }
680 
681     final override const pure nothrow @nogc @property
682     {
683         ///
684         bool mipmapable() { return true; }
685         ///
686         bool isArray() { return false; }
687         ///
688         Dim imageDim() { return Dim.ONE; }
689     }
690 }
691 
692 ///
693 class GLTexture1DArray : GLTextureImgBase!2
694 {
695     ///
696     this( uint tu ) { super( GL_TEXTURE_1D_ARRAY, tu ); }
697 
698     final override const pure nothrow @nogc @property
699     {
700         ///
701         bool mipmapable() { return true; }
702         ///
703         bool isArray() { return true; }
704         ///
705         Dim imageDim() { return Dim.ONE; }
706     }
707 }
708 
709 ///
710 class GLTexture2D : GLTextureImgBase!2
711 {
712     ///
713     this( uint tu ) { super( GL_TEXTURE_2D, tu ); }
714 
715     final override const pure nothrow @nogc @property
716     {
717         ///
718         bool mipmapable() { return true; }
719         ///
720         bool isArray() { return false; }
721         ///
722         Dim imageDim() { return Dim.TWO; }
723     }
724 }
725 
726 ///
727 class GLTexture2DArray : GLTextureImgBase!3
728 {
729     ///
730     this( uint tu ) { super( GL_TEXTURE_2D_ARRAY, tu ); }
731 
732     final override const pure nothrow @nogc @property
733     {
734         ///
735         bool mipmapable() { return true; }
736         ///
737         bool isArray() { return true; }
738         ///
739         Dim imageDim() { return Dim.TWO; }
740     }
741 }
742 
743 ///
744 class GLTextureRectangle : GLTextureImgBase!2
745 {
746     ///
747     this( uint tu ) { super( GL_TEXTURE_RECTANGLE, tu ); }
748 
749     final override const pure nothrow @nogc @property
750     {
751         ///
752         bool mipmapable() { return false; }
753         ///
754         bool isArray() { return false; }
755         ///
756         Dim imageDim() { return Dim.TWO; }
757     }
758 }
759 
760 ///
761 class GLTexture3D : GLTextureImgBase!3
762 {
763     ///
764     this( uint tu ) { super( GL_TEXTURE_3D, tu ); }
765 
766     final override const pure nothrow @nogc @property
767     {
768         ///
769         bool mipmapable() { return true; }
770         ///
771         bool isArray() { return false; }
772         ///
773         Dim imageDim() { return Dim.THREE; }
774     }
775 }
776 
777 abstract class GLTextureCubeBase(bool array) : GLTextureBase!(2+cast(uint)array)
778 {
779     protected enum CubeDim = 2u + cast(uint)array;
780 
781     ///
782     this( GLenum trg, uint tu ) { super( trg, tu ); }
783 
784     ///
785     void setImage( Side side, in uivec2 sz, InternalFormat store_format,
786                    Format input_format, Type input_type, in void* data=null, uint level=0 )
787     { setImageTrg( CubeDim, side, uivec3( sz, 1 ), store_format, input_format, input_type, data, level ); }
788 
789     ///
790     void setImage( Side side, in Image img, uint level=0 )
791     { setImageTrg( CubeDim, side, img, level ); }
792 
793     ///
794     void setImages( in Image[6] imgs, uint level=0 )
795     {
796         setImage( Side.PX, imgs[0], level );
797         setImage( Side.NX, imgs[1], level );
798         setImage( Side.PY, imgs[2], level );
799         setImage( Side.NY, imgs[3], level );
800         setImage( Side.PZ, imgs[4], level );
801         setImage( Side.NZ, imgs[5], level );
802     }
803 
804     ///
805     void setImages( in Image img, uint width, uivec2[6] pos,
806                     ImRepack[6] tr, uint level=0 )
807     {
808         auto sssz = redimSize( 3, img.size );
809 
810         auto getRegion( uivec2 p, uint w )
811         {
812             static if( CubeDim == 2 ) return Region!(2,uint)( p, uivec2(w) );
813             else return Region!(3,uint)( p, sssz[2], uivec2(w), sssz[2] );
814         }
815 
816         setImage( Side.PX, imGetCopy( img, getRegion( pos[0], width ), tr[0] ), level );
817         setImage( Side.NX, imGetCopy( img, getRegion( pos[1], width ), tr[1] ), level );
818         setImage( Side.PY, imGetCopy( img, getRegion( pos[2], width ), tr[2] ), level );
819         setImage( Side.NY, imGetCopy( img, getRegion( pos[3], width ), tr[3] ), level );
820         setImage( Side.PZ, imGetCopy( img, getRegion( pos[4], width ), tr[4] ), level );
821         setImage( Side.NZ, imGetCopy( img, getRegion( pos[5], width ), tr[5] ), level );
822     }
823 
824     ///
825     Image getImages( Type type, uint level=0 )
826     { return getImageTrg( target, type, level ); }
827 
828     ///
829     Image getImages( uint level=0 )
830     { return getImages( ltype, level ); }
831 }
832 
833 ///
834 class GLTextureCubeMap : GLTextureCubeBase!false
835 {
836     ///
837     this( uint tu ) { super( GL_TEXTURE_CUBE_MAP, tu ); }
838 
839     final override const pure nothrow @nogc @property
840     {
841         ///
842         bool mipmapable() { return true; }
843         ///
844         bool isArray() { return false; }
845         ///
846         Dim imageDim() { return Dim.TWO; }
847     }
848 }
849 
850 ///
851 class GLTextureCubeMapArray : GLTextureCubeBase!true
852 {
853     ///
854     this( uint tu ) { super( GL_TEXTURE_CUBE_MAP_ARRAY, tu ); }
855 
856     final override const pure nothrow @nogc @property
857     {
858         ///
859         bool mipmapable() { return true; }
860         ///
861         bool isArray() { return true; }
862         ///
863         Dim imageDim() { return Dim.TWO; }
864     }
865 }
866 
867 /////
868 //abstract class GLMultisampleTexture : GLTexture
869 //{
870 //    ///
871 //    this( GLenum trg, uint tu ) { super( trg, tu ); }
872 //
873 //    final override const pure nothrow @nogc @property
874 //    {
875 //        ///
876 //        bool mipmapable() { return false; }
877 //        ///
878 //        Dim imageDim() { return Dim.TWO; }
879 //    }
880 //}
881 //
882 /////
883 //class GLTexture2DMultisample : GLMultisampleTexture
884 //{
885 //    ///
886 //    this( uint tu ) { super( GL_TEXTURE_2D_MULTISAMPLE, tu ); }
887 //
888 //    final override const pure nothrow @nogc @property
889 //    {
890 //        ///
891 //        bool isArray() { return false; }
892 //        ///
893 //        Dim allocDim() { return Dim.TWO; }
894 //    }
895 //}
896 //
897 /////
898 //class GLTexture2DMultisampleArray : GLMultisampleTexture
899 //{
900 //    ///
901 //    this( uint tu ) { super( GL_TEXTURE_2D_MULTISAMPLE_ARRAY, tu ); }
902 //
903 //    final override const pure nothrow @nogc @property
904 //    {
905 //        ///
906 //        bool isArray() { return true; }
907 //        ///
908 //        Dim allocDim() { return Dim.THREE; }
909 //    }
910 //}