1 module converter;
2 
3 //import imageformats;
4 
5 import PixelPerfectEngine.graphics.bitmap;
6 import PixelPerfectEngine.extbmp.extbmp;
7 import PixelPerfectEngine.system.exc;
8 import PixelPerfectEngine.system.etc;
9 import PixelPerfectEngine.map.mapload;
10 
11 //import derelict.freeimage.freeimage;
12 //import derelict.freeimage.functions;
13 //import derelict.freeimage.types;
14 
15 import std.stdio;
16 import std.path;
17 import std.bitmanip;
18 import std.conv;
19 
20 /*Bitmap32Bit import32BitBitmapFromFile(string filename){
21 
22 	FREE_IMAGE_FORMAT format;
23 	switch(filename[filename.length-3..filename.length]){
24 		case "png": format = FIF_PNG; break;
25 		case "tga": format = FIF_TARGA; break;
26 		case "bmp": format = FIF_BMP; break;
27 		default: break;
28 	}
29 
30 	const char* fn = std.string.toStringz(filename);
31 	FIBITMAP* source = FreeImage_Load(format, fn);
32 	int iX = FreeImage_GetWidth(source), iY = FreeImage_GetHeight(source);
33 	Bitmap32Bit result = new Bitmap32Bit(iX,iY);
34 	switch(FreeImage_GetBPP(source)){
35 		case 32:
36 			for(int y; y < iY; y++){
37 				for(int x; x < iX; x++){
38 					RGBQUAD c; FreeImage_GetPixelColor(source, x, iY - 1 - y, &c);
39 					result.writePixel(x,y,c.rgbRed,c.rgbGreen,c.rgbBlue,c.rgbReserved);
40 					//writeln(c.rgbRed,',',c.rgbGreen,',',c.rgbBlue,',',c.rgbReserved,',');
41 				}
42 			}
43 			break;
44 		default:
45 			for(int y; y < iY; y++){
46 				for(int x; x < iX; x++){
47 					RGBQUAD c; FreeImage_GetPixelColor(source, x, iY - 1 - y, &c);
48 					result.writePixel(x,y,c.rgbRed,c.rgbGreen,c.rgbBlue,255);
49 					//writeln(c.rgbRed,',',c.rgbGreen,',',c.rgbBlue,',',c.rgbReserved,',');
50 				}
51 			}
52 			break;
53 	}
54 
55 	return result;
56 }*/
57 
58 enum NumberingStyle{
59 	DECIMAL		=	0,
60 	OCTAL		=	1,
61 	HEXADECIMAL	=	2,
62 	CHAR		=	3,
63 	WCHAR		=	4
64 }
65 
66 class ImportData{
67 	string[] ID;
68 	string bitdepth, format;
69 	int x, y, IDpos;
70 	ushort paletteOffset;
71 	NamingConvention nc;
72 	this(string[] ID, string bitdepth, int x, int y, ushort paletteOffset){
73 		this.ID = ID;
74 		this.bitdepth = bitdepth;
75 		this.x = x;
76 		this.y = y;
77 		this.paletteOffset = paletteOffset;
78 		//this.numOfDigits = numOfDigits;
79 	}
80 	this(NamingConvention nc, string bitdepth, int x, int y, ushort paletteOffset){
81 		this.nc = nc;
82 		this.bitdepth = bitdepth;
83 		this.x = x;
84 		this.y = y;
85 		this.paletteOffset = paletteOffset;
86 		//this.numOfDigits = numOfDigits;
87 	}
88 	string getNextID(){
89 		if(nc is null){
90 			string result = ID[IDpos];
91 			IDpos++;
92 			return result;
93 		}else{
94 			string result = nc.wordA;
95 			switch(nc.incrStyle){
96 				case NumberingStyle.OCTAL: result ~= intToOct(IDpos+nc.startingPoint,nc.format); break;
97 				case NumberingStyle.HEXADECIMAL: result ~= intToHex(IDpos+nc.startingPoint,nc.format); break;
98 				default: result ~= to!string(IDpos+nc.startingPoint); break;
99 			}
100 			IDpos++;
101 			result ~= nc.wordB;
102 			return result;
103 		}
104 	}
105 	bool isMulti(){
106 		if(x > 0 && y > 0) return true;
107 		return false;
108 	}
109 
110 }
111 
112 class NamingConvention{
113 	string wordA, wordB;
114 	NumberingStyle incrStyle;
115 	int startingPoint, format;
116 	this(string wordA, string wordB, NumberingStyle incrStyle, int startingPoint, int format){
117 		this.wordA = wordA;
118 		this.wordB = wordB;
119 		this.incrStyle = incrStyle;
120 		this.startingPoint = startingPoint;
121 		this.format = format;
122 	}
123 }
124 
125 public class BitmapInfo{
126 	int width, height;
127 	public this(){
128 
129 	}
130 }
131 
132 public BitmapInfo getBitmapInfo(string path){
133 	import std..string;
134 	/*FREE_IMAGE_FORMAT format;
135 	switch(extension(path)){
136 		case ".png": format = FIF_PNG; break;
137 		case ".tga": format = FIF_TARGA; break;
138 		case ".bmp": format = FIF_BMP; break;
139 		default: break;
140 	}
141 	const char* fn = std.string.toStringz(path);
142 	FIBITMAP* source = FreeImage_Load(format, fn);
143 	BitmapInfo bi = new BitmapInfo;
144 	bi.width = FreeImage_GetWidth(source);
145 	bi.height = FreeImage_GetHeight(source);
146 	if(source)
147 		FreeImage_Unload(source);
148 	return bi;*/
149 	throw new Exception("Function unimplemented!");
150 }
151 
152 public void importDirectlyToXMP(string path, string palette, ExtendibleBitmap target, ImportData id){
153 	/*import std.string;
154 	FREE_IMAGE_FORMAT format;
155 	switch(extension(path)){
156 		case ".png": format = FIF_PNG; break;
157 		case ".tga": format = FIF_TARGA; break;
158 		case ".bmp": format = FIF_BMP; break;
159 		default: break;
160 	}
161 	const char* fn = std.string.toStringz(path);
162 	FIBITMAP* source = FreeImage_Load(format, fn);
163 	int iX = FreeImage_GetWidth(source), iY = FreeImage_GetHeight(source);
164 	ubyte[] raw; ushort[] raw16;
165 	switch(id.bitdepth){
166 		case "1bit":
167 			BitArray ba = BitArray(cast(void[])raw, 0);
168 			ba.length(iX * iY);
169 			for(int y; y < iY; y++){
170 				for(int x; x < iX; x++){
171 					ubyte c; FreeImage_GetPixelIndex(source, x, iY - 1 - y, &c);
172 					if(c != 0){
173 						ba[x + (iX * y)] = true;
174 					}
175 				}
176 			}
177 			break;
178 		case "16bit":
179 			for(int y; y < iY; y++){
180 				for(int x; x < iX; x++){
181 					ubyte c; FreeImage_GetPixelIndex(source, x, iY - 1 - y, &c);
182 					raw16 ~= to!ushort(id.paletteOffset + c);
183 				}
184 			}
185 			break;
186 		default:
187 			switch(FreeImage_GetBPP(source)){
188 				case 1,2,4,8:
189 					for(int y; y < iY; y++){
190 						for(int x; x < iX; x++){
191 							ubyte c; FreeImage_GetPixelIndex(source, x, iY - 1 - y, &c);
192 							raw ~= c;
193 						}
194 					}
195 					break;
196 				case 32:
197 					for(int y; y < iY; y++){
198 						for(int x; x < iX; x++){
199 							RGBQUAD c; FreeImage_GetPixelColor(source, x, iY - 1 - y, &c);
200 							//result.writePixel(x,y,c.rgbRed,c.rgbGreen,c.rgbBlue,c.rgbReserved);
201 							//writeln(c.rgbRed,',',c.rgbGreen,',',c.rgbBlue,',',c.rgbReserved,',');
202 							raw ~= [c.rgbRed,c.rgbGreen,c.rgbBlue,c.rgbReserved];
203 						}
204 					}
205 					break;
206 				default:
207 					for(int y; y < iY; y++){
208 						for(int x; x < iX; x++){
209 							RGBQUAD c; FreeImage_GetPixelColor(source, x, iY - 1 - y, &c);
210 							//result.writePixel(x,y,c.rgbRed,c.rgbGreen,c.rgbBlue,255);
211 							//writeln(c.rgbRed,',',c.rgbGreen,',',c.rgbBlue,',',c.rgbReserved,',');
212 							raw ~= [c.rgbRed,c.rgbGreen,c.rgbBlue,255];
213 						}
214 					}
215 					break;
216 			}
217 			break;
218 	}
219 	if(id.isMulti){
220 		if(iX%id.x > 0 || iY%id.y > 0){
221 			throw new BitmapFormatException("Incorrect sizes for slicing!");
222 		}
223 		if(id.bitdepth == "16bit"){
224 			//target.addBitmap(raw16,id.x,id.y,id.bitdepth,id.ID[0]);
225 			for(int jY; jY < iY / id.y; jY++){
226 				for(int jX; jX < iX / id.x; jX++){
227 					ushort[] raw2;
228 					for(int y; y < id.y; y++){
229 						int from = ((jY * id.y * iX) + (y * iX) + (jX * id.x)), t = from + id.x;
230 						raw2 ~= raw16[from..t];
231 					}
232 					target.addBitmap(raw2,id.x,id.y,id.bitdepth,id.getNextID(),id.format,palette);
233 					//si++;
234 				}
235 			}
236 		}else{
237 			int pitch = 1;
238 			if(id.bitdepth == "32bit")pitch = 4;
239 			for(int jY; jY < iY / id.y; jY++){
240 				for(int jX; jX < iX / id.x; jX++){
241 					ubyte[] raw2;
242 					for(int y; y < id.y; y++){
243 						int from = pitch * ((jY * id.y * iX) + (y * iX) + (jX * id.x)), t = from + (id.x * pitch);
244 						raw2~= raw[from..t];
245 					}
246 					target.addBitmap(raw2,id.x,id.y,id.bitdepth,id.getNextID(),id.format,palette);
247 					//si++;
248 				}
249 			}
250 
251 		}
252 	}else{
253 		if(id.bitdepth == "16bit"){
254 			target.addBitmap(raw16,iX,iY,id.bitdepth,id.ID[0]);
255 		}else{
256 			target.addBitmap(raw,iX,iY,id.bitdepth,id.ID[0],id.format);
257 		}
258 	}
259 	if(source)
260 		FreeImage_Unload(source);*/
261 	throw new Exception("XMP is being deprecated. Please use different graphics format.");
262 }
263 
264 public void importPaletteDirectlyToXMP(string path, ExtendibleBitmap target, string paletteID, ushort offset = 0){
265 	import std..string;
266 	/*FREE_IMAGE_FORMAT format;
267 	switch(extension(path)){
268 		case ".png": format = FIF_PNG; break;
269 		case ".tga": format = FIF_TARGA; break;
270 		case ".bmp": format = FIF_BMP; break;
271 		default: break;
272 	}
273 	const char* fn = std.string.toStringz(path);
274 	FIBITMAP* source = FreeImage_Load(format, fn);
275 	uint bitdepth = FreeImage_GetBPP(source);
276 
277 	ubyte[] palette;
278 	switch(bitdepth){
279 		case 4: palette.length = 64; break;
280 		case 8: palette.length = 1024; break;
281 		default: break;
282 	}
283 	RGBQUAD* colors = FreeImage_GetPalette(source);
284 	//RGBQUAD.sizeof;
285 	palette[0] = 0;
286 	palette[1] = colors.rgbRed;
287 	palette[2] = colors.rgbGreen;
288 	palette[3] = colors.rgbBlue;
289 	for(int i = 4; i < palette.length; i+=4){
290 		colors++;
291 		palette[i] = 255;
292 		palette[i + 1] = colors.rgbRed;
293 		palette[i + 2] = colors.rgbGreen;
294 		palette[i + 3] = colors.rgbBlue;
295 
296 	}
297 	target.addPalette(cast(void[])palette, paletteID);
298 	if(source)
299 		FreeImage_Unload(source);*/
300 	throw new Exception("XMP is being deprecated. Please use different graphics format.");
301 }
302 
303 public Bitmap32Bit getBitmapPreview(ExtendibleBitmap xmp, string ID){
304 	Bitmap32Bit result;
305 	switch(xmp.getBitDepth(ID)){
306 		case "32bit":
307 			result = new Bitmap32Bit(cast(Color[])xmp.getBitmap(ID),xmp.getXsize(ID),xmp.getYsize(ID));
308 			break;
309 		case "16bit":
310 			ushort[] raw = xmp.get16bitBitmap(ID);
311 			Color[] clut = cast(Color[])xmp.getPalette(xmp.getPaletteMode(ID));
312 			Color[] res2;
313 			foreach(c; raw){
314 				res2 ~= clut[c];
315 			}
316 			result = new Bitmap32Bit(res2,xmp.getXsize(ID),xmp.getYsize(ID));
317 			break;
318 		case "8bit":
319 			ubyte[] raw = xmp.get8bitBitmap(ID);
320 			Color[] clut = cast(Color[])xmp.getPalette(xmp.getPaletteMode(ID));
321 			Color[] res2;
322 			foreach(c; raw){
323 				res2 ~= clut[c];
324 			}
325 			result = new Bitmap32Bit(res2,xmp.getXsize(ID),xmp.getYsize(ID));
326 			break;
327 		default: break;
328 	}
329 	return result;
330 }
331 
332 public void autoloadFromXMP(string filename, ExtendibleMap map, int layerNum){
333 	ExtendibleBitmap xmpFile = new ExtendibleBitmap(filename);
334 	map.addFileToTileSource(layerNum, filename);
335 	for(int i ; i < xmpFile.bitmapID.length ; i++){
336 		try{
337 			if(xmpFile.bitmapID[i].length <= 4){
338 				throw new Exception("");
339 			}
340 			wchar ID = to!wchar(parseHex(xmpFile.bitmapID[i][0..4]));
341 			string descr = xmpFile.bitmapID[i].length > 5 ? xmpFile.bitmapID[i][5..xmpFile.bitmapID[i].length] : "";
342 			map.addTileToTileSource(layerNum, ID, descr, xmpFile.bitmapID[i], filename);
343 		}catch(Exception e){
344 			writeln("Bitmap \'"~xmpFile.bitmapID[i]~"\' does not follow the format xxxx\\{description} and will be skipped.");
345 		}
346 	}
347 }
348 
349 enum LookupMethod : uint{
350 	NearestValue	=	1,
351 	Dithering		=	2
352 }