From fffe36e3581788bd8255c584189c5dbdacf6f427 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 28 Mar 2020 12:33:16 +0100 Subject: [PATCH] fix bresenham line --- .../prog8/optimizer/ExpressionSimplifier.kt | 6 + .../{lines-circles-gfx.p8 => c64graphics.p8} | 141 ++++++++++-------- examples/line-circle-gfx.p8 | 35 +++++ .../{lines-circles.p8 => line-circle-txt.p8} | 3 +- 4 files changed, 123 insertions(+), 62 deletions(-) rename examples/{lines-circles-gfx.p8 => c64graphics.p8} (74%) create mode 100644 examples/line-circle-gfx.p8 rename examples/{lines-circles.p8 => line-circle-txt.p8} (96%) diff --git a/compiler/src/prog8/optimizer/ExpressionSimplifier.kt b/compiler/src/prog8/optimizer/ExpressionSimplifier.kt index a40d14475..ea491f206 100644 --- a/compiler/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/compiler/src/prog8/optimizer/ExpressionSimplifier.kt @@ -14,6 +14,12 @@ import kotlin.math.pow /* todo add more expression optimizations + x + x -> x << 1 (for words... for bytes too?) + x + x + x + x -> x << 2 (for words... for bytes too?) + x + x + x -> ???? x*3 ??? words/bytes? + x - x -> 0 + + Investigate what optimizations binaryen has, also see https://egorbo.com/peephole-optimizations.html */ diff --git a/examples/lines-circles-gfx.p8 b/examples/c64graphics.p8 similarity index 74% rename from examples/lines-circles-gfx.p8 rename to examples/c64graphics.p8 index 1f0afefbb..aba5a133d 100644 --- a/examples/lines-circles-gfx.p8 +++ b/examples/c64graphics.p8 @@ -1,77 +1,96 @@ %import c64lib -%import c64utils -%zeropage basicsafe +; bitmap pixel graphics module for the C64 +; only black/white monchrome for now -main { +; you could put this code at $4000 which is after the bitmap screen in memory ($2000-$3fff), +; this leaves more space for user program code. +graphics { const uword bitmap_address = $2000 - - sub start() { - + sub enable_bitmap_mode() { ; enable bitmap screen, erase it and set colors to black/white. c64.SCROLY |= %00100000 c64.VMCSB = (c64.VMCSB & %11110000) | %00001000 ; $2000-$3fff memset(bitmap_address, 320*200/8, 0) - c64scr.clear_screen($10, 0) - - lines() - circles() - forever { - } + c64scr.clear_screen($10, 0) ; pixel color $1 (white) backround $0 (black) } - - sub circles() { - ubyte xx - for xx in 3 to 7 { - circle(xx*50-100, 10+xx*16, (xx+6)*4) - disc(xx*50-100, 10+xx*16, (xx+6)*2) - } - } - - sub lines() { - ubyte ix - for ix in 1 to 15 { - line(10, 10, ix*4, 50) ; TODO fix lines of lenghts > 128 - } - } - - sub line(ubyte x1, ubyte y1, ubyte x2, ubyte y2) { + sub line(uword x1, ubyte y1, uword x2, ubyte y2) { ; Bresenham algorithm - byte d = 0 - ubyte dx = abs(x2 - x1) - ubyte dy = abs(y2 - y1) - ubyte dx2 = 2 * dx - ubyte dy2 = 2 * dy - word ix = sgn(x2 as byte - x1 as byte) - word iy = sgn(y2 as byte - y1 as byte) + word dx + word dy + byte ix = 1 + byte iy = 1 + if x2>x1 { + dx = x2-x1 + } else { + ix = -1 + dx = x1-x2 + } + if y2>y1 { + dy = y2-y1 + } else { + iy = -1 + dy = y1-y2 + } + word dx2 = 2 * dx + word dy2 = 2 * dy + word d = 0 plotx = x1 if dx >= dy { - forever { - plot(y1) - if plotx==x2 - return - plotx += ix - d += dy2 - if d > dx { - y1 += iy - d -= dx2 + if ix<0 { + forever { + graphics.plot(y1) + if plotx==x2 + return + plotx-- + d += dy2 + if d > dx { + y1 += iy + d -= dx2 + } + } + } else { + forever { + graphics.plot(y1) + if plotx==x2 + return + plotx++ + d += dy2 + if d > dx { + y1 += iy + d -= dx2 + } } } } else { - forever { - plot(y1) - if y1 == y2 - return - y1 += iy - d += dx2 - if d > dy { - plotx += ix - d -= dy2 + if iy<0 { + forever { + plot(y1) + if y1 == y2 + return + y1-- + d += dx2 + if d > dy { + plotx += ix as word + d -= dy2 + } + } + } else { + forever { + plot(y1) + if y1 == y2 + return + y1++ + d += dx2 + if d > dy { + plotx += ix as word + d -= dy2 + } } } } @@ -149,6 +168,13 @@ main { } +; here is the non-asm code for the plot routine below: +; sub plot_nonasm(uword px, ubyte py) { +; ubyte[] ormask = [128, 64, 32, 16, 8, 4, 2, 1] +; uword addr = bitmap_address + 320*(py>>3) + (py & 7) + (px & %0000000111111000) +; @(addr) |= ormask[lsb(px) & 7] +; } + uword plotx ; 0..319 asmsub plot(ubyte ploty @A) { ; plotx is 16 bits 0 to 319... doesn't fit in a register @@ -219,13 +245,6 @@ _y_lookup_lo }} } -; here is the non-asm code for the same plot routine: -; sub plot_nonasm(uword px, ubyte py) { -; ubyte[] ormask = [128, 64, 32, 16, 8, 4, 2, 1] -; uword addr = bitmap_address + 320*(py>>3) + (py & 7) + (px & %0000000111111000) -; @(addr) |= ormask[lsb(px) & 7] -; } - } diff --git a/examples/line-circle-gfx.p8 b/examples/line-circle-gfx.p8 new file mode 100644 index 000000000..f846d837f --- /dev/null +++ b/examples/line-circle-gfx.p8 @@ -0,0 +1,35 @@ +%import c64lib +%import c64graphics +%zeropage basicsafe + + +main { + + sub start() { + graphics.enable_bitmap_mode() + draw_lines() + draw_circles() + forever { + } + } + + sub draw_circles() { + ubyte xx + for xx in 3 to 7 { + graphics.circle(xx*50-100, 10+xx*16, (xx+6)*4) + graphics.disc(xx*50-100, 10+xx*16, (xx+6)*2) + } + } + + sub draw_lines() { + ubyte i + for i in 0 to 255 step 4 { + ; uword x1 = (320-256)/2 + sin8u(i) + uword x1 = ((320-256)/2 as uword) + sin8u(i) ; TODO fix the need for a cast here + uword y1 = (200-128)/2 + cos8u(i)/2 + uword x2 = ((320-64)/2 as uword) + sin8u(i)/4 ; TODO fix the need for a cast here + uword y2 = (200-64)/2 + cos8u(i)/4 + graphics.line(x1, lsb(y1), x2, lsb(y2)) + } + } +} diff --git a/examples/lines-circles.p8 b/examples/line-circle-txt.p8 similarity index 96% rename from examples/lines-circles.p8 rename to examples/line-circle-txt.p8 index 3bc0e72b2..091444335 100644 --- a/examples/lines-circles.p8 +++ b/examples/line-circle-txt.p8 @@ -64,7 +64,8 @@ main { } sub line(ubyte x1, ubyte y1, ubyte x2, ubyte y2) { - ; Bresenham algorithm + ; Bresenham algorithm, not very optimized to keep clear code. + ; For a better optimized version have a look in the graphics.p8 module. byte d = 0 ubyte dx = abs(x2 - x1) ubyte dy = abs(y2 - y1)