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