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     Target _target;
65 
66     ///
67     nothrow @property GLenum gltype() const { return cast(GLenum)_target; }
68 
69     ///
70     InternalFormat liformat;
71     ///
72     Format lformat;
73     ///
74     Type ltype;
75 
76     /// texture unit
77     uint _unit;
78 
79     ///
80     enum Parameter
81     {
82         DEPTH_STENCIL_TEXTURE_MODE = GL_DEPTH_STENCIL_TEXTURE_MODE, /// `GL_DEPTH_STENCIL_TEXTURE_MODE`
83         BASE_LEVEL                 = GL_TEXTURE_BASE_LEVEL,         /// `GL_TEXTURE_BASE_LEVEL`
84         MAX_LEVEL                  = GL_TEXTURE_MAX_LEVEL,          /// `GL_TEXTURE_MAX_LEVEL`
85         BORDER_COLOR               = GL_TEXTURE_BORDER_COLOR,       /// `GL_TEXTURE_BORDER_COLOR`
86         COMPARE_FUNC               = GL_TEXTURE_COMPARE_FUNC,       /// `GL_TEXTURE_COMPARE_FUNC`
87         COMPARE_MODE               = GL_TEXTURE_COMPARE_MODE,       /// `GL_TEXTURE_COMPARE_MODE`
88         LOD_BIAS                   = GL_TEXTURE_LOD_BIAS,           /// `GL_TEXTURE_LOD_BIAS`
89         MIN_FILTER                 = GL_TEXTURE_MIN_FILTER,         /// `GL_TEXTURE_MIN_FILTER`
90         MAG_FILTER                 = GL_TEXTURE_MAG_FILTER,         /// `GL_TEXTURE_MAG_FILTER`
91         MIN_LOD                    = GL_TEXTURE_MIN_LOD,            /// `GL_TEXTURE_MIN_LOD`
92         MAX_LOD                    = GL_TEXTURE_MAX_LOD,            /// `GL_TEXTURE_MAX_LOD`
93         SWIZZLE_R                  = GL_TEXTURE_SWIZZLE_R,          /// `GL_TEXTURE_SWIZZLE_R`
94         SWIZZLE_G                  = GL_TEXTURE_SWIZZLE_G,          /// `GL_TEXTURE_SWIZZLE_G`
95         SWIZZLE_B                  = GL_TEXTURE_SWIZZLE_B,          /// `GL_TEXTURE_SWIZZLE_B`
96         SWIZZLE_A                  = GL_TEXTURE_SWIZZLE_A,          /// `GL_TEXTURE_SWIZZLE_A`
97         SWIZZLE_RGBA               = GL_TEXTURE_SWIZZLE_RGBA,       /// `GL_TEXTURE_SWIZZLE_RGBA`
98         WRAP_S                     = GL_TEXTURE_WRAP_S,             /// `GL_TEXTURE_WRAP_S`
99         WRAP_T                     = GL_TEXTURE_WRAP_T,             /// `GL_TEXTURE_WRAP_T`
100         WRAP_R                     = GL_TEXTURE_WRAP_R              /// `GL_TEXTURE_WRAP_R`
101     }
102 
103 public:
104 
105     alias CrdVector!3 texsize_t; 
106 
107     @property
108     {
109         ///
110         Target target() const { return _target; }
111         ///
112         void target( Target trg ) { _target = trg; }
113     }
114 
115     ///
116     enum Target
117     {
118         T1D                   = GL_TEXTURE_1D,                   /// `GL_TEXTURE_1D`
119         T2D                   = GL_TEXTURE_2D,                   /// `GL_TEXTURE_2D`
120         T3D                   = GL_TEXTURE_3D,                   /// `GL_TEXTURE_3D`
121         T1D_ARRAY             = GL_TEXTURE_1D_ARRAY,             /// `GL_TEXTURE_1D_ARRAY`
122         T2D_ARRAY             = GL_TEXTURE_2D_ARRAY,             /// `GL_TEXTURE_2D_ARRAY`
123         RECTANGLE             = GL_TEXTURE_RECTANGLE,            /// `GL_TEXTURE_RECTANGLE`
124         CUBE_MAP              = GL_TEXTURE_CUBE_MAP,             /// `GL_TEXTURE_CUBE_MAP`
125         CUBE_MAP_ARRAY        = GL_TEXTURE_CUBE_MAP_ARRAY,       /// `GL_TEXTURE_CUBE_MAP_ARRAY`
126 
127         BUFFER                = GL_TEXTURE_BUFFER,               /// `GL_TEXTURE_BUFFER`
128         T2D_MULTISAMPLE       = GL_TEXTURE_2D_MULTISAMPLE,       /// `GL_TEXTURE_2D_MULTISAMPLE`
129         T2D_MULTISAMPLE_ARRAY = GL_TEXTURE_2D_MULTISAMPLE_ARRAY, /// `GL_TEXTURE_2D_MULTISAMPLE_ARRAY`
130 
131         CUBE_MAP_POSITIVE_X   = GL_TEXTURE_CUBE_MAP_POSITIVE_X,  /// `GL_TEXTURE_CUBE_MAP_POSITIVE_X`
132         CUBE_MAP_NEGATIVE_X   = GL_TEXTURE_CUBE_MAP_NEGATIVE_X,  /// `GL_TEXTURE_CUBE_MAP_NEGATIVE_X`
133         CUBE_MAP_POSITIVE_Y   = GL_TEXTURE_CUBE_MAP_POSITIVE_Y,  /// `GL_TEXTURE_CUBE_MAP_POSITIVE_Y`
134         CUBE_MAP_NEGATIVE_Y   = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,  /// `GL_TEXTURE_CUBE_MAP_NEGATIVE_Y`
135         CUBE_MAP_POSITIVE_Z   = GL_TEXTURE_CUBE_MAP_POSITIVE_Z,  /// `GL_TEXTURE_CUBE_MAP_POSITIVE_Z`
136         CUBE_MAP_NEGATIVE_Z   = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z   /// `GL_TEXTURE_CUBE_MAP_NEGATIVE_Z`
137     }
138 
139     ///
140     enum DepthStencilTextureMode
141     {
142         DEPTH   = GL_DEPTH_COMPONENT,   /// `GL_DEPTH_COMPONENT`
143         STENCIL = GL_STENCIL_COMPONENTS /// `GL_STENCIL_COMPONENTS`
144     }
145 
146     ///
147     enum CompareFunc
148     {
149         LEQUAL   = GL_LEQUAL,   /// `GL_LEQUAL`
150         GEQUAL   = GL_GEQUAL,   /// `GL_GEQUAL`
151         LESS     = GL_LESS,     /// `GL_LESS`
152         GREATER  = GL_GREATER,  /// `GL_GREATER`
153         EQUAL    = GL_EQUAL,    /// `GL_EQUAL`
154         NOTEQUAL = GL_NOTEQUAL, /// `GL_NOTEQUAL`
155         ALWAYS   = GL_ALWAYS,   /// `GL_ALWAYS`
156         NEVER    = GL_NEVER     /// `GL_NEVER`
157     }
158 
159     ///
160     enum CompareMode
161     {
162         REF_TO_TEXTURE = GL_COMPARE_REF_TO_TEXTURE, /// `GL_COMPARE_REF_TO_TEXTURE`
163         NONE = GL_NONE /// `GL_NONE`
164     }
165 
166     ///
167     enum Filter
168     {
169         NEAREST                = GL_NEAREST,                /// `GL_NEAREST`
170         LINEAR                 = GL_LINEAR,                 /// `GL_LINEAR`
171         NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST, /// `GL_NEAREST_MIPMAP_NEAREST`
172         LINEAR_MIPMAP_NEAREST  = GL_LINEAR_MIPMAP_NEAREST,  /// `GL_LINEAR_MIPMAP_NEAREST`
173         NEAREST_MIPMAP_LINEAR  = GL_NEAREST_MIPMAP_LINEAR,  /// `GL_NEAREST_MIPMAP_LINEAR`
174         LINEAR_MIPMAP_LINEAR   = GL_LINEAR_MIPMAP_LINEAR    /// `GL_LINEAR_MIPMAP_LINEAR`
175     }
176 
177     ///
178     enum Swizzle
179     {
180         RED   = GL_RED,  /// `GL_RED`
181         GREEN = GL_GREEN,/// `GL_GREEN`
182         BLUE  = GL_BLUE, /// `GL_BLUE`
183         ALPHA = GL_ALPHA,/// `GL_ALPHA`
184         ONE   = GL_ONE,  /// `GL_ONE`
185         ZERO  = GL_ZERO  /// `GL_ZERO`
186     }
187 
188     ///
189     enum Wrap
190     {
191         CLAMP_TO_EDGE   = GL_CLAMP_TO_EDGE,   /// `GL_CLAMP_TO_EDGE`
192         CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER, /// `GL_CLAMP_TO_BORDER`
193         MIRRORED_REPEAT = GL_MIRRORED_REPEAT, /// `GL_MIRRORED_REPEAT`
194         REPEAT          = GL_REPEAT           /// `GL_REPEAT`
195     }
196 
197     ///
198     enum InternalFormat
199     {
200         COMPRESSED_RED        = GL_COMPRESSED_RED,        /// `GL_COMPRESSED_RED`
201         COMPRESSED_RG         = GL_COMPRESSED_RG,         /// `GL_COMPRESSED_RG`
202         COMPRESSED_RGB        = GL_COMPRESSED_RGB,        /// `GL_COMPRESSED_RGB`
203         COMPRESSED_RGBA       = GL_COMPRESSED_RGBA,       /// `GL_COMPRESSED_RGBA`
204         COMPRESSED_SRGB       = GL_COMPRESSED_SRGB,       /// `GL_COMPRESSED_SRGB`
205         COMPRESSED_SRGB_ALPHA = GL_COMPRESSED_SRGB_ALPHA, /// `GL_COMPRESSED_SRGB_ALPHA`
206         DEPTH                 = GL_DEPTH_COMPONENT,       /// `GL_DEPTH_COMPONENT`
207         DEPTH16               = GL_DEPTH_COMPONENT16,     /// `GL_DEPTH_COMPONENT16`
208         DEPTH24               = GL_DEPTH_COMPONENT24,     /// `GL_DEPTH_COMPONENT24`
209         DEPTH32               = GL_DEPTH_COMPONENT32,     /// `GL_DEPTH_COMPONENT32`
210         DEPTH32F              = GL_DEPTH_COMPONENT32F,    /// `GL_DEPTH_COMPONENT32F`
211         DEPTH_STENCIL         = GL_DEPTH_STENCIL,         /// `GL_DEPTH_STENCIL`
212         R3_G3_B2              = GL_R3_G3_B2,              /// `GL_R3_G3_B2`
213         RED                   = GL_RED,                   /// `GL_RED`
214         RG                    = GL_RG,                    /// `GL_RG`
215         RGB                   = GL_RGB,                   /// `GL_RGB`
216         RGB4                  = GL_RGB4,                  /// `GL_RGB4`
217         RGB5                  = GL_RGB5,                  /// `GL_RGB5`
218         RGB8                  = GL_RGB8,                  /// `GL_RGB8`
219         RGB10                 = GL_RGB10,                 /// `GL_RGB10`
220         RGB12                 = GL_RGB12,                 /// `GL_RGB12`
221         RGB16                 = GL_RGB16,                 /// `GL_RGB16`
222         RGBA                  = GL_RGBA,                  /// `GL_RGBA`
223         RGBA2                 = GL_RGBA2,                 /// `GL_RGBA2`
224         RGBA4                 = GL_RGBA4,                 /// `GL_RGBA4`
225         RGB5_A1               = GL_RGB5_A1,               /// `GL_RGB5_A1`
226         RGBA8                 = GL_RGBA8,                 /// `GL_RGBA8`
227         RGB10_A2              = GL_RGB10_A2,              /// `GL_RGB10_A2`
228         RGBA12                = GL_RGBA12,                /// `GL_RGBA12`
229         RGBA16                = GL_RGBA16,                /// `GL_RGBA16`
230         SRGB                  = GL_SRGB,                  /// `GL_SRGB`
231         SRGB8                 = GL_SRGB8,                 /// `GL_SRGB8`
232         SRGB_ALPHA            = GL_SRGB_ALPHA,            /// `GL_SRGB_ALPHA`
233         SRGB8_ALPHA8          = GL_SRGB8_ALPHA8           /// `GL_SRGB8_ALPHA8`
234     }
235 
236     ///
237     enum Format
238     {
239         RED  = GL_RED,  /// `GL_RED`
240         RG   = GL_RG,   /// `GL_RG`
241         RGB  = GL_RGB,  /// `GL_RGB`
242         RGBA = GL_RGBA, /// `GL_RGBA`
243 
244         BGR  = GL_BGR,  /// `GL_BGR`
245         BGRA = GL_BGRA, /// `GL_BGRA`
246 
247         DEPTH = GL_DEPTH_COMPONENT, /// `GL_DEPTH_COMPONENT`
248         DEPTH_STENCIL = GL_DEPTH_STENCIL /// `GL_DEPTH_STENCIL`
249     }
250 
251     ///
252     enum Type
253     {
254         UNSIGNED_BYTE  = GL_UNSIGNED_BYTE,  /// `GL_UNSIGNED_BYTE`
255         BYTE           = GL_BYTE,           /// `GL_BYTE`
256         UNSIGNED_SHORT = GL_UNSIGNED_SHORT, /// `GL_UNSIGNED_SHORT`
257         SHORT          = GL_SHORT,          /// `GL_SHORT`
258         UNSIGNED_INT   = GL_UNSIGNED_INT,   /// `GL_UNSIGNED_INT`
259         INT            = GL_INT,            /// `GL_INT`
260         HALF_FLOAT     = GL_HALF_FLOAT,     /// `GL_HALF_FLOAT`
261         FLOAT          = GL_FLOAT,          /// `GL_FLOAT`
262 
263         UNSIGNED_BYTE_3_3_2             = GL_UNSIGNED_BYTE_3_3_2,           /// `GL_UNSIGNED_BYTE_3_3_2`
264         UNSIGNED_BYTE_2_3_3_REV         = GL_UNSIGNED_BYTE_2_3_3_REV,       /// `GL_UNSIGNED_BYTE_2_3_3_REV`
265         UNSIGNED_SHORT_5_6_5            = GL_UNSIGNED_SHORT_5_6_5,          /// `GL_UNSIGNED_SHORT_5_6_5`
266         UNSIGNED_SHORT_5_6_5_REV        = GL_UNSIGNED_SHORT_5_6_5_REV,      /// `GL_UNSIGNED_SHORT_5_6_5_REV`
267         UNSIGNED_SHORT_4_4_4_4          = GL_UNSIGNED_SHORT_4_4_4_4,        /// `GL_UNSIGNED_SHORT_4_4_4_4`
268         UNSIGNED_SHORT_4_4_4_4_REV      = GL_UNSIGNED_SHORT_4_4_4_4_REV,    /// `GL_UNSIGNED_SHORT_4_4_4_4_REV`
269         UNSIGNED_SHORT_5_5_5_1          = GL_UNSIGNED_SHORT_5_5_5_1,        /// `GL_UNSIGNED_SHORT_5_5_5_1`
270         UNSIGNED_SHORT_1_5_5_5_REV      = GL_UNSIGNED_SHORT_1_5_5_5_REV,    /// `GL_UNSIGNED_SHORT_1_5_5_5_REV`
271         UNSIGNED_INT_8_8_8_8            = GL_UNSIGNED_INT_8_8_8_8,          /// `GL_UNSIGNED_INT_8_8_8_8`
272         UNSIGNED_INT_8_8_8_8_REV        = GL_UNSIGNED_INT_8_8_8_8_REV,      /// `GL_UNSIGNED_INT_8_8_8_8_REV`
273         UNSIGNED_INT_10_10_10_2         = GL_UNSIGNED_INT_10_10_10_2,       /// `GL_UNSIGNED_INT_10_10_10_2`
274         UNSIGNED_INT_2_10_10_10_REV     = GL_UNSIGNED_INT_2_10_10_10_REV,   /// `GL_UNSIGNED_INT_2_10_10_10_REV`
275         UNSIGNED_INT_24_8               = GL_UNSIGNED_INT_24_8,             /// `GL_UNSIGNED_INT_24_8`
276         UNSIGNED_INT_10F_11F_11F_REV    = GL_UNSIGNED_INT_10F_11F_11F_REV,  /// `GL_UNSIGNED_INT_10F_11F_11F_REV`
277         UNSIGNED_INT_5_9_9_9_REV        = GL_UNSIGNED_INT_5_9_9_9_REV,      /// `GL_UNSIGNED_INT_5_9_9_9_REV`
278         FLOAT_32_UNSIGNED_INT_24_8_REV  = GL_FLOAT_32_UNSIGNED_INT_24_8_REV /// `GL_FLOAT_32_UNSIGNED_INT_24_8_REV`
279     }
280 
281     ///
282     this( Target tg, uint tu = 0 )
283     in
284     {
285         assert( isBase(tg) );
286         int max_tu;
287         checkGLCall!glGetIntegerv( GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_tu );
288         assert( tu < max_tu );
289     }
290     body
291     {
292         _unit = tu;
293         checkGLCall!glGenTextures( 1, &_id );
294         logger = new InstanceLogger( this, format( "%d:%d", tu, _id ) );
295         _target = tg;
296         logger.Debug( "with target [%s]", _target );
297     }
298 
299     final pure @property
300     {
301         ///
302         uint id() const { return _id; }
303         ///
304         uint unit() const { return _unit; }
305         ///
306         void unit( uint tu ) { _unit = tu; }
307     }
308 
309     /// bind, glGenerateMipmap
310     void genMipmap()
311     in { assert( isMipmapable(_target) ); } body
312     {
313         bind();
314         checkGLCall!glGenerateMipmap(gltype);
315         logger.Debug( "with target [%s]", _target );
316     }
317 
318     ///
319     void setParam( GLenum param, int val )
320     {
321         bind();
322         checkGLCall!glTexParameteri( gltype, param, val );
323     }
324 
325     ///
326     void setParam( GLenum param, int[] val )
327     {
328         bind();
329         checkGLCall!glTexParameteriv( gltype, param, val.ptr );
330     }
331 
332     ///
333     void setParam( GLenum param, float val )
334     {
335         bind();
336         checkGLCall!glTexParameterf( gltype, param, val );
337     }
338 
339     ///
340     void setParam( GLenum param, float[] val )
341     {
342         bind();
343         checkGLCall!glTexParameterfv( gltype, param, val.ptr );
344     }
345 
346     ///
347     void setMinFilter( Filter filter )
348     {
349         setParam( Parameter.MIN_FILTER, filter );
350         logger.Debug( "to [%s]", filter );
351     }
352 
353     ///
354     void setMagFilter( Filter filter )
355     {
356         setParam( Parameter.MAG_FILTER, filter );
357         logger.Debug( "to [%s]", filter );
358     }
359 
360     ///
361     void setWrapS( Wrap wrap )
362     {
363         setParam( Parameter.WRAP_S, wrap );
364         logger.Debug( "to [%s]", wrap );
365     }
366 
367     ///
368     void setWrapT( Wrap wrap )
369     {
370         setParam( Parameter.WRAP_T, wrap );
371         logger.Debug( "to [%s]", wrap );
372     }
373 
374     ///
375     void setWrapR( Wrap wrap )
376     {
377         setParam( Parameter.WRAP_R, wrap );
378         logger.Debug( "to [%s]", wrap );
379     }
380 
381     ///
382     void setMinLOD( float v )
383     {
384         setParam( Parameter.MIN_LOD, v );
385         logger.Debug( "to [%f]", v );
386     }
387 
388     ///
389     void setMaxLOD( float v )
390     {
391         setParam( Parameter.MAX_LOD, v );
392         logger.Debug( "to [%f]", v );
393     }
394 
395     ///
396     void setLODBais( float v )
397     {
398         setParam( Parameter.LOD_BIAS, v );
399         logger.Debug( "to [%f]", v );
400     }
401 
402     ///
403     void setBaseLevel( int v )
404     {
405         setParam( Parameter.BASE_LEVEL, v );
406         logger.Debug( "to [%d]", v );
407     }
408 
409     ///
410     void setMaxLevel( int v )
411     {
412         setParam( Parameter.MAX_LEVEL, v );
413         logger.Debug( "to [%d]", v );
414     }
415 
416     ///
417     void setBorderColor( vec4 clr )
418     {
419         setParam( Parameter.BORDER_COLOR, clr.data );
420         logger.Debug( "to [%f,%f,%f,%f]", clr.r, clr.g, clr.b, clr.a );
421     }
422 
423     ///
424     void setCompareFunc( CompareFunc cf )
425     {
426         setParam( Parameter.COMPARE_FUNC, cf );
427         logger.Debug( "to [%s]", cf );
428     }
429 
430     ///
431     void setCompareMode( CompareMode cm )
432     {
433         setParam( Parameter.COMPARE_MODE, cm );
434         logger.Debug( "to [%s]", cm );
435     }
436 
437     ///
438     void setSwizzleR( Swizzle s )
439     {
440         setParam( Parameter.SWIZZLE_R, s );
441         logger.Debug( "to [%s]", s );
442     }
443 
444     ///
445     void setSwizzleG( Swizzle s )
446     {
447         setParam( Parameter.SWIZZLE_G, s );
448         logger.Debug( "to [%s]", s );
449     }
450 
451     ///
452     void setSwizzleB( Swizzle s )
453     {
454         setParam( Parameter.SWIZZLE_B, s );
455         logger.Debug( "to [%s]", s );
456     }
457 
458     ///
459     void setSwizzleA( Swizzle s )
460     {
461         setParam( Parameter.SWIZZLE_A, s );
462         logger.Debug( "to [%s]", s );
463     }
464 
465     ///
466     void setSwizzleRGBA( Swizzle[4] s )
467     {
468         setParam( Parameter.SWIZZLE_RGBA, to!(int[])(s) );
469         logger.Debug( "to %s", s );
470     }
471 
472     ///
473     void setDepthStencilTextureMode( DepthStencilTextureMode dstm )
474     {
475         setParam( Parameter.DEPTH_STENCIL_TEXTURE_MODE, dstm );
476         logger.Debug( "to [%s]", dstm );
477     }
478 
479     final nothrow
480     {
481         /// glActiveTexture, glBindTexture
482         void bind()
483         {
484             ntCheckGLCall!glActiveTexture( GL_TEXTURE0 + _unit );
485             ntCheckGLCall!glBindTexture( gltype, _id );
486             debug logger.trace( "pass" );
487         }
488 
489         ///
490         void unbind()
491         {
492             ntCheckGLCall!glActiveTexture( GL_TEXTURE0 + _unit );
493             ntCheckGLCall!glBindTexture( gltype, 0 );
494             debug logger.trace( "pass" );
495         }
496 
497         ///
498         texsize_t size() const { return img_size; }
499     }
500 
501     ///
502     void resize(size_t N,T)( in Vector!(N,T) sz )
503         if( (N==1 || N==2 || N==3) && isIntegral!T )
504     { image( sz, liformat, lformat, ltype ); }
505 
506     /// set image
507     void image(size_t N,T)( in Vector!(N,T) sz, InternalFormat internal_format, 
508             Format data_format, Type data_type, in void* data=null )
509     if( (N==1 || N==2 || N==3) && isIntegral!T )
510     {
511         enum N = sz.length;
512         img_size = texsize_t( sz, [1,1][0 .. 3-N] );
513 
514         liformat = internal_format;
515         lformat = data_format;
516         ltype = data_type;
517 
518         bind();
519         mixin( format(`
520         glTexImage%1dD( gltype, 0, cast(int)internal_format, %s, 0,
521                         cast(GLenum)data_format, cast(GLenum)data_type, data );
522         `, N, accessVecFields!(sz) ) );
523 
524         debug checkGL;
525         logger.Debug( "[%d]: size %s, internal format [%s], format [%s], type [%s], with data [%s]",
526                 _id, sz.data.dup, internal_format, data_format, data_type, data?true:false );
527     }
528 
529     /// ditto
530     final void image(size_t N)( in Image!N img ) if( N >= 1 && N <= 3 )
531     in
532     {
533         switch( N )
534         {
535             case 1: assert( target == Target.T1D ); break;
536             case 2: assert( target == Target.T2D ); break;
537             case 3: assert( target == Target.T3D ); break;
538             default: assert(0);
539         }
540     }
541     body
542     {
543         Type type = typeFromImageDataType( img.info.comp );
544         auto fmt = formatFromImageChanelsCount( img.info.channels );
545         image( img.size, fmt[0], fmt[1], type, img.data.ptr );
546     }
547 
548     ///
549     final void getImage( ref Image!2 img )
550     in { assert( _target == Target.T2D ); } body
551     { getImage( img, ltype ); }
552 
553     ///
554     final void getImage( ref Image!2 img, Type type )
555     in { assert( _target == Target.T2D ); } body
556     {
557         enum uint level = 0;
558 
559         bind();
560         debug checkGL;
561         int w, h;
562         glGetTexLevelParameteriv( GL_TEXTURE_2D, level, GL_TEXTURE_WIDTH, &(w));
563         debug checkGL;
564         glGetTexLevelParameteriv( GL_TEXTURE_2D, level, GL_TEXTURE_HEIGHT, &(h));
565         debug checkGL;
566 
567         auto elemSize = formatElemCount(lformat) * sizeofType(type);
568 
569         auto dsize = w * h * elemSize;
570 
571         if( img.size != CrdVector!2(w,h) || img.info.bpe != elemSize )
572         {
573             img.size = ivec2( w, h );
574             img.info = imageElemInfo( lformat, type );
575         }
576 
577         glGetTexImage( GL_TEXTURE_2D, level, cast(GLenum)lformat, cast(GLenum)type, img.data.ptr );
578         debug checkGL;
579         unbind();
580         debug checkGL;
581         debug logger.trace( "[%d] size [%d,%d], format [%s], type [%s]", _id, w,h, lformat, type );
582     }
583 
584     protected static
585     {
586         ///
587         bool isBase( Target trg )
588         {
589             switch(trg)
590             {
591             case Target.T1D:
592             case Target.T2D:
593             case Target.T3D:
594             case Target.T1D_ARRAY:
595             case Target.T2D_ARRAY:
596             case Target.RECTANGLE:
597             case Target.CUBE_MAP:
598             case Target.CUBE_MAP_ARRAY: return true;
599             default: return false;
600             }
601         }
602 
603         ///
604         bool isParametric( Target trg )
605         {
606             switch(trg)
607             {
608             case Target.T1D:
609             case Target.T2D:
610             case Target.T3D:
611             case Target.T1D_ARRAY:
612             case Target.T2D_ARRAY:
613             case Target.RECTANGLE:
614             case Target.CUBE_MAP: return true;
615             default: return false;
616             }
617         }
618 
619         ///
620         bool isMipmapable( Target trg )
621         {
622             switch(trg)
623             {
624             case Target.T1D:
625             case Target.T2D:
626             case Target.T3D:
627             case Target.T1D_ARRAY:
628             case Target.T2D_ARRAY:
629             case Target.CUBE_MAP: return true;
630             default: return false;
631             }
632         }
633 
634         ///
635         size_t formatElemCount( Format fmt )
636         {
637             final switch(fmt)
638             {
639                 case Format.RED: return 1;
640                 case Format.RG:  return 2;
641 
642                 case Format.RGB:
643                 case Format.BGR:
644                     return 3;
645 
646                 case Format.RGBA:
647                 case Format.BGRA:
648                     return 4;
649 
650                 case Format.DEPTH:
651                     return 1;
652 
653                 case Format.DEPTH_STENCIL:
654                     return 2;
655             }
656         }
657 
658         ///
659         size_t sizeofType( Type type )
660         {
661             final switch(type)
662             {
663             case Type.BYTE:          
664             case Type.UNSIGNED_BYTE:
665             case Type.UNSIGNED_BYTE_3_3_2:
666             case Type.UNSIGNED_BYTE_2_3_3_REV:
667                 return byte.sizeof;
668 
669             case Type.SHORT:
670             case Type.UNSIGNED_SHORT:
671             case Type.UNSIGNED_SHORT_5_6_5:
672             case Type.UNSIGNED_SHORT_5_6_5_REV:
673             case Type.UNSIGNED_SHORT_4_4_4_4:
674             case Type.UNSIGNED_SHORT_4_4_4_4_REV:
675             case Type.UNSIGNED_SHORT_5_5_5_1:
676             case Type.UNSIGNED_SHORT_1_5_5_5_REV:
677                 return short.sizeof;
678 
679             case Type.INT:
680             case Type.UNSIGNED_INT:
681             case Type.UNSIGNED_INT_8_8_8_8:
682             case Type.UNSIGNED_INT_8_8_8_8_REV:
683             case Type.UNSIGNED_INT_10_10_10_2:
684             case Type.UNSIGNED_INT_2_10_10_10_REV:
685             case Type.UNSIGNED_INT_24_8:
686             case Type.UNSIGNED_INT_10F_11F_11F_REV:
687             case Type.UNSIGNED_INT_5_9_9_9_REV:
688             case Type.FLOAT_32_UNSIGNED_INT_24_8_REV:
689                 return int.sizeof;
690 
691             case Type.HALF_FLOAT: return float.sizeof / 2;
692             case Type.FLOAT: return float.sizeof;
693             }
694         }
695 
696         ///
697         auto imageElemInfo( Format fmt, Type type )
698         {
699             auto cnt = formatElemCount(fmt);
700             auto ict = imageDataType(type);
701             if( ict == DataType.RAWBYTE )
702                 return ElemInfo( sizeofType(type) * cnt );
703             else
704                 return ElemInfo( ict, cnt );
705         }
706 
707         ///
708         DataType imageDataType( Type type )
709         {
710             switch( type )
711             {
712                 case Type.BYTE:           return DataType.BYTE;
713                 case Type.UNSIGNED_BYTE:  return DataType.UBYTE;
714                 case Type.SHORT:          return DataType.SHORT;
715                 case Type.UNSIGNED_SHORT: return DataType.USHORT;
716                 case Type.INT:            return DataType.INT;
717                 case Type.UNSIGNED_INT:   return DataType.UINT;
718                 case Type.FLOAT:          return DataType.FLOAT;
719                 default:                  return DataType.RAWBYTE;
720             }
721         }
722 
723         ///
724         @property bool isParameterEnum(T)()
725         {
726             return is(T==DepthStencilTextureMode) ||
727                    is(T==CompareFunc) ||
728                    is(T==CompareMode) ||
729                    is(T==Filter) ||
730                    is(T==Swizzle) ||
731                    is(T==Wrap);
732         }
733 
734         ///
735         Type typeFromImageDataType( DataType ctype )
736         {
737             switch( ctype )
738             {
739                 case DataType.BYTE:     return Type.BYTE;
740                 case DataType.UBYTE:
741                 case DataType.RAWBYTE:  return Type.UNSIGNED_BYTE;
742                 case DataType.SHORT:    return Type.SHORT;
743                 case DataType.USHORT:   return Type.UNSIGNED_SHORT;
744                 case DataType.INT:      return Type.INT;
745                 case DataType.UINT:     return Type.UNSIGNED_INT;
746                 case DataType.NORM_FIXED: return Type.INT;
747                 case DataType.UNORM_FIXED: return Type.UNSIGNED_INT;
748                 case DataType.FLOAT:    return Type.FLOAT;
749                 default:
750                     throw new GLTextureException( "uncompatible image component type" );
751             }
752         }
753 
754         ///
755         auto formatFromImageChanelsCount( size_t channels )
756         {
757             switch( channels )
758             {
759                 case 1: return tuple(InternalFormat.RED,  Format.RED  );
760                 case 2: return tuple(InternalFormat.RG,   Format.RG   );
761                 case 3: return tuple(InternalFormat.RGB,  Format.RGB  );
762                 case 4: return tuple(InternalFormat.RGBA, Format.RGBA );
763                 default:
764                     throw new GLTextureException( "uncompatible image chanels count" );
765             }
766         }
767     }
768 }
769 
770 private @property string accessVecFields(alias T)()
771 {
772     string[] ret;
773     foreach( i; 0 .. T.length )
774         ret ~= format( "cast(int)(%s[%d])", T.stringof, i );
775     return ret.join(",");
776 }