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