1 module armos.graphics.image; 2 3 import armos.graphics; 4 import armos.math; 5 /++ 6 画像のファイルフォーマットを表します 7 +/ 8 enum ImageFormat{ 9 BMP = 0, 10 ICO = 1, 11 JPEG = 2, 12 JNG = 3, 13 KOALA = 4, 14 LBM = 5, 15 IFF = LBM, 16 MNG = 6, 17 PBM = 7, 18 PBMRAW = 8, 19 PCD = 9, 20 PCX = 10, 21 PGM = 11, 22 PGMRAW = 12, 23 PNG = 13, 24 PPM = 14, 25 PPMRAW = 15, 26 RAS = 16, 27 TARGA = 17, 28 TIFF = 18, 29 WBMP = 19, 30 PSD = 20, 31 CUT = 21, 32 XBM = 22, 33 XPM = 23, 34 DDS = 24, 35 GIF = 25, 36 HDR = 26, 37 FAXG3 = 27, 38 SGI = 28, 39 EXR = 29, 40 J2K = 30, 41 JP2 = 31, 42 PFM = 32, 43 PICT = 33, 44 RAW = 34 45 } 46 47 48 import derelict.freeimage.freeimage; 49 50 /++ 51 画像を表すクラスです. 52 load()で画像を読み込み,draw()で表示することができます. 53 +/ 54 class Image { 55 public{ 56 this(){ 57 if(!isInitializedFreeImage){ 58 DerelictFI.load(); 59 FreeImage_Initialise(); 60 isInitializedFreeImage = true; 61 } 62 _material = (new DefaultMaterial); 63 _material.uniform("diffuse", Vector4f(1, 1, 1, 1)); 64 } 65 66 /++ 67 Load image. 68 69 画像を読み込みます. 70 +/ 71 Image load(string pathInDataDir){ 72 import std.string; 73 FIBITMAP * freeImageBitmap = null; 74 _bitmap = Bitmap!(char)(); 75 76 import armos.utils; 77 string fileName = absolutePath(pathInDataDir); 78 79 FREE_IMAGE_FORMAT freeImageFormat = FIF_UNKNOWN; 80 freeImageFormat = FreeImage_GetFileType(fileName.toStringz , 0); 81 82 if(freeImageFormat == FIF_UNKNOWN) { 83 freeImageFormat = FreeImage_GetFIFFromFilename(fileName.toStringz); 84 } 85 if((freeImageFormat != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(freeImageFormat)) { 86 freeImageBitmap = FreeImage_Load(freeImageFormat, fileName.toStringz, 0); 87 if (freeImageBitmap != null){ 88 _isLoaded = true; 89 } 90 } 91 92 if ( _isLoaded ){ 93 //TODO: bring freeImageBitmap to Bitmap 94 bitmap(freeImageBitmap); 95 } 96 97 if (freeImageBitmap != null){ 98 FreeImage_Unload(freeImageBitmap); 99 } 100 101 allocate; 102 _material.texture("tex0", this._texture); 103 return this; 104 } 105 106 107 Image drawCropped(T)( 108 in T x, in T y, 109 in T startX, in T startY, 110 in T endX, in T endY 111 ){ 112 drawCropped(x, y, T(0), startX, startY, endX, endY); 113 return this; 114 } 115 116 Image drawCropped(T)( 117 in T x, in T y, in T z, 118 in T startX, in T startY, 119 in T endX, in T endY 120 ){ 121 if(_isLoaded){ 122 import std.conv; 123 _rect.texCoords[0] = Vector4f(startX.to!float/_texture.width, startY.to!float/_texture.height, 0, 1); 124 _rect.texCoords[1] = Vector4f(startX.to!float/_texture.width, endY.to!float/_texture.height, 0, 1); 125 _rect.texCoords[2] = Vector4f(endX.to!float/_texture.width, endY.to!float/_texture.height, 0, 1); 126 _rect.texCoords[3] = Vector4f(endX.to!float/_texture.width, startY.to!float/_texture.height, 0, 1); 127 128 // _rect.texCoords[0] = Vector4f(0, 0, 0, 1); 129 // _rect.texCoords[1] = Vector4f(0, 1, 0, 1); 130 // _rect.texCoords[2] = Vector4f(1, 1, 0, 1); 131 // _rect.texCoords[3] = Vector4f(1, , 0, 1); 132 133 _rect.vertices[0] = Vector4f(0f, 0f, 0f, 1f); 134 _rect.vertices[1] = Vector4f(0f, endY-startY, 0f, 1f); 135 _rect.vertices[2] = Vector4f(endX-startX, endY-startY, 0f, 1f); 136 _rect.vertices[3] = Vector4f(endX-startX, 0f, 0f, 1f); 137 138 pushMatrix; 139 translate(x, y, z); 140 _material.begin; 141 _rect.drawFill(); 142 _material.end; 143 popMatrix; 144 } 145 146 return this; 147 } 148 149 /++ 150 Draw image data which loaded in advance. 151 152 読み込んだ画像データを画面に描画します. 153 +/ 154 Image draw(T)(in T x, in T y, in T z = T(0)){ 155 drawCropped(x, y, z, 0, 0, bitmap.width, bitmap.height); 156 return this; 157 } 158 159 /++ 160 Draw image data which loaded in advance. 161 162 読み込んだ画像データを画面に描画します. 163 +/ 164 Image draw(T)(in T position)const{ 165 static if(position.data.length == 2) 166 draw(position[0], position[1]); 167 else if(position.data.length == 3) 168 draw(position[0], position[1], position[2]); 169 else 170 static assert(0, "arg is invalid dimention"); 171 return this; 172 } 173 174 /++ 175 Return image size. 176 177 画像のサイズを返します. 178 +/ 179 Vector2i size()const{return _size;} 180 181 /++ 182 Return width. 183 184 画像の幅を返します. 185 +/ 186 int width()const{return _size[0];} 187 188 /++ 189 Return height. 190 191 画像の高さを返します. 192 +/ 193 int height()const{return _size[1];} 194 195 /++ 196 Return bitmap pointer. 197 198 画像のビットマップデータを返します. 199 +/ 200 Bitmap!(char) bitmap(){return _bitmap;} 201 202 /++ 203 Set bitmap 204 +/ 205 Image bitmap(Bitmap!(char) data){ 206 _bitmap = data; 207 allocate(); 208 _isLoaded = true; 209 _material.texture("tex0", this._texture); 210 return this; 211 } 212 213 /++ 214 Generate a image from the aligned pixels 215 216 一次元配列からImageを生成します 217 +/ 218 Image setFromAlignedPixels(T)(T* pixels, int width, int height, ColorFormat format){ 219 _bitmap.setFromAlignedPixels(cast(char*)pixels, width, height, format); 220 allocate; 221 _isLoaded = true; 222 _material.texture("tex0", this._texture); 223 return this; 224 } 225 226 /++ 227 与えられたbitmapを元にtextureとrectを生成します 228 +/ 229 Image allocate(){ 230 _texture = new Texture; 231 _texture.allocate(_bitmap); 232 _rect = new Mesh; 233 _rect.primitiveMode = PrimitiveMode.TriangleStrip ; 234 float x = _bitmap.width; 235 float y = _bitmap.height; 236 237 _rect.vertices = [ 238 Vector4f(0.0, 0.0, 0.0, 1.0f), 239 Vector4f(0.0, y, 0.0, 1.0f), 240 Vector4f(x, y, 0.0, 1.0f), 241 Vector4f(x, 0.0, 0.0, 1.0f), 242 ]; 243 244 _rect.texCoords0= [ 245 Vector4f(0f, 0f, 0f, 1f), 246 Vector4f(0, 1f*_bitmap.height/_texture.height, 0f, 1f), 247 Vector4f(1f*_bitmap.width/_texture.width, 1f*_bitmap.height/_texture.height, 0f, 1f), 248 Vector4f(1f*_bitmap.width/_texture.width, 0, 0f, 1f), 249 ]; 250 251 _rect.indices = [ 252 0, 1, 2, 253 2, 3, 0, 254 ]; 255 return this; 256 } 257 258 /++ 259 Retun true if the image was loaded. 260 261 画像が読み込まれている場合trueを,そうでない場合はfalseを返します. 262 +/ 263 bool isLoaded()const{ 264 return _isLoaded; 265 } 266 267 /++ 268 +/ 269 Texture texture(){ 270 return _texture; 271 } 272 273 /++ 274 +/ 275 Image minMagFilter(in TextureMinFilter minFilter, in TextureMagFilter magFilter){ 276 _texture.minMagFilter(minFilter, magFilter); 277 return this; 278 } 279 280 /++ 281 +/ 282 Image minFilter(in TextureMinFilter filter){ 283 _texture.minFilter(filter); 284 return this; 285 } 286 287 /// 288 Image magFilter(in TextureMagFilter filter){ 289 _texture.magFilter(filter); 290 return this; 291 } 292 293 /// 294 Material material(){ 295 return _material; 296 } 297 }//public 298 299 private{ 300 static bool isInitializedFreeImage = false; 301 Vector2i _size; 302 Bitmap!(char) _bitmap; 303 Texture _texture; 304 Mesh _rect; 305 bool _isLoaded = false; 306 Material _material; 307 308 /++ 309 ImageのbitmapにfreeImageのbitmapを指定します. 310 +/ 311 void bitmap(FIBITMAP* freeImageBitmap, bool swapForLittleEndian = true){ 312 FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(freeImageBitmap); 313 314 uint bits = char.sizeof; 315 316 import std.stdio; 317 FIBITMAP* bitmapConverted; 318 bitmapConverted = FreeImage_ConvertTo32Bits(freeImageBitmap); 319 freeImageBitmap = bitmapConverted; 320 321 uint width = FreeImage_GetWidth(freeImageBitmap); 322 uint height = FreeImage_GetHeight(freeImageBitmap); 323 uint bpp = FreeImage_GetBPP(freeImageBitmap); 324 uint channels = (bpp / bits) / 8; 325 uint pitch = FreeImage_GetPitch(freeImageBitmap); 326 327 ColorFormat armosColorFormat; 328 switch (channels) { 329 case 1: 330 armosColorFormat = ColorFormat.Gray; 331 break; 332 case 2: 333 armosColorFormat = ColorFormat.Gray; 334 break; 335 case 3: 336 armosColorFormat = ColorFormat.RGB; 337 break; 338 case 4: 339 armosColorFormat = ColorFormat.RGBA; 340 break; 341 default: 342 break; 343 } 344 345 FreeImage_FlipVertical(freeImageBitmap); 346 char* bitmapBits = cast(char*)FreeImage_GetBits(freeImageBitmap); 347 348 _bitmap.setFromAlignedPixels(bitmapBits, width, height, armosColorFormat); 349 _bitmap.swapRAndB; 350 _size = _bitmap.size; 351 } 352 }//private 353 }//class Image