1 /*
2  * Copyright (C) 2015-2017, by Laszlo Szeremi under the Boost license.
3  *
4  * Pixel Perfect Engine, graphics.layers module
5  */
6 module PixelPerfectEngine.graphics.layers;
7 
8 public import PixelPerfectEngine.graphics.bitmap;
9 public import PixelPerfectEngine.graphics.common;
10 import PixelPerfectEngine.graphics.transformFunctions;
11 import PixelPerfectEngine.system.binarySearchTree;
12 import std.parallelism;
13 //import std.container.rbtree;
14 //import system.etc;
15 import PixelPerfectEngine.system.exc;
16 //import std.algorithm;
17 import derelict.sdl2.sdl;
18 import core.stdc.stdlib;
19 //import std.range;
20 import CPUblit.composing;
21 import CPUblit.colorlookup;
22 
23 version(LDC){
24 	import inteli.emmintrin;
25 }
26 
27 /*static immutable ushort[4] alphaMMXmul_const256 = [256,256,256,256];
28 static immutable ushort[4] alphaMMXmul_const1 = [1,1,1,1];
29 static immutable ushort[8] alphaSSEConst256 = [256,256,256,256,256,256,256,256];
30 static immutable ushort[8] alphaSSEConst1 = [1,1,1,1,1,1,1,1];
31 static immutable ubyte[16] alphaSSEMask = [255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0];
32 static immutable uint[4] SSEUQWmaxvalue = [0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF] ;*/
33 
34 //static immutable uint[2] alphaMMXmul_0 = [1,1];
35 
36 /**
37  * The basis of all layer classes, containing functions for rendering.
38  * TODO: Move rendering functions to an external library.
39  */
40 abstract class Layer {
41 	protected @nogc void function(uint* src, uint* dest, size_t length) mainRenderingFunction;		///Used to get around some readability issues. (void* src, void* dest, int length)
42 	protected @nogc void function(ushort* src, uint* dest, uint* palette, size_t length) mainColorLookupFunction;
43 	//protected @nogc void function(uint* src, int length) mainHorizontalMirroringFunction;
44 	protected @nogc void function(ubyte* src, uint* dest, uint* palette, size_t length) main8BitColorLookupFunction;
45 	protected @nogc void function(ubyte* src, uint* dest, uint* palette, size_t length, int offset) main4BitColorLookupFunction;
46 	protected LayerRenderingMode renderMode;
47 	
48 	// scrolling position
49 	protected int sX, sY, rasterX, rasterY;
50 	
51 	/// Sets the main rasterizer
52 	public void setRasterizer(int rX, int rY){
53 		//frameBuffer = frameBufferP;
54 		rasterX=rX;
55 		rasterY=rY;
56 		
57 	}
58 	///Sets the rendering mode
59 	@nogc public void setRenderingMode(LayerRenderingMode mode){
60 		renderMode = mode;
61 		switch(mode){
62 			case LayerRenderingMode.ALPHA_BLENDING:
63 				//mainRenderingFunction = &alphaBlend;
64 				mainRenderingFunction = &alphaBlend32bit;
65 				break;
66 			case LayerRenderingMode.BLITTER:
67 				mainRenderingFunction = &blitter32bit;
68 				break;
69 			default:
70 				mainRenderingFunction = &copy32bit;
71 		}
72 		mainColorLookupFunction = &colorLookup!(ushort,uint);
73 		//mainHorizontalMirroringFunction = &flipHorizontal;
74 		main8BitColorLookupFunction = &colorLookup!(ubyte,uint);
75 		main4BitColorLookupFunction = &colorLookup4Bit!uint;
76 	}
77 	///Absolute scrolling.
78 	@nogc @safe public void scroll(int x, int y){
79 		sX=x;
80 		sY=y;
81 	}
82 	///Relative scrolling. Positive values scrolls the layer left and up, negative values scrolls the layer down and right.
83 	@nogc @safe public void relScroll(int x, int y){
84 		sX=sX+x;
85 		sY=sY+y;
86 	}
87 	///Getter for the X scroll position.
88 	@nogc @safe public int getSX(){
89 		return sX;
90 	}
91 	///Getter for the Y scroll position.
92 	@nogc @safe public int getSY(){
93 		return sY;
94 	}
95 	/// Override this to enable output to the raster
96 	public abstract void updateRaster(void* workpad, int pitch, Color* palette, int[] threads);
97 	///Standard algorithm for horizontal mirroring
98 	@nogc protected void flipHorizontal(uint* src, int length){
99 		uint s;
100 		uint* dest = src + length;
101 		for(int i ; i < length ; i++){
102 			s = *src;
103 			*src = *dest;
104 			*dest = s;
105 			src++;
106 			dest--;
107 		}
108 	}
109 }
110 
111 /**
112  * Sets the rendering mode of the TileLayer.
113  * 
114  * COPY is the fastest, but overrides any kind of transparency keying. It directly writes into the framebuffer. Should only be used for certain applications, like bottom layers.
115  * BLITTER uses a custom BitBlT algorithm for the SSE2 instruction set. Automatically generates the copying mask depending on the alpha-value. Any alpha-value that's non-zero will cause a non-transparent pixel, and all zeros are completely transparent. Gradual transparency in not avaliable.
116  * ALPHA_BLENDING uses SSE2 for alpha blending. The slowest, but allows gradual transparencies.
117  */ 
118 public enum LayerRenderingMode{
119 	COPY,
120 	BLITTER,
121 	ALPHA_BLENDING
122 }
123 /**
124  * Tile interface, defines common functions.
125  */
126 public interface ITileLayer{
127 	public MappingElement[] getMapping();
128 	/// Reads the mapping element from the given area.
129 	@nogc public MappingElement readMapping(int x, int y);
130 	/// Writes the given element into the mapping at the given location.
131 	@nogc public void writeMapping(int x, int y, MappingElement w);
132 	/// Loads the mapping, primarily used for deserialization.
133 	public void loadMapping(int x, int y, MappingElement[] mapping);
134 	/// Removes the tile from the display list with the given ID.
135 	public void removeTile(wchar id);
136 	/// Returns the tile ID from the location by pixel.
137 	@nogc public MappingElement tileByPixel(int x, int y);
138 	/// Returns the width of the tiles.
139 	@nogc public int getTileWidth();
140 	/// Returns the height of the tiles.
141 	@nogc public int getTileHeight();
142 	/// Returns the width of the mapping.
143 	@nogc public int getMX();
144 	/// Returns the height of the mapping.
145 	@nogc public int getMY();
146 	/// Returns the total width of the tile layer.
147 	@nogc public int getTX();
148 	/// Returns the total height of the tile layer.
149 	@nogc public int getTY();
150 	/// Adds a tile.
151 	public void addTile(ABitmap tile, wchar id);
152 }
153 
154 public struct MappingElement{
155 	wchar tileID;				///Determines which tile is being used for the given instance
156 	BitmapAttrib attributes;	///General attributes
157 	ubyte reserved;				///Currently unused
158 	@nogc this(wchar tileID, BitmapAttrib attributes = BitmapAttrib(false, false)){
159 		this.tileID = tileID;
160 		this.attributes = attributes;
161 	}
162 }
163 
164 /**
165  * General purpose TileLayer with palette support, mainly for backgrounds.
166  * Use multiple of this class for paralax scrolling.
167  * Can use any kind of bitmaps thanks to code restructuring.
168  */
169 public class TileLayer : Layer, ITileLayer{
170 	protected struct DisplayListItem{
171 		ABitmap tile;			///reference counting only
172 		void* pixelDataPtr;		///points to the pixeldata
173 		Color* palettePtr;		///points to the palette if present
174 		wchar ID;				///ID, mainly as a padding to 32 bit alignment
175 		ubyte wordLength;		///to avoid calling the more costly classinfo
176 		ubyte reserved;
177 		this(wchar ID, ABitmap tile){
178 			palettePtr = tile.getPalettePtr();
179 			this.ID = ID;
180 			this.tile=tile;
181 			if(tile.classinfo == typeid(Bitmap4Bit)){
182 				wordLength = 4;
183 				pixelDataPtr = (cast(Bitmap4Bit)(tile)).getPtr;
184 			}else if(tile.classinfo == typeid(Bitmap8Bit)){
185 				wordLength = 8;
186 				pixelDataPtr = (cast(Bitmap8Bit)(tile)).getPtr;
187 			}else if(tile.classinfo == typeid(Bitmap16Bit)){
188 				wordLength = 16;
189 				pixelDataPtr = (cast(Bitmap16Bit)(tile)).getPtr;
190 			}else if(tile.classinfo == typeid(Bitmap32Bit)){
191 				wordLength = 32;
192 				pixelDataPtr = (cast(Bitmap32Bit)(tile)).getPtr;
193 			}
194 		}
195 	}
196 	protected int tileX, tileY, mX, mY;
197 	protected int totalX, totalY;
198 	protected MappingElement[] mapping;
199 	//private wchar[] mapping;
200 	//private BitmapAttrib[] tileAttributes;
201 	Color[] src;
202 	protected BinarySearchTree!(wchar, DisplayListItem) displayList;
203 	protected bool warpMode;
204 	///Constructor. tX , tY : Set the size of the tiles on the layer.
205 	this(int tX, int tY, LayerRenderingMode renderMode = LayerRenderingMode.ALPHA_BLENDING){
206 		tileX=tX;
207 		tileY=tY;
208 		setRenderingMode(renderMode);
209 		src.length = tileX;
210 	}
211 	/// Warpmode: if enabled, the layer will be turned into an "infinite" mode.
212 	public void setWarpMode(bool w){
213 		warpMode = w;
214 	}
215 	///Gets the the ID of the given element from the mapping. x , y : Position.
216 	@nogc public MappingElement readMapping(int x, int y){
217 		if(!warpMode){
218 			if(x < 0 || y < 0 || x >= mX || y >= mY){
219 				return MappingElement(0xFFFF);
220 			}
221 		}else{
222 			x = x % mX;
223 			y = y % mY;
224 		}
225 		return mapping[x+(mX*y)];
226 	}
227 	///Writes to the map. x , y : Position. w : ID of the tile.
228 	@nogc public void writeMapping(int x, int y, MappingElement w){
229 		mapping[x+(mX*y)]=w;
230 	}
231 	///Writes to the map. x , y : Position. w : ID of the tile.
232 	/*@nogc public void writeTileAttribute(int x, int y, BitmapAttrib ba){
233 		tileAttributes[x+(mX*y)]=ba;
234 	}*/
235 	///Loads a mapping from an array. x , y : Sizes of the mapping. map : an array representing the elements of the map.
236 	///x*y=map.length
237 	public void loadMapping(int x, int y, MappingElement[] mapping){
238 		mX=x;
239 		mY=y;
240 		this.mapping = mapping;
241 		totalX=mX*tileX;
242 		totalY=mY*tileY;
243 	}
244 	///Adds a tile to the tileSet. t : The tile. id : The ID in wchar to differentiate between different tiles.
245 	public void addTile(ABitmap tile, wchar id){
246 		if(tile.width==tileX && tile.height==tileY){
247 			displayList[id]=DisplayListItem(id, tile);
248 		}else{
249 			throw new TileFormatException("Incorrect tile size!", __FILE__, __LINE__, null);
250 		}
251 	}
252 	///Removes the tile with the ID from the set.
253 	public void removeTile(wchar id){
254 		displayList.remove(id);
255 	}
256 	///Returns which tile is at the given pixel
257 	@nogc public MappingElement tileByPixel(int x, int y){
258 		x /= tileX;
259 		y /= tileY;
260 		if(warpMode){
261 			x %= mX;
262 			y %= mY;
263 		}
264 		if(x >= mX || y >= mY || x < 0 || y < 0) return MappingElement(0xFFFF);
265 		return mapping[x + y*mX];
266 	}
267 	///Returns the tile's attribute at the given pixel
268 	/+@nogc public BitmapAttrib tileAttributeByPixel(int x, int y){
269 		x /= tileX;
270 		y /= tileY;
271 		if(warpMode){
272 			x %= totalX;
273 			y %= totalY;
274 		}
275 		if(x >= mX || y >= mY || x < 0 || y < 0) return BitmapAttrib(false,false);
276 		return tileAttributes[x + y*mX];
277 	}+/
278 	
279 	public @nogc override void updateRaster(void* workpad, int pitch, Color* palette, int[] threads){
280 		import core.stdc.stdio;
281 		int y = sY < 0 && !warpMode ? sY * -1 : 0;
282 		int sY0 = cast(int)(cast(uint)(sY) & 0b0111_1111_1111_1111_1111_1111_1111_1111);
283 		int offsetP = y*pitch;	// The offset of the line that is being written
284 		int offsetY = sY0 % tileY;		//Scroll offset upwards
285 		int offsetY0 = (sY + rasterY) % tileY;
286 		int offsetXA = sX%tileX;	// tile offset of the first column
287 		//for( ; y < rasterY ; y+=tileY){
288 		while(y < rasterY){
289 			//int offsetY = tileX * ((y + sY)%tileY);		
290 			int offsetYA = !y ? offsetY : 0;	//top offset for first tile, 0 otherwise
291 			int offsetYB = y + tileY > rasterY ? offsetY0 : tileY;	//bottom offset of last tile, equals tileY otherwise
292 			int x = sX < 0 && !warpMode ? sX * -1 : 0;
293 			int targetX = totalX - sX > rasterX && !warpMode ? rasterX : rasterX - (totalX - sX);
294 			void *p0 = (workpad + (x*Color.sizeof) + offsetP);
295 			while(x < targetX){
296 				MappingElement currentTile = tileByPixel(x+sX,y+sY);
297 				int tileXtarget = x + tileX < rasterX ? tileX : tileX - ((x + tileX) - rasterX) ;	// the length of the displayed tile
298 				int xp = (offsetXA != 0 && x == 0) ? offsetXA : 0;	// offset of the first column
299 				tileXtarget -= xp;	// length of the first tile
300 				if(currentTile.tileID != 0xFFFF){ // skip if tile is null
301 					//BitmapAttrib tileAttrib = tileAttributeByPixel(x+sX,y+sY);
302 					DisplayListItem d = displayList[currentTile.tileID];	// pointer to the current tile's pixeldata
303 					int tileYOffset = tileY;
304 					tileYOffset *= currentTile.attributes.vertMirror ? -1 : 1;	//vertical mirroring
305 					//int pitchOffset = pitch * threads.length;
306 					void* p1 = p0;
307 					switch(d.wordLength){
308 						case 4:
309 							ubyte* c = cast(ubyte*)d.pixelDataPtr;
310 							c += currentTile.attributes.vertMirror ? ((tileY - offsetYA - 1) * tileX)>>1 : (offsetYA * tileX)>>1;
311 							for(int y0 = offsetYA ; y0 < offsetYB ; y0++){
312 								main4BitColorLookupFunction(c, cast(uint*)src.ptr, cast(uint*)d.palettePtr, tileX, x & 1);
313 								if(currentTile.attributes.horizMirror){//Horizontal mirroring
314 									flipHorizontal(cast(uint*)src.ptr, tileX);
315 								}
316 								mainRenderingFunction(cast(uint*)src.ptr + xp, cast(uint*)p1, tileXtarget);
317 								c += tileYOffset>>>1;
318 								p1 += pitch;
319 							}
320 							break;
321 						case 8:
322 							ubyte* c = cast(ubyte*)d.pixelDataPtr;
323 							c += currentTile.attributes.vertMirror ? (tileY - offsetYA - 1) * tileX : offsetYA * tileX;
324 							for(int y0 = offsetYA ; y0 < offsetYB ; y0++){
325 								main8BitColorLookupFunction(c, cast(uint*)src.ptr, cast(uint*)d.palettePtr, tileX);
326 								if(currentTile.attributes.horizMirror){//Horizontal mirroring
327 									flipHorizontal(cast(uint*)src.ptr, tileX);
328 								}
329 								mainRenderingFunction(cast(uint*)src.ptr + xp, cast(uint*)p1, tileXtarget);
330 								c += tileYOffset;
331 								p1 += pitch;
332 							}
333 							break;
334 						case 16:
335 							ushort* c = cast(ushort*)d.pixelDataPtr;
336 							c += currentTile.attributes.vertMirror ? (tileY - offsetYA - 1) * tileX : offsetYA * tileX;
337 							for(int y0 = offsetYA ; y0 < offsetYB ; y0++){
338 								mainColorLookupFunction(c, cast(uint*)src.ptr, cast(uint*)palette, tileX);
339 								if(currentTile.attributes.horizMirror){//Horizontal mirroring
340 									flipHorizontal(cast(uint*)src.ptr, tileX);
341 								}
342 								mainRenderingFunction(cast(uint*)src.ptr + xp, cast(uint*)p1, tileXtarget);
343 								c += tileYOffset;
344 								p1 += pitch;
345 							}
346 							break;
347 						case 32:
348 							Color* c = cast(Color*)d.pixelDataPtr;								
349 							c += currentTile.attributes.vertMirror ? (tileY - offsetYA - 1) * tileX : offsetYA * tileX;
350 							for(int y0 = offsetYA ; y0 < offsetYB ; y0++){
351 								if(currentTile.attributes.horizMirror){//Horizontal mirroring
352 									copy32bit(cast(uint*)c, cast(uint*)src.ptr, tileX);
353 									flipHorizontal(cast(uint*)src.ptr, tileX);
354 									mainRenderingFunction(cast(uint*)src.ptr + xp, cast(uint*)p1, tileXtarget);
355 								}else{
356 									mainRenderingFunction(cast(uint*)(c + xp), cast(uint*)p1, tileXtarget);
357 								}
358 								c += tileYOffset;
359 								p1 += pitch;
360 							}
361 							break;
362 						default:
363 							break;
364 					}
365 					
366 				}
367 				p0 += tileXtarget * Color.sizeof;
368 				x+=tileXtarget;
369 			}
370 			offsetP	+= !y ? pitch * (tileY - offsetY) : pitch * tileY;
371 			/*if(y + tileY > y) y += tileY - offsetY0;
372 			else if(y) y += tileY;
373 			else y += (tileY - offsetY);*/
374 			y += !y ? (tileY - offsetY) : tileY;
375 		}
376 				
377 		
378 	}
379 	public MappingElement[] getMapping(){
380 		return mapping;
381 	}
382 	@nogc public int getTileWidth(){
383 		return tileX;
384 	}
385 	@nogc public int getTileHeight(){
386 		return tileY;
387 	}
388 	@nogc public int getMX(){
389 		return mX;
390 	}
391 	@nogc public int getMY(){
392 		return mY;
393 	}
394 	@nogc public int getTX(){
395 		return totalX;
396 	}
397 	@nogc public int getTY(){
398 		return totalY;
399 	}
400 }
401 /**
402  * Implements a modified TileLayer with transformability with capabilities similar to MODE7.
403  * <br/>
404  * Transform function:
405  * [x',y'] = ([A,B,C,D] * ([x,y] + [sX,sY] - [x_0,y_0])>>>8 + [x_0,y_0]
406  * <br/>
407  * All basic transform values are integer based, 256 equals with 1.0
408  * <br/>
409  * Restrictions compared to standard TileLayer:
410  * <ul>
411  * <li>Only a single type of bitmap can be used and 4 bit ones are excluded.</li>
412  * <li>8 bit tiles will share the same palette.</li>
413  * <li>Tiles must have any of the following sizes: 8, 16, 32, 64.</li>
414  * <li>Maximum layer size in pixels are restricted to 65536*65536</li>
415  * </ul>
416  * HDMA emulation supported through delegate hBlankInterrupt.
417  */
418 public class TransformableTileLayer(BMPType = Bitmap16Bit, int TileX = 8, int TileY = 8) : Layer, ITileLayer{
419 	protected struct DisplayListItem{
420 		void* pixelSrc;		///Used for quicker access to the Data
421 		wchar ID;			///ID, mainly used as a padding
422 		ushort reserved;	///Padding for 32 bit
423 		this(wchar ID, BMPType tile){
424 			this.ID = ID;
425 			pixelSrc = cast(void*)tile.getPtr();
426 		}
427 	}
428 	protected BinarySearchTree!(wchar, DisplayListItem) displayList;
429 	protected short[4] transformPoints;	/** Defines how the layer is being transformed */
430 	protected short[2] tpOrigin;
431 	protected Bitmap32Bit backbuffer;	///used to store current screen output
432 	static if(BMPType.mangleof == Bitmap8Bit.mangleof){
433 		protected ubyte[] src;
434 		protected Color* palettePtr;	///Shared palette
435 	}else static if(BMPType.mangleof == Bitmap16Bit.mangleof){
436 		protected ushort[] src;
437 	}else static if(BMPType.mangleof == Bitmap32Bit.mangleof){
438 		
439 	}else static assert("Template parameter " ~ BMPType.mangleof ~ " not supported by TransformableTileLayer!");
440 	protected bool needsUpdate;			///Set to true if backbuffer needs an update
441 	protected bool warpMode;			///Repeats the whole layer if set to true
442 	protected int mX, mY;				///"Inherited" from TileLayer
443 	static if(TileX == 8)
444 		protected immutable int shiftX = 3;
445 	else static if(TileX == 16)
446 		protected immutable int shiftX = 4;
447 	else static if(TileX == 32)
448 		protected immutable int shiftX = 5;
449 	else static if(TileX == 64)
450 		protected immutable int shiftX = 6;
451 	else static assert("Unsupported horizontal tile size!");
452 	static if(TileY == 8)
453 		protected immutable int shiftY = 3;
454 	else static if(TileY == 16)
455 		protected immutable int shiftY = 4;
456 	else static if(TileY == 32)
457 		protected immutable int shiftY = 5;
458 	else static if(TileY == 64)
459 		protected immutable int shiftY = 6;
460 	else static assert("Unsupported vertical tile size!");
461 	protected int totalX, totalY;		
462 	protected MappingElement[] mapping;
463 	version(LDC){
464 		protected int4 _tileAmpersand;
465 		protected static short8 _increment;
466 	}
467 
468 	public @nogc void delegate(ref short[4] localABCD, ref short[2] localsXsY, ref short[2] localx0y0, short y) hBlankInterrupt;
469 
470 	this(LayerRenderingMode renderMode = LayerRenderingMode.ALPHA_BLENDING){
471 		A = 256;
472 		B = 0;
473 		C = 0;
474 		D = 256;
475 		x_0 = 0;
476 		y_0 = 0;
477 		_tileAmpersand = [TileX - 1, TileY - 1, TileX - 1, TileY - 1];
478 		setRenderingMode(renderMode);
479 		needsUpdate = true;	
480 	}
481 	static this(){
482 		for(int i ; i < 8 ; i+=2)
483 			_increment[i] = 2;
484 	}
485 	override public void setRasterizer(int rX,int rY) {
486 		super.setRasterizer(rX,rY);
487 		backbuffer = new Bitmap32Bit(rX, rY);
488 		static if(BMPType.mangleof == Bitmap8Bit.mangleof || BMPType.mangleof == Bitmap16Bit.mangleof){
489 			src.length = rX;
490 		}
491 	}
492 	
493 	override public @nogc void updateRaster(void* workpad,int pitch,Color* palette,int[] threads) {
494 		//import core.stdc.stdio;
495 		if(needsUpdate){
496 			needsUpdate = false;
497 			//clear buffer
498 			//backbuffer.clear();
499 			Color* dest = backbuffer.getPtr();
500 			short[2] sXsY = [cast(short)sX,cast(short)sY];
501 			short[4] localTP = transformPoints;
502 			short[2] localTPO = tpOrigin;
503 			//write new data into it
504 			for(short y; y < rasterY; y++){
505 				if(hBlankInterrupt !is null){
506 					hBlankInterrupt(localTP, sXsY, localTPO, y);
507 				}
508 				version(DMD){
509 					for(short x; x < rasterX; x++){
510 						int[2] xy = transformFunctionInt([x,y], localTP, localTPO, sXsY);
511 						//printf("[%i,%i]",xy[0],xy[1]);
512 						MappingElement currentTile = tileByPixelWithoutTransform(xy[0],xy[1]);
513 						if(currentTile.tileID != 0xFFFF){
514 							DisplayListItem d = displayList[currentTile.tileID];
515 							static if(BMPType.mangleof == Bitmap8Bit.mangleof){
516 								ubyte* tsrc = cast(ubyte*)d.pixelSrc;
517 							}else static if(BMPType.mangleof == Bitmap16Bit.mangleof){
518 								ushort* tsrc = cast(ushort*)d.pixelSrc;
519 							}else static if(BMPType.mangleof == Bitmap32Bit.mangleof){
520 								Color* tsrc = cast(Color*)d.pixelSrc;
521 							}
522 							xy = [xy[0] & (TileX - 1), xy[1] & (TileY - 1)];
523 							tsrc += xy[0] + xy[1] * TileX;
524 							static if(BMPType.mangleof == Bitmap8Bit.mangleof || BMPType.mangleof == Bitmap16Bit.mangleof){
525 								src[x] = *tsrc;
526 							}else{
527 								*dest = *tsrc;
528 								dest++;
529 							}
530 						}else{
531 							static if(BMPType.mangleof == Bitmap8Bit.mangleof || BMPType.mangleof == Bitmap16Bit.mangleof){
532 								src[x] = 0;
533 							}
534 						}
535 					}
536 				}else version(LDC){
537 					/*short8 _sXsY = [sXsY[0],sXsY[1],sXsY[0],sXsY[1],sXsY[0],sXsY[1],sXsY[0],sXsY[1]], 
538 							_localTP = [localTP[0], localTP[1],localTP[2], localTP[3], localTP[0], localTP[1],localTP[2], localTP[3]], 
539 							_localTPO = [localTPO[0],localTPO[1],localTPO[0],localTPO[1],localTPO[0],localTPO[1],localTPO[0],localTPO[1]];
540 					int4 _localTPO_0 = [localTPO[0],localTPO[1],localTPO[0],localTPO[1]];*/
541 					short8 _sXsY, _localTP, _localTPO;
542 					for(int i; i < 8; i++){
543 						_sXsY[i] = sXsY[i & 1];
544 						_localTP[i] = localTP[i & 3];
545 						_localTPO[i] = localTPO[i & 1];
546 					}
547 					short8 xy_in;
548 					for(int i = 1; i < 8; i += 2){
549 						xy_in[i] = y;
550 					}
551 					xy_in[4] = 1;
552 					xy_in[6] = 1;
553 					int4 _localTPO_0;
554 					for(int i; i < 4; i++){
555 						_localTPO_0[i] = localTPO[i & 1];
556 					}
557 					for(short x; x < rasterX; x++){
558 						int4 xy = _mm_srai_epi32(_mm_madd_epi16(_localTP, xy_in + _sXsY - _localTPO),8) + _localTPO_0;
559 						MappingElement currentTile0 = tileByPixelWithoutTransform(xy[0],xy[1]), currentTile1 = tileByPixelWithoutTransform(xy[2],xy[3]);
560 						xy &= _tileAmpersand;
561 						if(currentTile0.tileID != 0xFFFF){
562 							DisplayListItem d = displayList[currentTile0.tileID];
563 							static if(BMPType.mangleof == Bitmap8Bit.mangleof){
564 								ubyte* tsrc = cast(ubyte*)d.pixelSrc;
565 							}else static if(BMPType.mangleof == Bitmap16Bit.mangleof){
566 								ushort* tsrc = cast(ushort*)d.pixelSrc;
567 							}else static if(BMPType.mangleof == Bitmap32Bit.mangleof){
568 								Color* tsrc = cast(Color*)d.pixelSrc;
569 							}
570 							
571 							tsrc += xy[0] + xy[1] * TileX;
572 							static if(BMPType.mangleof == Bitmap8Bit.mangleof || BMPType.mangleof == Bitmap16Bit.mangleof){
573 								src[x] = *tsrc;
574 							}else{
575 								*dest = *tsrc;
576 								dest++;
577 							}
578 						}else{
579 							static if(BMPType.mangleof == Bitmap8Bit.mangleof || BMPType.mangleof == Bitmap16Bit.mangleof){
580 								src[x] = 0;
581 							}else{
582 								(*dest).raw = 0;
583 							}
584 						}
585 						x++;
586 						if(currentTile1.tileID != 0xFFFF){
587 							DisplayListItem d = displayList[currentTile1.tileID];
588 							static if(BMPType.mangleof == Bitmap8Bit.mangleof){
589 								ubyte* tsrc = cast(ubyte*)d.pixelSrc;
590 							}else static if(BMPType.mangleof == Bitmap16Bit.mangleof){
591 								ushort* tsrc = cast(ushort*)d.pixelSrc;
592 							}else static if(BMPType.mangleof == Bitmap32Bit.mangleof){
593 								Color* tsrc = cast(Color*)d.pixelSrc;
594 							}
595 							//xy = [xy[2] & (TileX - 1), xy[3] & (TileY - 1)];
596 							tsrc += xy[2] + xy[3] * TileX;
597 							static if(BMPType.mangleof == Bitmap8Bit.mangleof || BMPType.mangleof == Bitmap16Bit.mangleof){
598 								src[x] = *tsrc;
599 							}else{
600 								*dest = *tsrc;
601 								dest++;
602 							}
603 						}else{
604 							static if(BMPType.mangleof == Bitmap8Bit.mangleof || BMPType.mangleof == Bitmap16Bit.mangleof){
605 								src[x] = 0;
606 							}else{
607 								(*dest).raw = 0;
608 							}
609 						}
610 						xy_in += _increment;
611 
612 					}
613 				}else static assert("Compiler not supported");
614 				static if(BMPType.mangleof == Bitmap8Bit.mangleof){
615 					main8BitColorLookupFunction(src.ptr, cast(uint*)dest, cast(uint*)palettePtr, rasterX);
616 					dest += rasterX;
617 				}else static if(BMPType.mangleof == Bitmap16Bit.mangleof){
618 					mainColorLookupFunction(src.ptr, cast(uint*)dest, cast(uint*)palette, rasterX);
619 					dest += rasterX;
620 				}
621 			}
622 		}
623 		//render surface onto the raster
624 		void* p0 = workpad;
625 		Color* c = backbuffer.getPtr();
626 		for(int y; y < rasterY; y++){
627 			mainRenderingFunction(cast(uint*)c,cast(uint*)p0,rasterX);
628 			c += rasterX;
629 			p0 += pitch;
630 		}
631 		
632 	}
633 	///Returns which tile is at the given pixel
634 	@nogc public MappingElement tileByPixel(int x, int y){
635 		int[2] xy = transformFunctionInt([cast(short)x,cast(short)y],transformPoints,tpOrigin,[cast(short)sX,cast(short)sY]);
636 		return tileByPixelWithoutTransform(xy[0],xy[1]);
637 	}
638 	///Returns which tile is at the given pixel
639 	@nogc protected MappingElement tileByPixelWithoutTransform(int x, int y){
640 		x >>>= shiftX;
641 		y >>>= shiftY;
642 		if(warpMode){
643 			x %= mX;
644 			y %= mY;
645 		}
646 		if(x >= mX || y >= mY || x < 0 || y < 0) return MappingElement(0xFFFF);
647 		return mapping[x + y*mX];
648 	}
649 		
650 	/**
651 	 * Horizontal scaling. Greater than 256 means zooming in, less than 256 means zooming out.
652 	 */
653 	public @nogc @property short A(){
654 		return transformPoints[0];
655 	}
656 	/**
657 	 * Horizontal shearing.
658 	 */
659 	public @nogc @property short B(){
660 		return transformPoints[1];
661 	}
662 	/**
663 	 * Vertical shearing.
664 	 */
665 	public @nogc @property short C(){
666 		return transformPoints[2];
667 	}
668 	/**
669 	 * Vertical scaling. Greater than 256 means zooming in, less than 256 means zooming out.
670 	 */
671 	public @nogc @property short D(){
672 		return transformPoints[3];
673 	}
674 	public @nogc @property short x_0(){
675 		return tpOrigin[0];
676 	}
677 	public @nogc @property short y_0(){
678 		return tpOrigin[1];
679 	}
680 	public @nogc @property short A(short newval){
681 		transformPoints[0] = newval;
682 		needsUpdate = true;
683 		return transformPoints[0];
684 	}
685 	public @nogc @property short B(short newval){
686 		transformPoints[1] = newval;
687 		needsUpdate = true;
688 		return transformPoints[1];
689 	}
690 	public @nogc @property short C(short newval){
691 		transformPoints[2] = newval;
692 		needsUpdate = true;
693 		return transformPoints[2];
694 	}
695 	public @nogc @property short D(short newval){
696 		transformPoints[3] = newval;
697 		needsUpdate = true;
698 		return transformPoints[3];
699 	}
700 	public @nogc @property short x_0(short newval){
701 		tpOrigin[0] = newval;
702 		//tpOrigin[2] = newval;
703 		needsUpdate = true;
704 		return tpOrigin[0];
705 	}
706 	public @nogc @property short y_0(short newval){
707 		tpOrigin[1] = newval;
708 		//tpOrigin[3] = newval;
709 		needsUpdate = true;
710 		return tpOrigin[1];
711 	}
712 	override public @safe @nogc void scroll(int x,int y) {
713 		super.scroll(x,y);
714 		needsUpdate = true;
715 	}
716 	override public @safe @nogc void relScroll(int x,int y) {
717 		super.relScroll(x,y);
718 		needsUpdate = true;
719 	}
720 	public MappingElement[] getMapping(){
721 		return mapping;
722 	}
723 	@nogc public int getTileWidth(){
724 		return TileX;
725 	}
726 	@nogc public int getTileHeight(){
727 		return TileY;
728 	}
729 	@nogc public int getMX(){
730 		return mX;
731 	}
732 	@nogc public int getMY(){
733 		return mY;
734 	}
735 	@nogc public int getTX(){
736 		return totalX;
737 	}
738 	@nogc public int getTY(){
739 		return totalY;
740 	}
741 	/// Warpmode: if enabled, the layer will be turned into an "infinite" mode.
742 	public void setWarpMode(bool w){
743 		warpMode = w;
744 	}
745 	///Gets the the ID of the given element from the mapping. x , y : Position.
746 	@nogc public MappingElement readMapping(int x, int y){
747 		if(!warpMode){
748 			if(x < 0 || y < 0 || x >= mX || y >= mY){
749 				return MappingElement(0xFFFF);
750 			}
751 		}else{
752 			x = x % mX;
753 			y = y % mY;
754 		}
755 		return mapping[x+(mX*y)];
756 	}
757 	///Writes to the map. x , y : Position. w : ID of the tile.
758 	@nogc public void writeMapping(int x, int y, MappingElement w){
759 		mapping[x+(mX*y)]=w;
760 	}
761 	public void addTile(ABitmap tile, wchar id){
762 		if(tile.classinfo != typeid(BMPType)){
763 			throw new TileFormatException("Incorrect type of tile!");
764 		}
765 		if(tile.width == TileX && tile.height == TileY){
766 			displayList[id]=DisplayListItem(id, cast(BMPType)tile);
767 		}else{
768 			throw new TileFormatException("Incorrect tile size!", __FILE__, __LINE__, null);
769 		}
770 	}
771 	///Removes the tile with the ID from the set.
772 	public void removeTile(wchar id){
773 		displayList.remove(id);
774 	}
775 	///Loads a mapping from an array. x , y : Sizes of the mapping. map : an array representing the elements of the map.
776 	///x*y=map.length
777 	public void loadMapping(int x, int y, MappingElement[] mapping){
778 		mX=x;
779 		mY=y;
780 		this.mapping = mapping;
781 		totalX=mX*TileX;
782 		totalY=mY*TileY;
783 	}
784 }
785 /**
786  *Used by the collision detectors
787  *DEPRECATED! Use the new system instead!
788  */
789 public interface ISpriteCollision{
790 	///Returns all sprite coordinates.
791 	public ref Coordinate[int] getCoordinates();
792 	///Returns all sprite attributes.
793 	public ref BitmapAttrib[int] getSpriteAttributes();
794 	public ref int[] getSpriteSorter();
795 	
796 }
797 /**
798  *General SpriteLayer interface.
799  */
800 public interface ISpriteLayer{
801 	///Removes the sprite with the given ID.
802 	public void removeSprite(int n);
803 	///Moves the sprite to the given location.
804 	public @nogc void moveSprite(int n, int x, int y);
805 	///Relatively moves the sprite by the given values.
806 	public @nogc void relMoveSprite(int n, int x, int y);
807 	///Gets the coordinate of the sprite.
808 	public Coordinate getSpriteCoordinate(int n);
809 	///Adds a sprite to the layer.
810 	public void addSprite(ABitmap s, int n, Coordinate c, BitmapAttrib attr);
811 	///Adds a sprite to the layer.
812 	public void addSprite(ABitmap s, int n, int x, int y, BitmapAttrib attr);
813 	///Replaces the sprite. If the new sprite has a different dimension, the old sprite's upper-left corner will be used.
814 	public void replaceSprite(ABitmap s, int n);
815 	///Replaces the sprite and moves to the given position.
816 	public void replaceSprite(ABitmap s, int n, int x, int y);
817 	///Replaces the sprite and moves to the given position.
818 	public void replaceSprite(ABitmap s, int n, Coordinate c);
819 	///Edits a sprite attribute.
820 	public void editSpriteAttribute(S, T)(int n, T value);
821 	///Replaces a sprite attribute.
822 	public void replaceSpriteAttribute(int n, BitmapAttrib attr);
823 }
824 /**
825  *Use it to call the collision detector
826  */
827 public interface SpriteMovementListener{
828 	///Called when a sprite is moved.
829 	void spriteMoved(int ID);
830 }
831 /**
832  * General-purpose sprite controller and renderer.
833  */
834 public class SpriteLayer : Layer, ISpriteLayer{
835 	/**
836 	 * Helps to determine the displaying properties and order of sprites.
837 	 */
838 	protected struct DisplayListItem{
839 		Coordinate position;		/// Stores the position relative to the origin point. Actual display position is determined by the scroll positions.
840 		Coordinate slice;			/// To compensate for the lack of scanline interrupt capabilities, this enables chopping off parts of a sprite.
841 		//ABitmap sprite;				/// Defines the sprite being displayed on the screen.
842 		void* pixelData;
843 		Color* palette;
844 		int priority;				/// Used for automatic sorting and identification, otherwise the DisplayList is pre-sorted for better performance.
845 		BitmapAttrib attributes;	/// Horizontal and vertical mirroring.
846 		ubyte wordLength;			/// Determines the word length of a sprite in a much quicker way than getting classinfo.
847 		this(Coordinate position, ABitmap sprite, int priority, BitmapAttrib attributes = BitmapAttrib(false, false)){
848 			this.position = position;
849 			//this.sprite = sprite;
850 			palette = sprite.getPalettePtr();
851 			this.priority = priority;
852 			this.attributes = attributes;
853 			slice = Coordinate(0,0,sprite.width,sprite.height);
854 			if(sprite.classinfo == typeid(Bitmap4Bit)){
855 				wordLength = 4;
856 				pixelData = (cast(Bitmap4Bit)(sprite)).getPtr;
857 			}else if(sprite.classinfo == typeid(Bitmap8Bit)){
858 				wordLength = 8;
859 				pixelData = (cast(Bitmap8Bit)(sprite)).getPtr;
860 			}else if(sprite.classinfo == typeid(Bitmap16Bit)){
861 				wordLength = 16;
862 				pixelData = (cast(Bitmap16Bit)(sprite)).getPtr;
863 			}else if(sprite.classinfo == typeid(Bitmap32Bit)){
864 				wordLength = 32;
865 				pixelData = (cast(Bitmap32Bit)(sprite)).getPtr;
866 			}
867 		}
868 		this(Coordinate position, Coordinate slice, ABitmap sprite, int priority, BitmapAttrib attributes = BitmapAttrib(false, false)){
869 			this.position = position;
870 			//this.sprite = sprite;
871 			palette = sprite.getPalettePtr();
872 			this.priority = priority;
873 			this.attributes = attributes;
874 			if(slice.top < 0)
875 				slice.top = 0;
876 			if(slice.left < 0)
877 				slice.left = 0;
878 			if(slice.right >= sprite.width)
879 				slice.right = sprite.width - 1;
880 			if(slice.bottom >= sprite.height)
881 				slice.bottom = sprite.height - 1;
882 			this.slice = slice;
883 			if(sprite.classinfo == typeid(Bitmap4Bit)){
884 				wordLength = 4;
885 				pixelData = (cast(Bitmap4Bit)(sprite)).getPtr;
886 				palette = sprite.getPalettePtr();
887 			}else if(sprite.classinfo == typeid(Bitmap8Bit)){
888 				wordLength = 8;
889 				pixelData = (cast(Bitmap8Bit)(sprite)).getPtr;
890 				palette = sprite.getPalettePtr();
891 			}else if(sprite.classinfo == typeid(Bitmap16Bit)){
892 				wordLength = 16;
893 				pixelData = (cast(Bitmap16Bit)(sprite)).getPtr;
894 			}else if(sprite.classinfo == typeid(Bitmap32Bit)){
895 				wordLength = 32;
896 				pixelData = (cast(Bitmap32Bit)(sprite)).getPtr;
897 			}
898 		}
899 		void replaceSprite(ABitmap sprite){
900 			//this.sprite = sprite;
901 			palette = sprite.getPalettePtr();
902 			if(sprite.classinfo == typeid(Bitmap4Bit)){
903 				wordLength = 4;
904 				pixelData = (cast(Bitmap4Bit)(sprite)).getPtr;
905 				palette = sprite.getPalettePtr();
906 			}else if(sprite.classinfo == typeid(Bitmap8Bit)){
907 				wordLength = 8;
908 				pixelData = (cast(Bitmap8Bit)(sprite)).getPtr;
909 				palette = sprite.getPalettePtr();
910 			}else if(sprite.classinfo == typeid(Bitmap16Bit)){
911 				wordLength = 16;
912 				pixelData = (cast(Bitmap16Bit)(sprite)).getPtr;
913 			}else if(sprite.classinfo == typeid(Bitmap32Bit)){
914 				wordLength = 32;
915 				pixelData = (cast(Bitmap32Bit)(sprite)).getPtr;
916 			}
917 		}
918 		@nogc int opCmp(in DisplayListItem d){
919 			return priority - d.priority;
920 		}
921 		@nogc bool opEquals(in DisplayListItem d){
922 			return priority == d.priority;
923 		}
924 	}
925 	protected DisplayListItem[] displayList;	///Stores the display data with the 
926 	//private ABitmap[int] spriteSet;			///Stores the sprites.
927 	//private Coordinate[int] coordinates;		///Stores the coordinates.
928 	//private BitmapAttrib[int] spriteAttributes;	///Stores spriteattributes. (layer priority, mirroring, etc.)
929 	//private int[] spriteSorter;					///Stores the priorities.
930 	//public SpriteMovementListener[int] collisionDetector;	Deprecated, different collision detection will be used in the future.
931 	Color[] src;
932 	//size_t[8] prevSize;
933 	
934 	public this(LayerRenderingMode renderMode = LayerRenderingMode.ALPHA_BLENDING){
935 		setRenderingMode(renderMode);
936 		//src[0].length = 1024;
937 	}
938 	/+~this(){
939 		foreach(p; src){
940 			if(p)
941 				free(p);
942 		}
943 	}+/
944 	override public void setRasterizer(int rX,int rY) {
945 		super.setRasterizer(rX,rY);
946 		/+for(int i; i < src.length; i++){
947 			src[i].length=rY;
948 		}+/
949 		src.length = rY;
950 	}
951 	
952 	public void addSprite(ABitmap s, int n, Coordinate c, BitmapAttrib attr){
953 		import std.algorithm.sorting;
954 		import std.algorithm.searching;
955 		DisplayListItem d = DisplayListItem(c, s, n, attr);
956 		if(canFind(displayList, d)){
957 			throw new SpritePriorityException("Sprite number already exists!");
958 		}else{
959 			displayList ~= d;
960 			displayList.sort!"a > b"();
961 		}
962 	}
963 	
964 	public void addSprite(ABitmap s, int n, int x, int y, BitmapAttrib attr){
965 		import std.algorithm.sorting;
966 		import std.algorithm.searching;
967 		Coordinate c = Coordinate(x,y,x+s.width,y+s.height);
968 		DisplayListItem d = DisplayListItem(c, s, n, attr);
969 		if(canFind(displayList, d)){
970 			throw new SpritePriorityException("Sprite number already exists!");
971 		}else{
972 			displayList ~= d;
973 			displayList.sort!"a > b"();
974 		}
975 	}
976 	public void editSpriteAttribute(S, T)(int n, T value){
977 		for(int i; i < displayList.length ; i++){
978 			if(displayList[i].priority == n){
979 				displayList[i].S = value;
980 				return;
981 			}
982 		}
983 	}
984 	public void replaceSpriteAttribute(int n, BitmapAttrib attr){
985 		for(int i; i < displayList.length ; i++){
986 			if(displayList[i].priority == n){
987 				displayList[i].attributes = attr;
988 				return;
989 			}
990 		}
991 	}
992 	public void replaceSprite(ABitmap s, int n){
993 		for(int i; i < displayList.length ; i++){
994 			if(displayList[i].priority == n){
995 				displayList[i].replaceSprite(s);
996 				return;
997 			}
998 		}
999 	}
1000 
1001 	public void replaceSprite(ABitmap s, int n, int x, int y){
1002 		
1003 	}
1004 
1005 	public void replaceSprite(ABitmap s, int n, Coordinate c){
1006 		
1007 	}
1008 	
1009 	/*public ushort getTransparencyIndex(){
1010 		return transparencyIndex;
1011 	}*/
1012 	
1013 	public void removeSprite(int n){
1014 		DisplayListItem[] ndl;
1015 		ndl.reserve(displayList.length);
1016 		for(int i; i < displayList.length ; i++){
1017 			if(displayList[i].priority != n){
1018 				ndl ~= displayList[i];
1019 			}
1020 		}
1021 		displayList = ndl;
1022 	}
1023 	public @nogc void moveSprite(int n, int x, int y){
1024 		for(int i; i < displayList.length ; i++){
1025 			if(displayList[i].priority == n){
1026 				displayList[i].position.move(x,y);
1027 				return;
1028 			}
1029 		}
1030 	}
1031 	public @nogc void relMoveSprite(int n, int x, int y){
1032 		for(int i; i < displayList.length ; i++){
1033 			if(displayList[i].priority == n){
1034 				displayList[i].position.relMove(x,y);
1035 				return;
1036 			}
1037 		}
1038 	}
1039 	
1040 	public @nogc Coordinate getSpriteCoordinate(int n){
1041 		for(int i; i < displayList.length ; i++){
1042 			if(displayList[i].priority == n){
1043 				return displayList[i].position;
1044 			}
1045 		}
1046 		return Coordinate(0,0,0,0);
1047 	}
1048 
1049 	public override @nogc void updateRaster(void* workpad, int pitch, Color* palette, int[] threads){
1050 		foreach(i ; displayList){
1051 			if((i.position.right > sX && i.position.bottom > sY) && (i.position.left < sX + rasterX && i.position.top < sY + rasterY)){
1052 				int offsetXA = sX > i.position.left ? sX - i.position.left : 0;//Left hand side offset
1053 				int offsetXB = sX + rasterX < i.position.right ? i.position.right - rasterX : 0; //Right hand side offset
1054 				int offsetYA = sY > i.position.top ? sY - i.position.top : 0;
1055 				int offsetYB = sY + rasterY < i.position.bottom ? i.position.bottom - rasterY : 0;
1056 				int sizeX = i.position.width(), offsetX = i.position.left - sX;
1057 				int length = sizeX - offsetXA - offsetXB, lfour = length * 4;
1058 				int offsetY = sY < i.position.top ? (i.position.top-sY)*pitch : 0;
1059 				//int pitchOffset = pitch * threads.length;
1060 				//int sizeXOffset = sizeX * threads.length;
1061 				//sizeXOffset *= i.attributes.vertMirror ? -1 : 1;
1062 				int sizeXOffset = sizeX * (i.attributes.vertMirror ? -1 : 1);
1063 				switch(i.wordLength){
1064 					case 4:
1065 						//Bitmap4Bit bmp = cast(Bitmap4Bit)i.sprite;
1066 						//ubyte* p0 = bmp.getPtr();
1067 						ubyte* p0 = cast(ubyte*)i.pixelData;
1068 						if(i.attributes.vertMirror)
1069 							p0 += (sizeX * (i.position.height - offsetYB))>>1;
1070 						else
1071 							p0 += (sizeX * offsetYA)>>1;
1072 						if(!i.attributes.horizMirror)
1073 							p0 += offsetXA>>1;
1074 						else
1075 							p0 += offsetXB>>1;
1076 						//foreach(int threadOffset; threads.parallel){
1077 						//ubyte* p1 = p0 + threadOffset * sizeX;
1078 						//void* dest = workpad + (offsetX + offsetXA)*4 + offsetY + threadOffset * pitch;
1079 						void* dest = workpad + (offsetX + offsetXA)*4 + offsetY;
1080 						//for(int y = offsetYA + threadOffset ; y < i.position.height - offsetYB ; y+=threads.length){
1081 						for(int y = offsetYA ; y < i.slice.height - offsetYB ; y++){	
1082 							//main4BitColorLookupFunction(p1, cast(uint*)src[threadOffset], cast(uint*)i.sprite.getPalettePtr(), length, offsetXA);
1083 							main4BitColorLookupFunction(p0, cast(uint*)src.ptr, cast(uint*)i.palette, length, offsetXA);
1084 							if(i.attributes.horizMirror){//Flips lines if needed
1085 								flipHorizontal(cast(uint*)src.ptr, length);
1086 							}
1087 							mainRenderingFunction(cast(uint*)src.ptr, cast(uint*)dest, length);
1088 							//dest += pitchOffset;
1089 							dest += pitch;
1090 							//p1 += sizeXOffset;
1091 							p0 += sizeXOffset;
1092 						}
1093 						//}
1094 						break;
1095 					case 8:
1096 						//Bitmap8Bit bmp = cast(Bitmap8Bit)i.sprite;
1097 						//ubyte* p0 = bmp.getPtr();
1098 						ubyte* p0 = cast(ubyte*)i.pixelData;
1099 						if(i.attributes.vertMirror)
1100 							p0 += sizeX * (i.position.height - offsetYB);
1101 						else
1102 						p0 += sizeX * offsetYA;
1103 						if(!i.attributes.horizMirror)
1104 							p0 += offsetXA;
1105 						else
1106 							p0 += offsetXB;
1107 						//foreach(int threadOffset; threads.parallel){
1108 						//ubyte* p1 = p0 + threadOffset * sizeX;
1109 						//void* dest = workpad + (offsetX + offsetXA)*4 + offsetY + threadOffset * pitch;
1110 						void* dest = workpad + (offsetX + offsetXA)*4 + offsetY;
1111 						//for(int y = offsetYA + threadOffset ; y < i.position.height - offsetYB ; y+=threads.length){	
1112 						for(int y = offsetYA ; y < i.slice.height - offsetYB ; y++){	
1113 							//main8BitColorLookupFunction(p1, cast(uint*)src[threadOffset], cast(uint*)i.sprite.getPalettePtr(), length);
1114 							main8BitColorLookupFunction(p0, cast(uint*)src.ptr, cast(uint*)i.palette, length);
1115 							if(i.attributes.horizMirror){//Flips lines if needed
1116 								flipHorizontal(cast(uint*)src.ptr, length);
1117 							}
1118 							mainRenderingFunction(cast(uint*)src.ptr, cast(uint*)dest, length);
1119 							//dest += pitchOffset;
1120 							dest += pitch;
1121 							//p1 += sizeXOffset;
1122 							p0 += sizeXOffset;
1123 						}
1124 						//}
1125 						break;
1126 					case 16:
1127 						//Bitmap16Bit bmp = cast(Bitmap16Bit)i.sprite;
1128 						//ushort* p0 = bmp.getPtr();
1129 						ushort* p0 = cast(ushort*)i.pixelData;
1130 						if(i.attributes.vertMirror)
1131 							p0 += sizeX * (i.position.height - offsetYB);
1132 						else
1133 							p0 += sizeX * offsetYA;
1134 						if(!i.attributes.horizMirror)
1135 							p0 += offsetXA;
1136 						else
1137 							p0 += offsetXB;
1138 						//foreach(int threadOffset; threads.parallel){
1139 						//ushort* p1 = p0 + threadOffset * sizeX;
1140 						//void* dest = workpad + (offsetX + offsetXA)*4 + offsetY + threadOffset * pitch;
1141 						void* dest = workpad + (offsetX + offsetXA)*4 + offsetY;
1142 						//for(int y = offsetYA + threadOffset ; y < i.position.height - offsetYB ; y+=threads.length){
1143 						for(int y = offsetYA ; y < i.slice.height - offsetYB ; y++){
1144 							//mainColorLookupFunction(p1, cast(uint*)src[threadOffset], cast(uint*)palette, length);
1145 							//mainColorLookupFunction(p1, cast(uint*)src[threadOffset].ptr, cast(uint*)palette, length);
1146 							mainColorLookupFunction(p0, cast(uint*)src.ptr, cast(uint*)palette, length);
1147 							if(i.attributes.horizMirror){//Flips lines if needed
1148 								flipHorizontal(cast(uint*)src.ptr, length);
1149 							}
1150 							mainRenderingFunction(cast(uint*)src.ptr, cast(uint*)dest, length);
1151 							//dest += pitchOffset;
1152 							dest += pitch;
1153 							//p1 += sizeXOffset;
1154 							p0 += sizeXOffset;
1155 						}
1156 						//}
1157 						break;
1158 					case 32:
1159 						//Bitmap32Bit bmp = cast(Bitmap32Bit)i.sprite;
1160 						//Color* p0 = bmp.getPtr();
1161 						uint* p0 = cast(uint*)i.pixelData;
1162 						if(i.attributes.vertMirror)
1163 							p0 += sizeX * (i.position.height - offsetYB);
1164 						else
1165 							p0 += sizeX * offsetYA;
1166 						if(!i.attributes.horizMirror)
1167 							p0 += offsetXA;
1168 						else
1169 							p0 += offsetXB;
1170 						//foreach(int threadOffset; threads.parallel){
1171 							
1172 						//uint* p1 = p0 + threadOffset * sizeX;
1173 						//void* dest = workpad + (offsetX + offsetXA)*4 + offsetY + threadOffset * pitch;
1174 						void* dest = workpad + (offsetX + offsetXA)*4 + offsetY;
1175 						//for(int y = offsetYA + threadOffset ; y < i.position.height - offsetYB ; y+=threads.length){		
1176 						for(int y = offsetYA ; y < i.slice.height - offsetYB ; y++){
1177 							if(i.attributes.horizMirror){//Flips lines if needed
1178 								//copy32bit(p1, cast(uint*)(src[threadOffset].ptr), length);
1179 								copy32bit(p0, cast(uint*)(src.ptr), length);
1180 								flipHorizontal(cast(uint*)(src.ptr), length);
1181 								mainRenderingFunction(cast(uint*)(src.ptr), cast(uint*)dest, length);
1182 							}else{
1183 								mainRenderingFunction(p0, cast(uint*)dest, length);
1184 							}
1185 							//dest += pitchOffset;
1186 							dest += pitch;
1187 							//p1 += sizeXOffset;
1188 							p0 += sizeXOffset;
1189 						}
1190 						//}
1191 						break;
1192 					default:
1193 						break;
1194 				}
1195 				
1196 			}
1197 		}
1198 		//foreach(int threadOffset; threads.parallel)
1199 			//free(src[threadOffset]);
1200 	}
1201 
1202 }
1203 /**
1204  * Puts various effects on the framebuffer (XOR blitter, etc). 
1205  */
1206 public class EffectLayer : Layer{
1207 	/**
1208 	 * Stores various commands for effects
1209 	 */
1210 	public class EffectLayerCommand{
1211 		public CommandType command;
1212 		public Coordinate[] coordinates;
1213 		public Color[] colors;
1214 		public ushort[] indexedColors;
1215 		public int[] values;
1216 		public this(CommandType command, Coordinate[] coordinates, Color[] colors, int[] values = null){
1217 			this.command = command;
1218 			this.coordinates = coordinates;
1219 			this.indexedColors = null;
1220 			this.colors = colors;
1221 			this.values = values;
1222 		}
1223 		public this(CommandType command, Coordinate[] coordinates, ushort[] indexedColors, int[] values = null){
1224 			this.command = command;
1225 			this.coordinates = coordinates;
1226 			this.indexedColors = indexedColors;
1227 			this.colors = null;
1228 			this.values = values;
1229 		}
1230 	}
1231 	public enum CommandType : ubyte{
1232 		/// Does nothing, placeholder command.
1233 		NONE			=	0,	
1234 		/** 
1235 		 * Does a XOR blitter line. Parameters: 
1236 		 * coordinate[0]: Begins the line from the top-left corner until the right corner. Bottom value is discarded.
1237 		 * color[0]: The 32 bit colorvector.
1238 		 */
1239 		XORBLITTERLINE	=	1,	
1240 		/** 
1241 		 * Does a XOR blitter box. Parameters: 
1242 		 * coordinate[0]: The coordinates where the box should be drawn.
1243 		 * color[0]: The 32 bit colorvector.
1244 		 */
1245 		XORBLITTERBOX	=	2,
1246 		/**
1247 		 * Offsets a line by a given value. Parameters:
1248 		 * coordinate[0]: Begins the line from the top-left corner until the right corner. Bottom value is discarded.
1249 		 * value[0]: The amount which the line will be offsetted.
1250 		 *
1251 		 * NOTE: Be careful with this operation, if the algorithm has to write out from the screen, it'll cause a MemoryAccessViolationError.
1252 		 * Overscanning will enable to write outside of it as well as offsetting otherwise off-screen elements onto the screen.
1253 		 */
1254 		LINEOFFSET		=	3
1255 	}
1256 	private EffectLayerCommand[int] commandList;
1257 	private int[] commandListPriorities;
1258 	public this(){
1259 		
1260 	}
1261 	/**
1262 	 * Adds a new command with the specified values.
1263 	 */
1264 	public void addCommand(int priority, EffectLayerCommand command){
1265 		import std.algorithm.sorting;
1266 		commandList[priority] = command;
1267 		commandListPriorities ~= priority;
1268 		commandListPriorities.sort();
1269 	}
1270 	/**
1271 	 * Removes a command at the specified priority.
1272 	 */
1273 	public void removeCommand(int priority){
1274 		commandList.remove(priority);
1275 		int[] newCommandListPriorities;
1276 		for(int i ; i < commandListPriorities.length ; i++){
1277 			if(commandListPriorities[i] != priority){
1278 				newCommandListPriorities ~= commandListPriorities[i];
1279 			}
1280 		}
1281 		commandListPriorities = newCommandListPriorities;
1282 	}
1283 
1284 	override public void updateRaster(void* workpad,int pitch,Color* palette,int[] threads) {
1285 		/*foreach(int i; commandListPriorities){
1286 			switch(commandList[i].command){
1287 				case CommandType.XORBLITTERLINE:
1288 					int offset = (commandList[i].coordinates[0].top * pitch) + commandList[i].coordinates[0].left;
1289 					if(commandList[i].indexedColors is null){
1290 						xorBlitter(workpad + offset,commandList[i].colors[0],commandList[i].coordinates[0].width());
1291 					}else{
1292 						xorBlitter(workpad + offset,palette[commandList[i].indexedColors[0]],commandList[i].coordinates[0].width());
1293 					}
1294 					break;
1295 				case CommandType.XORBLITTERBOX:
1296 					int offset = (commandList[i].coordinates[0].top * pitch) + commandList[i].coordinates[0].left;
1297 					if(commandList[i].indexedColors is null){
1298 						for(int y = commandList[i].coordinates[0].top; y < commandList[i].coordinates[0].bottom; y++){
1299 							xorBlitter(workpad + offset,commandList[i].colors[0],commandList[i].coordinates[0].width());
1300 							offset += pitch;
1301 						}
1302 					}else{
1303 						for(int y = commandList[i].coordinates[0].top; y < commandList[i].coordinates[0].bottom; y++){
1304 							xorBlitter(workpad + offset,commandList[i].colors[0],commandList[i].coordinates[0].width());
1305 							offset += pitch;
1306 						}
1307 					}
1308 					break;
1309 				case CommandType.LINEOFFSET:
1310 					int offset = (commandList[i].coordinates[0].top * pitch) + commandList[i].coordinates[0].left;
1311 					copyRegion(workpad + offset, workpad + offset + commandList[i].values[0], commandList[i].coordinates[0].width());
1312 					break;
1313 				default: 
1314 					break;
1315 			}
1316 		}*/
1317 	}
1318 	
1319 }