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 = ©32bit; 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 }