1 /*
2  * Copyright (C) 2015-2020, by Laszlo Szeremi under the Boost license.
3  *
4  * Pixel Perfect Engine, graphics.layers.trnstilelayer module
5  */
6 
7 module PixelPerfectEngine.graphics.layers.trnstilelayer;
8 
9 public import PixelPerfectEngine.graphics.layers.base;
10 import PixelPerfectEngine.system.etc;
11 import PixelPerfectEngine.system.exc;
12 import collections.treemap;
13 import inteli.emmintrin;
14 
15 /**
16  * Implements a modified TileLayer with transformability with capabilities similar to MODE7.
17  * <br/>
18  * Transform function:
19  * [x',y'] = ([A,B,C,D] * ([x,y] + [sX,sY] - [x_0,y_0])>>>8 + [x_0,y_0]
20  * <br/>
21  * All basic transform values are integer based, 256 equals with 1.0
22  * <br/>
23  * Restrictions compared to standard TileLayer:
24  * <ul>
25  * <li>Tiles must have any of the following sizes: 8, 16, 32, 64; since this layer needs to do modulo computations for each pixel.</li>
26  * <li>In future versions, map sizes for this layer will be restricted to power of two sizes to make things faster</li>
27  * <li>Maximum layer size in pixels are restricted to 65536*65536 due to architectural limitations. Accelerated versions might raise
28  * this limitation.</li>
29  * </ul>
30  * HDMA emulation supported through delegate hBlankInterrupt.
31  */
32 public class TransformableTileLayer(BMPType = Bitmap16Bit, int TileX = 8, int TileY = 8) : Layer, ITileLayer{
33 		/*if(isPowerOf2(TileX) && isPowerOf2(TileY))*/
34 	protected struct DisplayListItem {
35 		BMPType	tile;		///For reference counting
36 		void* 	pixelSrc;	///Used for quicker access to the Data
37 		wchar 	ID;			///ID, mainly used as a padding and secondary identification
38 		/**
39 		 * Sets the maximum accessable color amount by the bitmap.
40 		 * By default, for 4 bit bitmaps, it's 4, and it enables 256 * 16 color palettes.
41 		 * This limitation is due to the way how the MappingElement struct works.
42 		 * 8 bit bitmaps can assess the full 256 * 256 palette space.
43 		 * Lower values can be described to avoid wasting palettes space in cases when the
44 		 * bitmaps wouldn't use their full capability.
45 		 * Not used with 16 bit indexed and 32 bit direct color bitmaps.
46 		 */
47 		ubyte	palShift;
48 		ubyte 	reserved;	///Padding for 32 bit
49 		this (wchar ID, BMPType tile, ubyte paletteSh = 0) pure @trusted @nogc nothrow {
50 			void _systemWrapper() pure @system @nogc nothrow {
51 				pixelSrc = cast(void*)tile.getPtr();
52 			}
53 			this.ID = ID;
54 			this.tile = tile;
55 			static if (BMPType.mangleof == Bitmap4Bit.mangleof) this.palShift = paletteSh ? paletteSh : 4;
56 			else static if (BMPType.mangleof == Bitmap8Bit.mangleof) this.palShift = paletteSh ? paletteSh : 8;
57 			_systemWrapper;
58 		}
59 		string toString() const {
60 			import std.conv : to;
61 			string result = to!string(cast(ushort)ID) ~ " ; " ~ to!string(pixelSrc);
62 			return result;
63 		}
64 	}
65 	alias DisplayList = TreeMap!(wchar, DisplayListItem, true);
66 	protected DisplayList displayList;
67 	protected short[4] transformPoints;	/** Defines how the layer is being transformed */
68 	protected short[2] tpOrigin;		/** Transform point */
69 	protected Bitmap32Bit backbuffer;	///used to store current screen output
70 	/*static if(BMPType.mangleof == Bitmap8Bit.mangleof){
71 		protected ubyte[] src;
72 		protected Color* palettePtr;	///Shared palette
73 	}else static if(BMPType.mangleof == Bitmap16Bit.mangleof){
74 		protected ushort[] src;*/
75 	static if(is(BMPType == Bitmap4Bit) || is(BMPType == Bitmap8Bit) ||	is(BMPType == Bitmap16Bit)){
76 		protected ushort[] src;
77 	}else static if(is(BMPType == Bitmap32Bit)){
78 
79 	}else static assert(false,"Template parameter " ~ BMPType.mangleof ~ " not supported by TransformableTileLayer!");
80 	//TO DO: Replace these with a single 32 bit value
81 	protected bool		needsUpdate;	///Set to true if backbuffer needs an update (might be replaced with flags)
82 	public WarpMode		warpMode;		///Repeats the whole layer if set to true
83 	public ubyte		masterVal;		///Sets the master alpha value for the layer
84 	public ushort		paletteOffset;	///Offsets the palette by the given amount
85 	protected int mX, mY;				///"Inherited" from TileLayer
86 	static if(TileX == 8)
87 		protected immutable int shiftX = 3;
88 	else static if(TileX == 16)
89 		protected immutable int shiftX = 4;
90 	else static if(TileX == 32)
91 		protected immutable int shiftX = 5;
92 	else static if(TileX == 64)
93 		protected immutable int shiftX = 6;
94 	else static assert(false,"Unsupported horizontal tile size!");
95 	static if(TileY == 8)
96 		protected immutable int shiftY = 3;
97 	else static if(TileY == 16)
98 		protected immutable int shiftY = 4;
99 	else static if(TileY == 32)
100 		protected immutable int shiftY = 5;
101 	else static if(TileY == 64)
102 		protected immutable int shiftY = 6;
103 	else static assert(false,"Unsupported vertical tile size!");
104 	protected int totalX, totalY;
105 	protected MappingElement[] mapping;
106 	
107 	protected int4 _tileAmpersand;      ///Used for quick modulo by power of two to calculate tile positions.
108 	protected short8 _increment;
109 	protected __m128i _mapAmpersand;    ///Used for quick modulo by power of two to read maps
110 	//protected __m128i _mapShift;		///Used for quick divide by power of two to read maps
111 	
112 	alias HBIDelegate = @nogc nothrow void delegate(ref short[4] localABCD, ref short[2] localsXsY, ref short[2] localx0y0, short y);
113 	/**
114 	 * Called before each line being redrawn. Can modify global values for each lines.
115 	 */
116 	public HBIDelegate hBlankInterrupt;
117 
118 	this (RenderingMode renderMode = RenderingMode.AlphaBlend) {
119 		A = 256;
120 		B = 0;
121 		C = 0;
122 		D = 256;
123 		x_0 = 0;
124 		y_0 = 0;
125 		_tileAmpersand = [TileX - 1, TileY - 1, TileX - 1, TileY - 1];
126 		//_mapShift = [shiftX, shiftY, shiftX, shiftY];
127 		masterVal = ubyte.max;
128 		setRenderingMode(renderMode);
129 		needsUpdate = true;
130 		//static if (BMPType.mangleof == Bitmap4Bit.mangleof) _paletteOffset = 4;
131 		//else static if (BMPType.mangleof == Bitmap8Bit.mangleof) _paletteOffset = 8;
132 		for(int i ; i < 8 ; i+=2)
133 			_increment[i] = 2;
134 	}
135 
136 
137 	
138 	override public void setRasterizer(int rX,int rY) {
139 		super.setRasterizer(rX,rY);
140 		backbuffer = new Bitmap32Bit(rX, rY);
141 		static if(BMPType.mangleof == Bitmap8Bit.mangleof || BMPType.mangleof == Bitmap16Bit.mangleof){
142 			src.length = rX;
143 		}
144 	}
145 
146 	override public @nogc void updateRaster(void* workpad,int pitch,Color* palette) {
147 		//import core.stdc.stdio;
148 		if(needsUpdate){
149 			needsUpdate = false;
150 			//clear buffer
151 			//backbuffer.clear();
152 			Color* dest = backbuffer.getPtr();
153 			short[2] sXsY = [cast(short)sX,cast(short)sY];
154 			short[4] localTP = transformPoints;
155 			short[2] localTPO = tpOrigin;
156 			//write new data into it
157 			for(short y; y < rasterY; y++){
158 				if(hBlankInterrupt !is null){
159 					hBlankInterrupt(localTP, sXsY, localTPO, y);
160 				}
161 				short8 _sXsY, _localTP, _localTPO;
162 				for(int i; i < 8; i++){
163 					_sXsY[i] = sXsY[i & 1];
164 					_localTP[i] = localTP[i & 3];
165 					_localTPO[i] = localTPO[i & 1];
166 				}
167 				short8 xy_in;
168 				for(int i = 1; i < 8; i += 2){
169 					xy_in[i] = y;
170 				}
171 				xy_in[4] = 1;
172 				xy_in[6] = 1;
173 				int4 _localTPO_0;
174 				for(int i; i < 4; i++){
175 					_localTPO_0[i] = localTPO[i & 1];
176 				}
177 				for(short x; x < rasterX; x++){
178 					int4 xy = _mm_srai_epi32(_mm_madd_epi16(cast(int4)_localTP, cast(int4)(xy_in + _sXsY - _localTPO)),8)
179 							+ _localTPO_0;
180 					/+MappingElement currentTile0 = tileByPixelWithoutTransform(xy[0],xy[1]),
181 							currentTile[1] = tileByPixelWithoutTransform(xy[2],xy[3]);+/
182 					MappingElement[2] currentTile = tileByPixelWithoutTransform(xy);
183 					xy &= _tileAmpersand;
184 					if(currentTile[0].tileID != 0xFFFF){
185 						const DisplayListItem d = displayList[currentTile[0].tileID];
186 						static if(is(BMPType == Bitmap4Bit)){
187 							ubyte* tsrc = cast(ubyte*)d.pixelSrc;
188 						}else static if(is(BMPType == Bitmap8Bit)){
189 							ubyte* tsrc = cast(ubyte*)d.pixelSrc;
190 						}else static if(is(BMPType == Bitmap16Bit)){
191 							ushort* tsrc = cast(ushort*)d.pixelSrc;
192 						}else static if(is(BMPType == Bitmap32Bit)){
193 							Color* tsrc = cast(Color*)d.pixelSrc;
194 						}
195 						xy[0] = xy[0] & (TileX - 1);
196 						xy[1] = xy[1] & (TileY - 1);
197 						const int totalOffset = xy[0] + xy[1] * TileX;
198 						static if(BMPType.mangleof == Bitmap4Bit.mangleof){
199 							src[x] = cast(ushort)((totalOffset & 1 ? tsrc[totalOffset>>1]>>4 : tsrc[totalOffset>>1] & 0x0F) | 
200 									currentTile[0].paletteSel<<d.palShift);
201 						}else static if(BMPType.mangleof == Bitmap8Bit.mangleof ){
202 							src[x] = cast(ushort)(tsrc[totalOffset] | currentTile[0].paletteSel<<d.palShift);
203 						}else static if(BMPType.mangleof == Bitmap16Bit.mangleof){
204 							src[x] = tsrc[totalOffset];
205 						}else{
206 							*dest = *tsrc;
207 							dest++;
208 						}
209 					}else{
210 						static if(BMPType.mangleof == Bitmap8Bit.mangleof || BMPType.mangleof == Bitmap16Bit.mangleof ||
211 								BMPType.mangleof == Bitmap4Bit.mangleof){
212 							src[x] = 0;
213 						}else{
214 							(*dest).raw = 0;
215 						}
216 					}
217 					x++;
218 					if(currentTile[1].tileID != 0xFFFF){
219 						const DisplayListItem d = displayList[currentTile[1].tileID];
220 						static if(is(BMPType == Bitmap4Bit)){
221 							ubyte* tsrc = cast(ubyte*)d.pixelSrc;
222 						}else static if(is(BMPType == Bitmap8Bit)){
223 							ubyte* tsrc = cast(ubyte*)d.pixelSrc;
224 						}else static if(is(BMPType == Bitmap16Bit)){
225 							ushort* tsrc = cast(ushort*)d.pixelSrc;
226 						}else static if(is(BMPType == Bitmap32Bit)){
227 							Color* tsrc = cast(Color*)d.pixelSrc;
228 						}
229 						xy[2] = xy[2] & (TileX - 1);
230 						xy[3] = xy[3] & (TileY - 1);
231 						const int totalOffset = xy[2] + xy[3] * TileX;
232 						static if(BMPType.mangleof == Bitmap4Bit.mangleof){
233 							src[x] = cast(ushort)((totalOffset & 1 ? tsrc[totalOffset>>1]>>4 : tsrc[totalOffset>>1] & 0x0F) | 
234 									currentTile[1].paletteSel<<d.palShift);
235 						} else static if(BMPType.mangleof == Bitmap8Bit.mangleof ) {
236 							src[x] = cast(ushort)(tsrc[totalOffset] | currentTile[1].paletteSel<<d.palShift);
237 						} else static if(BMPType.mangleof == Bitmap16Bit.mangleof) {
238 							src[x] = tsrc[totalOffset];
239 						} else {
240 							*dest = *tsrc;
241 							dest++;
242 						}
243 					} else {
244 						static if(BMPType.mangleof == Bitmap8Bit.mangleof || BMPType.mangleof == Bitmap16Bit.mangleof ||
245 								BMPType.mangleof == Bitmap4Bit.mangleof){
246 							src[x] = 0;
247 						} else {
248 							(*dest).raw = 0;
249 						}
250 					}
251 					xy_in += _increment;
252 
253 				}
254 				/+else {
255 					for(short x; x < rasterX; x++){
256 						int[2] xy = transformFunctionInt([x,y], localTP, localTPO, sXsY);
257 						//printf("[%i,%i]",xy[0],xy[1]);
258 						MappingElement currentTile = tileByPixelWithoutTransform(xy[0],xy[1]);
259 						if(currentTile.tileID != 0xFFFF){
260 							const DisplayListItem d = displayList[currentTile.tileID];
261 							static if(BMPType.mangleof == Bitmap4Bit.mangleof){
262 								ubyte* tsrc = cast(ubyte*)d.pixelSrc;
263 							}else static if(BMPType.mangleof == Bitmap8Bit.mangleof){
264 								ubyte* tsrc = cast(ubyte*)d.pixelSrc;
265 							}else static if(BMPType.mangleof == Bitmap16Bit.mangleof){
266 								ushort* tsrc = cast(ushort*)d.pixelSrc;
267 							}else static if(BMPType.mangleof == Bitmap32Bit.mangleof){
268 								Color* tsrc = cast(Color*)d.pixelSrc;
269 							}
270 							xy[0] = xy[0] & (TileX - 1);
271 							xy[1] = xy[1] & (TileY - 1);
272 							const int totalOffset = xy[0] + xy[1] * TileX;
273 							static if(BMPType.mangleof == Bitmap4Bit.mangleof){
274 								src[x] = (totalOffset & 1 ? tsrc[totalOffset>>1]>>4 : tsrc[totalOffset>>1] & 0x0F) | currentTile.paletteSel<<_paletteOffset;
275 							}else static if(BMPType.mangleof == Bitmap8Bit.mangleof ){
276 								src[x] = tsrc[totalOffset] | currentTile.paletteSel<<_paletteOffset;
277 							}else static if(BMPType.mangleof == Bitmap16Bit.mangleof){
278 								src[x] = tsrc[totalOffset];
279 							}else{
280 								*dest = *tsrc;
281 								dest++;
282 							}
283 						}else{
284 							static if(BMPType.mangleof == Bitmap8Bit.mangleof || BMPType.mangleof == Bitmap16Bit.mangleof ||
285 									BMPType.mangleof == Bitmap4Bit.mangleof){
286 								src[x] = 0;
287 							}else{
288 								(*dest).raw = 0;
289 							}
290 						}
291 					}
292 				}+/
293 				static if(BMPType.mangleof == Bitmap4Bit.mangleof || BMPType.mangleof == Bitmap8Bit.mangleof || 
294 						BMPType.mangleof == Bitmap16Bit.mangleof){
295 					mainColorLookupFunction(src.ptr, cast(uint*)dest, cast(uint*)palette + paletteOffset, rasterX);
296 					dest += rasterX;
297 				}
298 			}
299 		}
300 		//render surface onto the raster
301 		void* p0 = workpad;
302 		Color* c = backbuffer.getPtr();
303 		for(int y; y < rasterY; y++){
304 			mainRenderingFunction(cast(uint*)c, cast(uint*)p0, rasterX, masterVal);
305 			c += rasterX;
306 			p0 += pitch;
307 		}
308 
309 	}
310 	///Returns which tile is at the given pixel
311 	public MappingElement tileByPixel(int x, int y) @nogc @safe pure nothrow const {
312 		//static if (USE_INTEL_INTRINSICS) {
313 		//	return MappingElement.init;
314 		//} else {
315 		int[2] xy = transformFunctionInt([cast(short)x,cast(short)y],transformPoints,tpOrigin,[cast(short)sX,cast(short)sY]);
316 		return tileByPixelWithoutTransform(xy[0],xy[1]);
317 		//}
318 		
319 	}
320 	///Returns which tile is at the given pixel.
321 	final protected MappingElement tileByPixelWithoutTransform(int x, int y) @nogc @safe pure nothrow const {
322 		x >>>= shiftX;
323 		y >>>= shiftY;
324 		final switch (warpMode) with (WarpMode) {
325 			case Off:
326 				if (x >= mX || y >= mY || x < 0 || y < 0) return MappingElement(0xFFFF);
327 				break;
328 			case MapRepeat:
329 				x &= _mapAmpersand[0];
330 				y &= _mapAmpersand[1];
331 				break;
332 			case TileRepeat:
333 				if (x >= mX || y >= mY || x < 0 || y < 0) return MappingElement(0x0000);
334 				break;
335 		}
336 		return mapping[x + y * mX];
337 	}
338 	///Returns two tiles to speed up rendering.
339 	final protected MappingElement[2] tileByPixelWithoutTransform(__m128i params) @nogc @safe pure nothrow const {
340 		//params >>>= mapShift;
341 		params[0] >>= shiftX;
342 		params[2] >>= shiftX;
343 		params[1] >>= shiftY;
344 		params[3] >>= shiftY;
345 		MappingElement[2] result;
346 		final switch (warpMode) with (WarpMode) {
347 			case Off:
348 				if (params[0] >= mX || params[1] >= mY || params[0] < 0 || params[1] < 0) result[0] = MappingElement(0xFFFF);
349 				else result[0] = mapping[params[0] + params[1] * mX];
350 				if (params[2] >= mX || params[3] >= mY || params[2] < 0 || params[3] < 0) result[1] = MappingElement(0xFFFF);
351 				else result[1] = mapping[params[2] + params[3] * mX];
352 				return result;
353 			case MapRepeat:
354 				params &= _mapAmpersand;
355 				result[0] = mapping[params[0] + params[1] * mX];
356 				result[1] = mapping[params[2] + params[3] * mX];
357 				return result;
358 			case TileRepeat:
359 				if (params[0] >= mX || params[1] >= mY || params[0] < 0 || params[1] < 0) result[0] = MappingElement(0x0000);
360 				else result[0] = mapping[params[0] + params[1] * mX];
361 				if (params[2] >= mX || params[3] >= mY || params[2] < 0 || params[3] < 0) result[1] = MappingElement(0x0000);
362 				else result[1] = mapping[params[2] + params[3] * mX];
363 				return result;
364 		}
365 	}
366 	/**
367 	 * Horizontal scaling. Greater than 256 means zooming in, less than 256 means zooming out.
368 	 */
369 	public @nogc @property pure @safe short A(){
370 		return transformPoints[0];
371 	}
372 	/**
373 	 * Horizontal shearing.
374 	 */
375 	public @nogc @property pure @safe short B(){
376 		return transformPoints[1];
377 	}
378 	/**
379 	 * Vertical shearing.
380 	 */
381 	public @nogc @property pure @safe short C(){
382 		return transformPoints[2];
383 	}
384 	/**
385 	 * Vertical scaling. Greater than 256 means zooming in, less than 256 means zooming out.
386 	 */
387 	public @nogc @property pure @safe short D(){
388 		return transformPoints[3];
389 	}
390 	/**
391 	 * Horizontal transformation offset.
392 	 */
393 	public @nogc @property pure @safe short x_0(){
394 		return tpOrigin[0];
395 	}
396 	/**
397 	 * Vertical transformation offset.
398 	 */
399 	public @nogc @property pure @safe short y_0(){
400 		return tpOrigin[1];
401 	}
402 	/**
403 	 * Horizontal scaling. Greater than 256 means zooming in, less than 256 means zooming out.
404 	 */
405 	public @nogc @property pure @safe short A(short newval){
406 		transformPoints[0] = newval;
407 		needsUpdate = true;
408 		return transformPoints[0];
409 	}
410 	/**
411 	 * Horizontal shearing.
412 	 */
413 	public @nogc @property pure @safe short B(short newval){
414 		transformPoints[1] = newval;
415 		needsUpdate = true;
416 		return transformPoints[1];
417 	}
418 	/**
419 	 * Vertical shearing.
420 	 */
421 	public @nogc @property pure @safe short C(short newval){
422 		transformPoints[2] = newval;
423 		needsUpdate = true;
424 		return transformPoints[2];
425 	}
426 	/**
427 	 * Vertical scaling. Greater than 256 means zooming in, less than 256 means zooming out.
428 	 */
429 	public @nogc @property pure @safe short D(short newval){
430 		transformPoints[3] = newval;
431 		needsUpdate = true;
432 		return transformPoints[3];
433 	}
434 	/**
435 	 * Horizontal transformation offset.
436 	 */
437 	public @nogc @property pure @safe short x_0(short newval){
438 		tpOrigin[0] = newval;
439 		//tpOrigin[2] = newval;
440 		needsUpdate = true;
441 		return tpOrigin[0];
442 	}
443 	/**
444 	 * Vertical transformation offset.
445 	 */
446 	public @nogc @property pure @safe short y_0(short newval){
447 		tpOrigin[1] = newval;
448 		//tpOrigin[3] = newval;
449 		needsUpdate = true;
450 		return tpOrigin[1];
451 	}
452 	override public void scroll(int x,int y) {
453 		super.scroll(x,y);
454 		needsUpdate = true;
455 	}
456 	override public void relScroll(int x,int y) {
457 		super.relScroll(x,y);
458 		needsUpdate = true;
459 	}
460 	public MappingElement[] getMapping() @nogc @safe pure nothrow {
461 		return mapping;
462 	}
463 	/+public MappingElement readMapping(int x, int y) @nogc @safe pure nothrow const {
464 		return mapping[(y * mX) + x];
465 	}+/
466 	public int getTileWidth() @nogc @safe pure nothrow const {
467 		return TileX;
468 	}
469 	public int getTileHeight() @nogc @safe pure nothrow const {
470 		return TileY;
471 	}
472 	public int getMX() @nogc @safe pure nothrow const {
473 		return mX;
474 	}
475 	public int getMY() @nogc @safe pure nothrow const {
476 		return mY;
477 	}
478 	public size_t getTX() @nogc @safe pure nothrow const {
479 		return totalX;
480 	}
481 	public size_t getTY() @nogc @safe pure nothrow const {
482 		return totalY;
483 	}
484 	/// Sets the warp mode.
485 	/// Returns the new warp mode that is being used.
486 	public WarpMode setWarpMode(WarpMode mode) @nogc @safe pure nothrow {
487 		return warpMode = mode;
488 	}
489 	/// Returns the currently used warp mode.
490 	public WarpMode getWarpMode() @nogc @safe pure nothrow const {
491 		return warpMode;
492 	}
493 	///Gets the the ID of the given element from the mapping. x , y : Position.
494 	public MappingElement readMapping(int x, int y) @nogc @safe pure nothrow const {
495 		if(!warpMode){
496 			if(x < 0 || y < 0 || x >= mX || y >= mY){
497 				return MappingElement(0xFFFF);
498 			}
499 		}else{
500 			x = x % mX;
501 			y = y % mY;
502 		}
503 		return mapping[x+(mX*y)];
504 	}
505 	///Writes to the map. x , y : Position. w : ID of the tile.
506 	@nogc public void writeMapping(int x, int y, MappingElement w) {
507 		mapping[x+(mX*y)]=w;
508 	}
509 	public void addTile(ABitmap tile, wchar id, ubyte paletteSh = 0) {
510 		if(typeid(tile) !is typeid(BMPType)){
511 			throw new TileFormatException("Incorrect type of tile!");
512 		}
513 		if(tile.width == TileX && tile.height == TileY){
514 			displayList[id] = DisplayListItem(id, cast(BMPType)tile, paletteSh);
515 		}else{
516 			throw new TileFormatException("Incorrect tile size!", __FILE__, __LINE__, null);
517 		}
518 	}
519 	///Returns a tile from the displaylist
520 	public ABitmap getTile(wchar id) {
521 		return displayList[id].tile;
522 	}
523 	///Removes the tile with the ID from the set.
524 	public void removeTile(wchar id){
525 		displayList.remove(id);
526 	}
527 	///Loads a mapping from an array. x , y : Sizes of the mapping. map : an array representing the elements of the map.
528 	///x*y=map.length
529 	public void loadMapping(int x, int y, MappingElement[] mapping) {
530 		if (!isPowerOf2(x) || !isPowerOf2(y)) 
531 			throw new MapFormatException("Map sizes are not power of two!");
532 		if (x * y != mapping.length) 
533 			throw new MapFormatException("Incorrect map sizes!");
534 		mX=x;
535 		mY=y;
536 		_mapAmpersand[0] = x - 1;
537 		_mapAmpersand[1] = y - 1;
538 		_mapAmpersand[2] = x - 1;
539 		_mapAmpersand[3] = y - 1;
540 		this.mapping = mapping;
541 		totalX=mX*TileX;
542 		totalY=mY*TileY;
543 	}
544 }