1 /* 2 * Copyright (C) 2015-2017, by Laszlo Szeremi under the Boost license. 3 * 4 * Pixel Perfect Engine, graphics.draw module 5 */ 6 7 module PixelPerfectEngine.graphics.draw; 8 9 import std.stdio; 10 import std.math; 11 import std.conv; 12 13 import PixelPerfectEngine.graphics.bitmap; 14 import CPUblit.composing; 15 import CPUblit.draw; 16 public import PixelPerfectEngine.graphics.fontsets; 17 public import PixelPerfectEngine.graphics.common; 18 //import system.etc; 19 /** 20 * Draws into a 16bit bitmap. 21 * TODO: Make it usable on 8 and 32bit bitmaps too. 22 */ 23 public class BitmapDrawer{ 24 public Bitmap16Bit output; 25 public ushort brushTransparency; 26 static const ushort[8] transparencytester8 = [0,0,0,0,0,0,0,0]; 27 static const ushort[4] transparencytester4 = [0,0,0,0]; 28 ///Creates the object alongside its output. 29 public this(int x, int y){ 30 output = new Bitmap16Bit(x, y); 31 32 } 33 ///Draws a single line. 34 public void drawLine(int xa, int xb, int ya, int yb, ushort color){ 35 if(xb < xa){ 36 int k = xa; 37 xa = xb; 38 xb = k; 39 } 40 if(yb < ya){ 41 int k = ya; 42 ya = yb; 43 yb = k; 44 } 45 int dx = xb - xa; 46 int dy = yb - ya; 47 if(!dx || !dy){ 48 if(!dy){ 49 for(int x = xa; x <= xb; x++){ 50 output.writePixel(x,ya,color); 51 } 52 }else{ 53 for(int y = ya; y <= yb; y++){ 54 output.writePixel(xa,y,color); 55 } 56 } 57 }else if(dx>=dy){ 58 int D = 2*dy - dx; 59 int y = ya; 60 for(int x = xa; x <= xb; x++){ 61 output.writePixel(x,y,color); 62 if(D > 0){ 63 y += 1; 64 D -= 2*dx; 65 } 66 D += 2*dx; 67 } 68 }else{ 69 int D = 2*dx - dy; 70 int x = xa; 71 for(int y = ya; y <= yb; y++){ 72 output.writePixel(x,y,color); 73 if(D > 0){ 74 x += 1; 75 D -= 2*dy; 76 } 77 D += 2*dy; 78 } 79 } 80 } 81 ///Draws a line using a brush. 82 public void drawLine(int xa, int xb, int ya, int yb, Bitmap16Bit brush){ 83 if(xa == xb){ 84 85 if(ya < yb){ 86 for(int j ; j < (yb - ya) ; j++){ 87 insertBitmap(xa, ya + j, brush); 88 } 89 }else{ 90 for(int j ; j > (yb - ya) ; j--){ 91 insertBitmap(xa, ya + j, brush); 92 } 93 } 94 xa++; 95 xb++; 96 97 }else if(ya == yb){ 98 99 if(xa > xb){ 100 for(int j ; j < (xa - xb) ; j++){ 101 insertBitmap(xa + j, ya, brush); 102 } 103 }else{ 104 for(int j ; j > (xa - xb) ; j--){ 105 insertBitmap(xa + j, ya, brush); 106 } 107 } 108 ya++; 109 yb++; 110 111 }else{ 112 if(xa < xb){ 113 if(ya < yb){ 114 int xy = to!int(sqrt(to!double((xb - xa) * (xb - xa)) + ((yb - ya) * (yb - ya)))); 115 116 for(int j ; j < xb - xa ; j++){ 117 int y = to!int(sqrt(to!double(xy * xy) - ((xa + j)*(xa + j)))); 118 insertBitmap(xa + j, ya + y, brush); 119 } 120 121 }else{ 122 int xy = to!int(sqrt(to!double((xb - xa) * (xb - xa)) + ((ya - yb) * (ya - yb)))); 123 124 for(int j ; j < xb - xa ; j++){ 125 int y = to!int(sqrt(to!double(xy * xy) - ((xa + j)*(xa + j)))); 126 insertBitmap(xa + j, ya - y, brush); 127 } 128 129 } 130 }else{ 131 if(ya < yb){ 132 int xy = to!int(sqrt(to!double((xa - xb) * (xa - xb)) + ((yb - ya) * (yb - ya)))); 133 134 for(int j ; j > xb - xa ; j--){ 135 int y = to!int(sqrt(to!double(xy * xy) - ((xa + j)*(xa + j)))); 136 insertBitmap(xa + j, ya + y, brush); 137 } 138 139 }else{ 140 int xy = to!int(sqrt(to!double((xa - xb) * (xa - xb)) + ((ya - yb) * (ya - yb)))); 141 142 for(int j ; j > xb - xa ; j--){ 143 int y = to!int(sqrt(to!double(xy * xy) - ((xa + j)*(xa + j)))); 144 insertBitmap(xa + j, ya - y, brush); 145 } 146 147 } 148 } 149 } 150 } 151 ///Inserts a bitmap using blitter. 152 public void insertBitmap(int x, int y, Bitmap16Bit bitmap){ 153 ushort* psrc = bitmap.getPtr, pdest = output.getPtr; 154 pdest += x + output.width * y; 155 int length = bitmap.width; 156 for(int iy ; iy < bitmap.height ; iy++){ 157 blitter16bit(psrc,pdest,length); 158 psrc += length; 159 pdest += output.width; 160 } 161 } 162 ///Inserts a midsection of the bitmap defined by slice 163 public void insertBitmapSlice(int x, int y, Bitmap16Bit bitmap, Coordinate slice){ 164 ushort* psrc = bitmap.getPtr, pdest = output.getPtr; 165 pdest += x + output.width * y; 166 int bmpWidth = bitmap.width; 167 psrc += slice.left + bmpWidth * slice.top; 168 int length = slice.width; 169 for(int iy ; iy < slice.height ; iy++){ 170 blitter16bit(psrc,pdest,length); 171 psrc += bmpWidth; 172 pdest += output.width; 173 } 174 } 175 ///Draws a rectangle. 176 public void drawRectangle(int xa, int xb, int ya, int yb, ushort color){ 177 drawLine(xa, xa, ya, yb, color); 178 drawLine(xb, xb, ya, yb, color); 179 drawLine(xa, xb, ya, ya, color); 180 drawLine(xa, xb, yb, yb, color); 181 } 182 183 public void drawRectangle(int xa, int xb, int ya, int yb, Bitmap16Bit brush){ 184 xa = xa + brush.width; 185 ya = ya + brush.height; 186 xb = xb - brush.width; 187 yb = yb - brush.height; 188 drawLine(xa, xa, ya, yb, brush); 189 drawLine(xb, xb, ya, yb, brush); 190 drawLine(xa, xb, ya, ya, brush); 191 drawLine(xa, xb, yb, yb, brush); 192 } 193 ///Draws a filled rectangle. 194 public void drawFilledRectangle(int xa, int xb, int ya, int yb, ushort color){ 195 //writeln(xa); writeln(ya); writeln(xb); writeln(yb); 196 197 ushort[8] colorvect = [color, color, color, color, color, color, color, color]; 198 ushort* p = output.getPtr; 199 int pitch = output.width; 200 for(int y = ya ; y < yb ; y++){ 201 ushort* p0 = p + xa + y * pitch; 202 203 int x = xa; 204 //writeln(x); 205 while( x < xb - 7 ){ 206 ushort[8]* p1 = cast(ushort[8]*)p0; 207 /*asm{ 208 movups XMM0, colorvect; 209 movups [p0], XMM0; 210 }*/ 211 *p1 = colorvect; 212 p0 += 8; 213 x += 8; 214 //writeln(x); 215 //output.writePixel(x, y, color); 216 } 217 if(xb - x > 3){ 218 ushort[4]* p1 = cast(ushort[4]*)p0; 219 /*asm{ 220 movups XMM0, colorvect; 221 movq [p0], XMM0; 222 }*/ 223 *p1 = [color,color,color,color]; 224 x += 4; 225 p0 += 4; 226 //writeln(x); 227 } 228 if(xb - x > 1){ 229 ushort[2]* p1 = cast(ushort[2]*)p0; 230 /*asm{ 231 movups XMM0, colorvect; 232 movd [p0], XMM0; 233 }*/ 234 *p1 = [color,color]; 235 x += 2; 236 p0 += 2; 237 //writeln(x); 238 } 239 if(xb - x == 1){ 240 *p0 = color; 241 //writeln(x); 242 } 243 } 244 } 245 ///Fills the area with a pattern. 246 public void patternFill(int xa, int ya, int xb, int yb, Bitmap16Bit pattern){ 247 248 } 249 ///Draws texts. (deprecated, will be removed after Version 1.0.0) 250 public deprecated void drawText(int x, int y, wstring text, Bitmap16Bit[wchar] fontSet, int style = 0){ 251 int length; 252 for(int i ; i < text.length ; i++){ 253 length += fontSet[text[i]].width; 254 } 255 //writeln(text); 256 if(style == 0){ 257 x = x - (length / 2); 258 y -= fontSet['a'].height / 2; 259 } 260 foreach(wchar c ; text){ 261 262 insertBitmap(x, y, fontSet[c]); 263 x = x + fontSet[c].width; 264 } 265 } 266 ///Draws text to the given point. Styles: 0 = centered, 1 = left, 2 = right 267 public void drawText(int x, int y, wstring text, Fontset!(Bitmap16Bit) fontset, int style = 0){ 268 int length = fontset.getTextLength(text); 269 //writeln(text); 270 if(style == 0){ 271 x = x - (length / 2); 272 y -= fontset.getSize() / 2; 273 }else if(style == 2){ 274 y -= fontset.getSize(); 275 } 276 foreach(wchar c ; text){ 277 insertBitmap(x, y, fontset.letters[c]); 278 x = x + fontset.letters[c].width; 279 } 280 } 281 ///Draws colored text from monocromatic font. 282 public void drawColorText(int x, int y, wstring text, Fontset!(Bitmap16Bit) fontset, ushort color, int style = 0){ 283 //color = 1; 284 ushort[8] colorvect = [color, color, color, color, color, color, color, color]; 285 int length = fontset.getTextLength(text); 286 //writeln(text); 287 if(style == 0){ 288 x = x - (length / 2); 289 y -= fontset.getSize() / 2; 290 }else if(style == 2){ 291 x -= length; 292 } 293 foreach(wchar c ; text){ 294 295 insertColorLetter(x, y, fontset.letters[c], colorvect); 296 x = x + fontset.letters[c].width; 297 } 298 } 299 public void insertColorLetter(int x, int y, Bitmap16Bit bitmap, ushort[8] colorvect){ 300 version(NO_SSE2){ 301 ushort[4] colortester = [1,1,1,1], colorvect4 = [colorvect[0],colorvect[0],colorvect[0],colorvect[0]]; 302 ushort* psrc = bitmap.getPtr, pdest = output.getPtr; 303 int pitch = output.width; 304 for(int iy ; iy < bitmap.height ; iy++){ 305 int ix = bitmap.width / 4; 306 int ix2 = bitmap.width - ix * 2; 307 int offsetY = bitmap.width * iy; 308 ushort[4]* psrc2 = cast(ushort[4]*)(psrc + offsetY), pdest2 = cast(ushort[4]*)(pdest + x + ((iy + y) * pitch)); 309 asm{ 310 mov EDI, pdest2[EBP]; 311 mov ESI, psrc2[EBP]; 312 movq MM5, colorvect4; 313 movq MM6, colortester; 314 mov ECX, ix; 315 //cmp ECX, 0; 316 jecxz blt4px; 317 loopstart: //using 8 pixel blitter for the most part 318 319 movq MM0, [ESI]; 320 movq MM1, [EDI]; 321 movq MM4, transparencytester4; 322 pcmpeqw MM4, MM0; 323 pcmpeqw MM0, MM6; 324 pand MM0, MM5; 325 326 pand MM1, XMM4; 327 por MM1, XMM0; 328 movq [EDI], XMM1; 329 330 add ESI, 8; 331 add EDI, 8; 332 loop loopstart; 333 334 //4 pixel blitter if needed 335 blt2px: 336 mov ECX, ix2; 337 cmp ECX, 2; 338 jb blt1px; 339 sub ECX, 2; 340 movd XMM0, [ESI]; 341 movd XMM1, [EDI]; 342 movq XMM4, transparencytester4; 343 pcmpeqw XMM4, XMM0; 344 pcmpeqw XMM0, XMM6; 345 pand XMM0, XMM5; 346 347 pand XMM1, XMM4; 348 por XMM1, XMM0; 349 movd [EDI], XMM1; 350 351 add ESI, 4; 352 add EDI, 4; 353 //1 pixel "blitter" if needed 354 blt1px: 355 jecxz end; 356 mov AX, [ESI]; 357 cmp AX, 0; 358 cmovnz AX, colorvect[0]; 359 cmovz AX, [EDI]; 360 mov [EDI], AX; 361 end:; 362 } 363 364 } 365 }else version(X86){ 366 ushort[8] colortester = [1,1,1,1,1,1,1,1]; 367 ushort* psrc = bitmap.getPtr, pdest = output.getPtr; 368 int pitch = output.width; 369 for(int iy ; iy < bitmap.height ; iy++){ 370 int ix = bitmap.width / 8; 371 int ix4 = bitmap.width - ix * 8; 372 int offsetY = bitmap.width * iy; 373 ushort[8]* psrc2 = cast(ushort[8]*)(psrc + offsetY), pdest2 = cast(ushort[8]*)(pdest + x + ((iy + y) * pitch)); 374 asm{ 375 mov EDI, pdest2[EBP]; 376 mov ESI, psrc2[EBP]; 377 movups XMM5, colorvect; 378 movups XMM6, colortester; 379 mov ECX, ix; 380 //cmp ECX, 0; 381 jecxz blt4px; 382 loopstart: //using 8 pixel blitter for the most part 383 384 movups XMM0, [ESI]; 385 movups XMM1, [EDI]; 386 movups XMM4, transparencytester8; 387 pcmpeqw XMM4, XMM0; 388 pcmpeqw XMM0, XMM6; 389 pand XMM0, XMM5; 390 391 pand XMM1, XMM4; 392 por XMM1, XMM0; 393 movups [EDI], XMM1; 394 395 add ESI, 16; 396 add EDI, 16; 397 loop loopstart; 398 399 //4 pixel blitter if needed 400 blt4px: 401 mov ECX, ix4; 402 cmp ECX, 4; 403 jb blt2px; 404 sub ECX, 4; 405 movq XMM0, [ESI]; 406 movq XMM1, [EDI]; 407 movups XMM4, transparencytester8; 408 pcmpeqw XMM4, XMM0; 409 pcmpeqw XMM0, XMM6; 410 pand XMM0, XMM5; 411 412 pand XMM1, XMM4; 413 por XMM1, XMM0; 414 movq [EDI], XMM1; 415 416 add ESI, 8; 417 add EDI, 8; 418 //2 pixel blitter if needed 419 blt2px: 420 cmp ECX, 2; 421 jb blt1px; 422 sub ECX, 2; 423 movd XMM0, [ESI]; 424 movd XMM1, [EDI]; 425 movups XMM4, transparencytester8; 426 pcmpeqw XMM4, XMM0; 427 pcmpeqw XMM0, XMM6; 428 pand XMM0, XMM5; 429 430 pand XMM1, XMM4; 431 por XMM1, XMM0; 432 movd [EDI], XMM1; 433 434 add ESI, 4; 435 add EDI, 4; 436 //1 pixel "blitter" if needed 437 blt1px: 438 jecxz end; 439 mov AX, [ESI]; 440 cmp AX, 0; 441 cmovnz AX, colorvect[0]; 442 cmovz AX, [EDI]; 443 mov [EDI], AX; 444 end:; 445 } 446 447 } 448 }else version(X86_64){ 449 ushort[8] colortester = [1,1,1,1,1,1,1,1]; 450 ushort* psrc = bitmap.getPtr, pdest = output.getPtr; 451 int pitch = output.width; 452 for(int iy ; iy < bitmap.height ; iy++){ 453 int ix = bitmap.width / 8; 454 int ix4 = bitmap.width - ix * 8; 455 int offsetY = bitmap.width * iy; 456 ushort[8]* psrc2 = cast(ushort[8]*)(psrc + offsetY), pdest2 = cast(ushort[8]*)(pdest + x + ((iy + y) * pitch)); 457 asm{ 458 mov RDI, pdest2[RBP]; 459 mov RSI, psrc2[RBP]; 460 movups XMM5, colorvect; 461 movups XMM6, colortester; 462 mov ECX, ix; 463 //cmp ECX, 0; 464 jecxz blt4px; 465 loopstart: //using 8 pixel blitter for the most part 466 467 movups XMM0, [RSI]; 468 movups XMM1, [RDI]; 469 movups XMM4, transparencytester8; 470 pcmpeqw XMM4, XMM0; 471 pcmpeqw XMM0, XMM6; 472 pand XMM0, XMM5; 473 474 pand XMM1, XMM4; 475 por XMM1, XMM0; 476 movups [RDI], XMM1; 477 478 add RSI, 16; 479 add RDI, 16; 480 loop loopstart; 481 482 //4 pixel blitter if needed 483 blt4px: 484 mov ECX, ix4; 485 cmp ECX, 4; 486 jb blt2px; 487 sub ECX, 4; 488 movq XMM0, [RSI]; 489 movq XMM1, [RDI]; 490 movups XMM4, transparencytester8; 491 pcmpeqw XMM4, XMM0; 492 pcmpeqw XMM0, XMM6; 493 pand XMM0, XMM5; 494 495 pand XMM1, XMM4; 496 por XMM1, XMM0; 497 movq [RDI], XMM1; 498 499 add RSI, 8; 500 add RDI, 8; 501 //2 pixel blitter if needed 502 blt2px: 503 cmp ECX, 2; 504 jb blt1px; 505 sub ECX, 2; 506 movd XMM0, [RSI]; 507 movd XMM1, [RDI]; 508 movups XMM4, transparencytester8; 509 pcmpeqw XMM4, XMM0; 510 pcmpeqw XMM0, XMM6; 511 pand XMM0, XMM5; 512 513 pand XMM1, XMM4; 514 por XMM1, XMM0; 515 movd [RDI], XMM1; 516 517 add RSI, 4; 518 add RDI, 4; 519 //1 pixel "blitter" if needed 520 blt1px: 521 jecxz end; 522 mov AX, [RSI]; 523 cmp AX, 0; 524 cmovnz AX, colorvect[0]; 525 cmovz AX, [RDI]; 526 mov [RDI], AX; 527 end:; 528 } 529 530 } 531 }else{ 532 for(int iy; iy < bitmap.height; iy++){ 533 for(int ix; ix < bitmap.width; ix++){ 534 ushort c = bitmap.readPixel(ix, iy); 535 if(c) 536 output.writePixel(x + ix, y + iy, colorvect[0]); 537 } 538 } 539 } 540 } 541 } 542