monogfx, gfx_lores, gfx_hires now all uses 8kb stack from buffers module; no more broken flood fills. fill() has an extra byte parameter now where you need to pass in the ram bank to use for the stack. (not on virtual target)

This commit is contained in:
Irmen de Jong 2024-11-29 20:57:40 +01:00
parent 310e8f15cd
commit feb8aa435e
8 changed files with 113 additions and 292 deletions

View File

@ -12,6 +12,8 @@
; This is compatible with the CX16's screen mode 128. (void cx16.set_screen_mode(128))
;
%import buffers
gfx_hires {
%option ignore_unused
@ -574,7 +576,7 @@ gfx_hires {
}}
}
sub fill(uword x, uword y, ubyte new_color) {
sub fill(uword x, uword y, ubyte new_color, ubyte stack_rambank) {
; reuse a few virtual registers in ZP for variables
&ubyte fillm = &cx16.r7L
&ubyte seedm = &cx16.r8L
@ -586,75 +588,28 @@ gfx_hires {
; Non-recursive scanline flood fill.
; based loosely on code found here https://www.codeproject.com/Articles/6017/QuickFill-An-efficient-flood-fill-algorithm
; with the fixes applied to the seedfill_4 routine as mentioned in the comments.
const ubyte MAXDEPTH = 100
word @zp xx = x as word
word @zp yy = y as word
word[MAXDEPTH] @split @shared stack_xl
word[MAXDEPTH] @split @shared stack_xr
word[MAXDEPTH] @split @shared stack_y
byte[MAXDEPTH] @shared stack_dy
cx16.r12L = 0 ; stack pointer
word x1
word x2
byte dy
cx16.r10L = new_color
stack.init(stack_rambank)
sub push_stack(word sxl, word sxr, word sy, byte sdy) {
if cx16.r12L==MAXDEPTH
return
cx16.r0s = sy+sdy
if cx16.r0s>=0 and cx16.r0s<=HEIGHT-1 {
;; stack_xl[cx16.r12L] = sxl
;; stack_xr[cx16.r12L] = sxr
;; stack_y[cx16.r12L] = sy
;; stack_dy[cx16.r12L] = sdy
;; cx16.r12L++
%asm {{
ldy cx16.r12L
lda p8v_sxl
sta p8v_stack_xl_lsb,y
lda p8v_sxl+1
sta p8v_stack_xl_msb,y
lda p8v_sxr
sta p8v_stack_xr_lsb,y
lda p8v_sxr+1
sta p8v_stack_xr_msb,y
lda p8v_sy
sta p8v_stack_y_lsb,y
lda p8v_sy+1
sta p8v_stack_y_msb,y
ldy cx16.r12L
lda p8v_sdy
sta p8v_stack_dy,y
inc cx16.r12L
}}
stack.pushw(sxl as uword)
stack.pushw(sxr as uword)
stack.pushw(sy as uword)
stack.push(sdy as ubyte)
}
}
sub pop_stack() {
;; cx16.r12L--
;; x1 = stack_xl[cx16.r12L]
;; x2 = stack_xr[cx16.r12L]
;; y = stack_y[cx16.r12L]
;; dy = stack_dy[cx16.r12L]
%asm {{
dec cx16.r12L
ldy cx16.r12L
lda p8v_stack_xl_lsb,y
sta p8v_x1
lda p8v_stack_xl_msb,y
sta p8v_x1+1
lda p8v_stack_xr_lsb,y
sta p8v_x2
lda p8v_stack_xr_msb,y
sta p8v_x2+1
lda p8v_stack_y_lsb,y
sta p8v_yy
lda p8v_stack_y_msb,y
sta p8v_yy+1
ldy cx16.r12L
lda p8v_stack_dy,y
sta p8v_dy
}}
dy = stack.pop() as byte
yy = stack.popw() as word
x2 = stack.popw() as word
x1 = stack.popw() as word
yy+=dy
}
cx16.r11L = pget(xx as uword, yy as uword) ; old_color
@ -666,7 +621,7 @@ gfx_hires {
push_stack(xx, xx, yy, 1)
push_stack(xx, xx, yy + 1, -1)
word left = 0
while cx16.r12L!=0 {
while not stack.isempty() {
pop_stack()
xx = x1
if fill_scanline_left_2bpp() goto skip

View File

@ -5,6 +5,7 @@
%import syslib
%import verafx
%import buffers
gfx_lores {
%option ignore_unused
@ -627,7 +628,7 @@ gfx_lores {
}}
}
sub fill(uword x, ubyte y, ubyte new_color) {
sub fill(uword x, ubyte y, ubyte new_color, ubyte stack_rambank) {
; reuse a few virtual registers in ZP for variables
&ubyte fillm = &cx16.r7L
&ubyte seedm = &cx16.r8L
@ -639,75 +640,28 @@ gfx_lores {
; Non-recursive scanline flood fill.
; based loosely on code found here https://www.codeproject.com/Articles/6017/QuickFill-An-efficient-flood-fill-algorithm
; with the fixes applied to the seedfill_4 routine as mentioned in the comments.
const ubyte MAXDEPTH = 100
word @zp xx = x as word
word @zp yy = y as word
word[MAXDEPTH] @split @shared stack_xl
word[MAXDEPTH] @split @shared stack_xr
word[MAXDEPTH] @split @shared stack_y
byte[MAXDEPTH] @shared stack_dy
cx16.r12L = 0 ; stack pointer
word x1
word x2
byte dy
cx16.r10L = new_color
stack.init(stack_rambank)
sub push_stack(word sxl, word sxr, word sy, byte sdy) {
if cx16.r12L==MAXDEPTH
return
cx16.r0s = sy+sdy
if cx16.r0s>=0 and cx16.r0s<=HEIGHT-1 {
;; stack_xl[cx16.r12L] = sxl
;; stack_xr[cx16.r12L] = sxr
;; stack_y[cx16.r12L] = sy
;; stack_dy[cx16.r12L] = sdy
;; cx16.r12L++
%asm {{
ldy cx16.r12L
lda p8v_sxl
sta p8v_stack_xl_lsb,y
lda p8v_sxl+1
sta p8v_stack_xl_msb,y
lda p8v_sxr
sta p8v_stack_xr_lsb,y
lda p8v_sxr+1
sta p8v_stack_xr_msb,y
lda p8v_sy
sta p8v_stack_y_lsb,y
lda p8v_sy+1
sta p8v_stack_y_msb,y
ldy cx16.r12L
lda p8v_sdy
sta p8v_stack_dy,y
inc cx16.r12L
}}
stack.pushw(sxl as uword)
stack.pushw(sxr as uword)
stack.pushw(sy as uword)
stack.push(sdy as ubyte)
}
}
sub pop_stack() {
;; cx16.r12L--
;; x1 = stack_xl[cx16.r12L]
;; x2 = stack_xr[cx16.r12L]
;; y = stack_y[cx16.r12L]
;; dy = stack_dy[cx16.r12L]
%asm {{
dec cx16.r12L
ldy cx16.r12L
lda p8v_stack_xl_lsb,y
sta p8v_x1
lda p8v_stack_xl_msb,y
sta p8v_x1+1
lda p8v_stack_xr_lsb,y
sta p8v_x2
lda p8v_stack_xr_msb,y
sta p8v_x2+1
lda p8v_stack_y_lsb,y
sta p8v_yy
lda p8v_stack_y_msb,y
sta p8v_yy+1
ldy cx16.r12L
lda p8v_stack_dy,y
sta p8v_dy
}}
dy = stack.pop() as byte
yy = stack.popw() as word
x2 = stack.popw() as word
x1 = stack.popw() as word
yy+=dy
}
cx16.r11L = pget(xx as uword, lsb(yy)) ; old_color
@ -718,7 +672,7 @@ gfx_lores {
push_stack(xx, xx, yy, 1)
push_stack(xx, xx, yy + 1, -1)
word left = 0
while cx16.r12L!=0 {
while not stack.isempty() {
pop_stack()
xx = x1
if fill_scanline_left_8bpp() goto skip

View File

@ -7,6 +7,8 @@
; NOTE: For sake of speed, NO BOUNDS CHECKING is performed in most routines!
; You'll have to make sure yourself that you're not writing outside of bitmap boundaries!
%import buffers
monogfx {
%option ignore_unused
@ -733,78 +735,31 @@ invert:
}}
}
sub fill(uword x, uword y, bool draw) {
sub fill(uword x, uword y, bool draw, ubyte stack_rambank) {
; Non-recursive scanline flood fill.
; based loosely on code found here https://www.codeproject.com/Articles/6017/QuickFill-An-efficient-flood-fill-algorithm
; with the fixes applied to the seedfill_4 routine as mentioned in the comments.
const ubyte MAXDEPTH = 100
word @zp xx = x as word
word @zp yy = y as word
word[MAXDEPTH] @split @shared stack_xl
word[MAXDEPTH] @split @shared stack_xr
word[MAXDEPTH] @split @shared stack_y
byte[MAXDEPTH] @shared stack_dy
cx16.r12L = 0 ; stack pointer
word x1
word x2
byte dy
stack.init(stack_rambank)
cx16.r10L = draw as ubyte
sub push_stack(word sxl, word sxr, word sy, byte sdy) {
if cx16.r12L==MAXDEPTH
return
cx16.r0s = sy+sdy
if cx16.r0s>=0 and cx16.r0s<=height-1 {
;; stack_xl[cx16.r12L] = sxl
;; stack_xr[cx16.r12L] = sxr
;; stack_y[cx16.r12L] = sy
;; stack_dy[cx16.r12L] = sdy
;; cx16.r12L++
%asm {{
ldy cx16.r12L
lda p8v_sxl
sta p8v_stack_xl_lsb,y
lda p8v_sxl+1
sta p8v_stack_xl_msb,y
lda p8v_sxr
sta p8v_stack_xr_lsb,y
lda p8v_sxr+1
sta p8v_stack_xr_msb,y
lda p8v_sy
sta p8v_stack_y_lsb,y
lda p8v_sy+1
sta p8v_stack_y_msb,y
ldy cx16.r12L
lda p8v_sdy
sta p8v_stack_dy,y
inc cx16.r12L
}}
stack.pushw(sxl as uword)
stack.pushw(sxr as uword)
stack.pushw(sy as uword)
stack.push(sdy as ubyte)
}
}
sub pop_stack() {
;; cx16.r12L--
;; x1 = stack_xl[cx16.r12L]
;; x2 = stack_xr[cx16.r12L]
;; y = stack_y[cx16.r12L]
;; dy = stack_dy[cx16.r12L]
%asm {{
dec cx16.r12L
ldy cx16.r12L
lda p8v_stack_xl_lsb,y
sta p8v_x1
lda p8v_stack_xl_msb,y
sta p8v_x1+1
lda p8v_stack_xr_lsb,y
sta p8v_x2
lda p8v_stack_xr_msb,y
sta p8v_x2+1
lda p8v_stack_y_lsb,y
sta p8v_yy
lda p8v_stack_y_msb,y
sta p8v_yy+1
ldy cx16.r12L
lda p8v_stack_dy,y
sta p8v_dy
}}
dy = stack.pop() as byte
yy = stack.popw() as word
x2 = stack.popw() as word
x1 = stack.popw() as word
yy+=dy
}
cx16.r11L = pget(xx as uword, yy as uword) as ubyte ; old_color
@ -815,7 +770,7 @@ invert:
push_stack(xx, xx, yy, 1)
push_stack(xx, xx, yy + 1, -1)
word left = 0
while cx16.r12L!=0 {
while not stack.isempty() {
pop_stack()
xx = x1
if fill_scanline_left() goto skip

View File

@ -4,6 +4,7 @@
; NOTE: For sake of speed, NO BOUNDS CHECKING is performed in most routines!
; You'll have to make sure yourself that you're not writing outside of bitmap boundaries!
%import buffers
monogfx {
@ -408,36 +409,27 @@ monogfx {
; Non-recursive scanline flood fill.
; based loosely on code found here https://www.codeproject.com/Articles/6017/QuickFill-An-efficient-flood-fill-algorithm
; with the fixes applied to the seedfill_4 routine as mentioned in the comments.
const ubyte MAXDEPTH = 100
word @zp xx = x as word
word @zp yy = y as word
word[MAXDEPTH] @split @shared stack_xl
word[MAXDEPTH] @split @shared stack_xr
word[MAXDEPTH] @split @shared stack_y
byte[MAXDEPTH] @shared stack_dy
cx16.r12L = 0 ; stack pointer
word x1
word x2
byte dy
stack.init()
cx16.r10L = draw as ubyte
sub push_stack(word sxl, word sxr, word sy, byte sdy) {
if cx16.r12L==MAXDEPTH
return
cx16.r0s = sy+sdy
if cx16.r0s>=0 and cx16.r0s<=height-1 {
stack_xl[cx16.r12L] = sxl
stack_xr[cx16.r12L] = sxr
stack_y[cx16.r12L] = sy
stack_dy[cx16.r12L] = sdy
cx16.r12L++
stack.pushw(sxl as uword)
stack.pushw(sxr as uword)
stack.pushw(sy as uword)
stack.push(sdy as ubyte)
}
}
sub pop_stack() {
cx16.r12L--
x1 = stack_xl[cx16.r12L]
x2 = stack_xr[cx16.r12L]
yy = stack_y[cx16.r12L]
dy = stack_dy[cx16.r12L]
dy = stack.pop() as byte
yy = stack.popw() as word
x2 = stack.popw() as word
x1 = stack.popw() as word
yy+=dy
}
cx16.r11L = pget(xx as uword, yy as uword) as ubyte ; old_color
@ -448,7 +440,7 @@ monogfx {
push_stack(xx, xx, yy, 1)
push_stack(xx, xx, yy + 1, -1)
word left = 0
while cx16.r12L!=0 {
while not stack.isempty() {
pop_stack()
xx = x1
while xx >= 0 {

View File

@ -1,6 +1,8 @@
TODO
====
virtual: importing buffers in main results in a vm error?
document the @R0 - @R15 register support for normal subroutine parameters (footgun!)
make a compiler switch to disable footgun warnings

View File

@ -8,6 +8,8 @@
main {
const ubyte FILL_STACK_BANK = 2
sub start() {
demofill()
sys.wait(120)
@ -24,9 +26,9 @@ main {
gfx_lores.line(100, 150, 240, 10, 1)
gfx_lores.line(101, 150, 241, 10, 1)
sys.wait(60)
gfx_lores.fill(100,100,2)
gfx_lores.fill(182,140,3)
gfx_lores.fill(182,40,1)
gfx_lores.fill(100,100,2, FILL_STACK_BANK)
gfx_lores.fill(182,140,3, FILL_STACK_BANK)
gfx_lores.fill(182,40,1, FILL_STACK_BANK)
}

View File

@ -7,6 +7,7 @@
main {
const ubyte FILL_STACK_BANK = 2
sub start() {
monogfx.lores()
@ -28,7 +29,7 @@ main {
monogfx.line(101, 150, 241, 10, true)
monogfx.drawmode(monogfx.MODE_STIPPLE)
sys.wait(60)
monogfx.fill(100,100,true)
monogfx.fill(100,100,true, FILL_STACK_BANK)
}
sub demo1() {

View File

@ -1,106 +1,66 @@
%import textio
%import buffers
%import monogfx
%option no_sysinit
%zeropage basicsafe
main {
sub start() {
txt.print("stack\n")
test_stack()
txt.print("\nringbuffer\n")
test_ring()
txt.print("\nsmallringbuffer\n")
test_smallring()
monogfx.lores()
uword x
for x in 128 to 319 step 40 {
monogfx.line(x, 0, x-100, 200, true)
}
for x in 32 to 200 step 40 {
monogfx.line(x, 239, x+100, 20, true)
}
monogfx.fill(310, 230, true, 44)
sys.wait(100)
}
sub test_stack() {
stack.init(2)
txt.print_uw(stack.size())
txt.spc()
txt.print_uw(stack.free())
txt.nl()
stack.push(1)
stack.push(2)
stack.push(3)
stack.pushw(12345)
txt.print_uw(stack.size())
txt.spc()
txt.print_uw(stack.free())
txt.nl()
txt.nl()
txt.print_uw(stack.popw())
txt.nl()
txt.print_uw(stack.pop())
txt.nl()
txt.print_uw(stack.pop())
txt.nl()
txt.print_uw(stack.pop())
txt.nl()
txt.nl()
txt.print_uw(stack.size())
txt.spc()
txt.print_uw(stack.free())
txt.nl()
}
; sub start() {
; monogfx.hires()
;
; uword x
; for x in 128 to 639 step 64 {
; monogfx.line(x, 0, x-100, 400, true)
; }
; for x in 32 to 500 step 64 {
; monogfx.line(x, 479, x+100, 100, true)
; }
; monogfx.fill(630, 440, true, 44)
;
; sys.wait(100)
; }
sub test_ring() {
ringbuffer.init(2)
txt.print_uw(ringbuffer.size())
txt.spc()
txt.print_uw(ringbuffer.free())
txt.nl()
ringbuffer.put(1)
ringbuffer.put(2)
ringbuffer.put(3)
ringbuffer.putw(12345)
txt.print_uw(ringbuffer.size())
txt.spc()
txt.print_uw(ringbuffer.free())
txt.nl()
txt.nl()
txt.print_uw(ringbuffer.get())
txt.nl()
txt.print_uw(ringbuffer.get())
txt.nl()
txt.print_uw(ringbuffer.get())
txt.nl()
txt.print_uw(ringbuffer.getw())
txt.nl()
txt.nl()
txt.print_uw(ringbuffer.size())
txt.spc()
txt.print_uw(ringbuffer.free())
txt.nl()
}
; sub start() {
; gfx_hires.graphics_mode()
;
; uword x
; for x in 128 to 639 step 64 {
; gfx_hires.line(x, 0, x-100, 400, 1)
; }
; for x in 32 to 500 step 64 {
; gfx_hires.line(x, 479, x+100, 100, 1)
; }
; gfx_hires.fill(630, 440, 2, 44)
;
; sys.wait(100)
; }
sub test_smallring() {
smallringbuffer.init()
txt.print_uw(smallringbuffer.size())
txt.spc()
txt.print_uw(smallringbuffer.free())
txt.nl()
smallringbuffer.put(1)
smallringbuffer.put(2)
smallringbuffer.put(3)
smallringbuffer.putw(12345)
txt.print_uw(smallringbuffer.size())
txt.spc()
txt.print_uw(smallringbuffer.free())
txt.nl()
txt.nl()
txt.print_uw(smallringbuffer.get())
txt.nl()
txt.print_uw(smallringbuffer.get())
txt.nl()
txt.print_uw(smallringbuffer.get())
txt.nl()
txt.print_uw(smallringbuffer.getw())
txt.nl()
txt.nl()
txt.print_uw(smallringbuffer.size())
txt.spc()
txt.print_uw(smallringbuffer.free())
txt.nl()
}
; sub start() {
; gfx_lores.graphics_mode()
;
; uword x
; for x in 128 to 319 step 40 {
; gfx_lores.line(x, 0, x-100, 200, 1)
; }
; for x in 32 to 200 step 40 {
; gfx_lores.line(x, 239, x+100, 20, 1)
; }
; gfx_lores.fill(310, 230, 2, 44)
;
; sys.wait(100)
; }
}