1 // Written in the D programming language. 2 /++ 3 + Authors: KanzakiKino 4 + Copyright: KanzakiKino 2018 5 + License: LGPL-3.0 6 ++/ 7 module g4d.gl.texture; 8 import g4d.gl.lib, 9 g4d.gl.type, 10 g4d.math.rational, 11 g4d.util.bitmap; 12 import gl3n.linalg; 13 import std.conv; 14 15 /// A baseclass of OpenGL texture. 16 abstract class Texture 17 { 18 protected static Texture _bindedTexture; 19 20 /// Invalid texture id. 21 enum NullId = 0; 22 23 protected GLuint _id; 24 /// OpenGL texture id. 25 const @property id () { return _id; } 26 27 /// Size of this texture. 28 const vec2i size; 29 30 /// GL_TEXTURE_2D, etc... 31 const pure @property GLenum target (); 32 33 /// 34 this ( vec2i sz ) 35 { 36 size = sz; 37 38 enforce!glGenTextures( 1, &_id ); 39 bind(); 40 41 enforce!glTexParameteri( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); 42 enforce!glTexParameteri( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); 43 } 44 45 /// 46 ~this () 47 { 48 dispose(); 49 } 50 /// Checks if the texture is disposed. 51 const @property disposed () 52 { 53 return _id == NullId; 54 } 55 /// Deletes the texture. 56 void dispose () 57 { 58 if ( !disposed ) { 59 enforce!glDeleteTextures( 1, &_id ); 60 } 61 if ( binded ) { 62 _bindedTexture = null; 63 } 64 _id = NullId; 65 } 66 67 /// Checks if the texture is binded. 68 const @property binded () 69 { 70 return _bindedTexture is this; 71 } 72 /// Sets the texture binded. 73 const void bind () 74 { 75 if ( !binded ) { 76 enforce!glBindTexture( target, id ); 77 _bindedTexture = cast(Texture) this; 78 } 79 } 80 } 81 82 /// A 2-dimensional texture. 83 /// target returns GL_TEXTURE_2D. 84 class Tex2D : Texture 85 { 86 protected static auto resizeBitmapPower2 (B) ( in B bmp ) 87 if ( isBitmap!B ) 88 { 89 auto sz = vec2i( bmp.width.nextPower2.to!int, 90 bmp.rows.nextPower2.to!int ); 91 return bmp.conservativeResize( sz ); 92 } 93 94 /// 95 override const pure @property GLenum target () 96 { 97 return GL_TEXTURE_2D; 98 } 99 100 /// 101 this (B) ( in B bmp, bool compress = false ) 102 if ( isBitmap!B ) 103 { 104 auto formatted = resizeBitmapPower2( bmp ); 105 106 super( formatted.size ); 107 enum type = toGLType!(B.Type); 108 enum lpp = B.LengthPerPixel; 109 110 enum srcFormat = lpp.toFormat; 111 const texFormat = compress? 112 lpp.toCompressedFormat: srcFormat; 113 114 enforce!glTexImage2D( target, 0, texFormat, 115 size.x, size.y, 0, srcFormat, type, formatted.data ); 116 formatted.dispose(); 117 } 118 119 /// Creates an empty texture. 120 /// Compressing is not allowed, 121 /// because compressed texture cannot use glTexSubImage2D. 122 this ( vec2i sz, uint lpp = 4 ) 123 { 124 super( vec2i( sz.x.nextPower2, sz.y.nextPower2 ) ); 125 126 enforce!glTexImage2D( target, 0, lpp.toFormat, 127 size.x, size.y, 0, GL_RED, 128 GL_UNSIGNED_BYTE, null ); 129 } 130 131 /// Modifies the texture. 132 void overwrite (B) ( in B bmp, vec2i offset = vec2i(0,0) ) 133 if ( isBitmap!B ) 134 { 135 auto formatted = resizeBitmapPower2( bmp ); 136 scope(exit) formatted.dispose(); 137 138 enum type = toGLType!(B.bitType); 139 enum format = B.lengthPerPixel.toFormat; 140 const bmpSize = formatted.size; 141 142 bind(); 143 enforce!glTexSubImage2D( target, 0, offset.x, offset.y, 144 bmpSize.x, bmpSize.y, format, type, formatted.data ); 145 } 146 }