1 module prova.assets.models.texture; 2 3 import imageformats; 4 import prova.assets; 5 import prova.graphics; 6 import std.algorithm.mutation; 7 import std.string; 8 9 /// 10 final class Texture : Asset 11 { 12 private static uint bindedId; 13 /// 14 immutable uint id; 15 private int _width; 16 private int _height; 17 18 /// Creates a new blank texture using the specified width and height 19 this(int width, int height) 20 { 21 this(null, width, height); 22 } 23 24 /** 25 * Params: 26 * data = RGBA by row 27 */ 28 this(ubyte[] data, int width, int height) 29 { 30 uint id; 31 glGenTextures(1, &id); 32 33 this.id = id; 34 35 recreate(data, width, height); 36 } 37 38 /// 39 this(string path) 40 { 41 IFImage image = read_image(path, ColFmt.RGBA); 42 43 flipImage(image); 44 45 this(image.pixels, image.w, image.h); 46 } 47 48 /// 49 @property int width() 50 { 51 return _width; 52 } 53 54 /// 55 @property int height() 56 { 57 return _height; 58 } 59 60 /** 61 * Params: 62 * data = RGBA by row 63 * width = new width of the texture 64 * width = new height of the texture 65 */ 66 void recreate(ubyte[] data, int width, int height) 67 { 68 bind(); 69 70 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 71 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 72 73 glTexImage2D( 74 GL_TEXTURE_2D, 75 0, 76 GL_RGBA, 77 width, 78 height, 79 0, 80 GL_RGBA, 81 GL_UNSIGNED_BYTE, 82 data ? data.ptr : null 83 ); 84 85 _width = width; 86 _height = height; 87 } 88 89 /** 90 * Updates the texture 91 * 92 * Params: 93 * data = RGBA by row 94 */ 95 void update(ubyte[] data) 96 { 97 update(data, 0, 0, _width, _height); 98 } 99 100 /** 101 * Updates part of the texture 102 * 103 * Params: 104 * data = RGBA by row 105 * x = x offset of the change 106 * y = y offset of the change 107 * width = width of the change 108 * height = height of the change 109 */ 110 void update(ubyte[] data, int x, int y, int width, int height) 111 { 112 bind(); 113 114 glTexSubImage2D( 115 GL_TEXTURE_2D, 116 0, 117 x, 118 y, 119 width, 120 height, 121 GL_RGBA, 122 GL_UNSIGNED_BYTE, 123 data ? data.ptr : null 124 ); 125 } 126 127 /// Resizes texture, preserving data 128 void resize(int width, int height) 129 { 130 ubyte[] data = getData(); 131 132 recreate(null, width, height); 133 update(data, 0, 0, _width, _height); 134 } 135 136 /// 137 ubyte[] getData() 138 { 139 ubyte[] data; 140 data.length = _width * _height * 4; 141 142 bind(); 143 144 glGetTexImage( 145 GL_TEXTURE_2D, 146 0, 147 GL_RGBA, 148 GL_UNSIGNED_BYTE, 149 data.ptr 150 ); 151 152 return data; 153 } 154 155 private static void flipImage(ref IFImage image) 156 { 157 int rowLength = image.w * 4; 158 159 foreach(i; 0 .. image.h) 160 { 161 const int start = i * rowLength; 162 163 ubyte[] row = image.pixels[start .. start + rowLength]; 164 165 reverse(row); 166 167 copy(image.pixels[start .. start + rowLength], row[0 .. rowLength]); 168 } 169 170 reverse(image.pixels); 171 } 172 173 ~this() 174 { 175 glDeleteTextures(1, &id); 176 } 177 178 package(prova) void bind() 179 { 180 bind(id); 181 } 182 183 package(prova) static void bind(uint id) 184 { 185 if(bindedId == id) 186 return; 187 188 bindedId = id; 189 glBindTexture(GL_TEXTURE_2D, id); 190 } 191 }