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)) ; This is compatible with the CX16's screen mode 128. (void cx16.set_screen_mode(128))
; ;
%import buffers
gfx_hires { gfx_hires {
%option ignore_unused %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 ; reuse a few virtual registers in ZP for variables
&ubyte fillm = &cx16.r7L &ubyte fillm = &cx16.r7L
&ubyte seedm = &cx16.r8L &ubyte seedm = &cx16.r8L
@@ -586,75 +588,28 @@ gfx_hires {
; Non-recursive scanline flood fill. ; Non-recursive scanline flood fill.
; based loosely on code found here https://www.codeproject.com/Articles/6017/QuickFill-An-efficient-flood-fill-algorithm ; 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. ; 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 xx = x as word
word @zp yy = y 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 x1
word x2 word x2
byte dy byte dy
cx16.r10L = new_color cx16.r10L = new_color
stack.init(stack_rambank)
sub push_stack(word sxl, word sxr, word sy, byte sdy) { sub push_stack(word sxl, word sxr, word sy, byte sdy) {
if cx16.r12L==MAXDEPTH
return
cx16.r0s = sy+sdy cx16.r0s = sy+sdy
if cx16.r0s>=0 and cx16.r0s<=HEIGHT-1 { if cx16.r0s>=0 and cx16.r0s<=HEIGHT-1 {
;; stack_xl[cx16.r12L] = sxl stack.pushw(sxl as uword)
;; stack_xr[cx16.r12L] = sxr stack.pushw(sxr as uword)
;; stack_y[cx16.r12L] = sy stack.pushw(sy as uword)
;; stack_dy[cx16.r12L] = sdy stack.push(sdy as ubyte)
;; 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
}}
} }
} }
sub pop_stack() { sub pop_stack() {
;; cx16.r12L-- dy = stack.pop() as byte
;; x1 = stack_xl[cx16.r12L] yy = stack.popw() as word
;; x2 = stack_xr[cx16.r12L] x2 = stack.popw() as word
;; y = stack_y[cx16.r12L] x1 = stack.popw() as word
;; 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
}}
yy+=dy yy+=dy
} }
cx16.r11L = pget(xx as uword, yy as uword) ; old_color 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)
push_stack(xx, xx, yy + 1, -1) push_stack(xx, xx, yy + 1, -1)
word left = 0 word left = 0
while cx16.r12L!=0 { while not stack.isempty() {
pop_stack() pop_stack()
xx = x1 xx = x1
if fill_scanline_left_2bpp() goto skip if fill_scanline_left_2bpp() goto skip

View File

@@ -5,6 +5,7 @@
%import syslib %import syslib
%import verafx %import verafx
%import buffers
gfx_lores { gfx_lores {
%option ignore_unused %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 ; reuse a few virtual registers in ZP for variables
&ubyte fillm = &cx16.r7L &ubyte fillm = &cx16.r7L
&ubyte seedm = &cx16.r8L &ubyte seedm = &cx16.r8L
@@ -639,75 +640,28 @@ gfx_lores {
; Non-recursive scanline flood fill. ; Non-recursive scanline flood fill.
; based loosely on code found here https://www.codeproject.com/Articles/6017/QuickFill-An-efficient-flood-fill-algorithm ; 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. ; 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 xx = x as word
word @zp yy = y 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 x1
word x2 word x2
byte dy byte dy
cx16.r10L = new_color cx16.r10L = new_color
stack.init(stack_rambank)
sub push_stack(word sxl, word sxr, word sy, byte sdy) { sub push_stack(word sxl, word sxr, word sy, byte sdy) {
if cx16.r12L==MAXDEPTH
return
cx16.r0s = sy+sdy cx16.r0s = sy+sdy
if cx16.r0s>=0 and cx16.r0s<=HEIGHT-1 { if cx16.r0s>=0 and cx16.r0s<=HEIGHT-1 {
;; stack_xl[cx16.r12L] = sxl stack.pushw(sxl as uword)
;; stack_xr[cx16.r12L] = sxr stack.pushw(sxr as uword)
;; stack_y[cx16.r12L] = sy stack.pushw(sy as uword)
;; stack_dy[cx16.r12L] = sdy stack.push(sdy as ubyte)
;; 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
}}
} }
} }
sub pop_stack() { sub pop_stack() {
;; cx16.r12L-- dy = stack.pop() as byte
;; x1 = stack_xl[cx16.r12L] yy = stack.popw() as word
;; x2 = stack_xr[cx16.r12L] x2 = stack.popw() as word
;; y = stack_y[cx16.r12L] x1 = stack.popw() as word
;; 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
}}
yy+=dy yy+=dy
} }
cx16.r11L = pget(xx as uword, lsb(yy)) ; old_color 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)
push_stack(xx, xx, yy + 1, -1) push_stack(xx, xx, yy + 1, -1)
word left = 0 word left = 0
while cx16.r12L!=0 { while not stack.isempty() {
pop_stack() pop_stack()
xx = x1 xx = x1
if fill_scanline_left_8bpp() goto skip 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! ; 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! ; You'll have to make sure yourself that you're not writing outside of bitmap boundaries!
%import buffers
monogfx { monogfx {
%option ignore_unused %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. ; Non-recursive scanline flood fill.
; based loosely on code found here https://www.codeproject.com/Articles/6017/QuickFill-An-efficient-flood-fill-algorithm ; 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. ; 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 xx = x as word
word @zp yy = y 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 x1
word x2 word x2
byte dy byte dy
stack.init(stack_rambank)
cx16.r10L = draw as ubyte cx16.r10L = draw as ubyte
sub push_stack(word sxl, word sxr, word sy, byte sdy) { sub push_stack(word sxl, word sxr, word sy, byte sdy) {
if cx16.r12L==MAXDEPTH
return
cx16.r0s = sy+sdy cx16.r0s = sy+sdy
if cx16.r0s>=0 and cx16.r0s<=height-1 { if cx16.r0s>=0 and cx16.r0s<=height-1 {
;; stack_xl[cx16.r12L] = sxl stack.pushw(sxl as uword)
;; stack_xr[cx16.r12L] = sxr stack.pushw(sxr as uword)
;; stack_y[cx16.r12L] = sy stack.pushw(sy as uword)
;; stack_dy[cx16.r12L] = sdy stack.push(sdy as ubyte)
;; 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
}}
} }
} }
sub pop_stack() { sub pop_stack() {
;; cx16.r12L-- dy = stack.pop() as byte
;; x1 = stack_xl[cx16.r12L] yy = stack.popw() as word
;; x2 = stack_xr[cx16.r12L] x2 = stack.popw() as word
;; y = stack_y[cx16.r12L] x1 = stack.popw() as word
;; 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
}}
yy+=dy yy+=dy
} }
cx16.r11L = pget(xx as uword, yy as uword) as ubyte ; old_color 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)
push_stack(xx, xx, yy + 1, -1) push_stack(xx, xx, yy + 1, -1)
word left = 0 word left = 0
while cx16.r12L!=0 { while not stack.isempty() {
pop_stack() pop_stack()
xx = x1 xx = x1
if fill_scanline_left() goto skip 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! ; 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! ; You'll have to make sure yourself that you're not writing outside of bitmap boundaries!
%import buffers
monogfx { monogfx {
@@ -408,36 +409,27 @@ monogfx {
; Non-recursive scanline flood fill. ; Non-recursive scanline flood fill.
; based loosely on code found here https://www.codeproject.com/Articles/6017/QuickFill-An-efficient-flood-fill-algorithm ; 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. ; 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 xx = x as word
word @zp yy = y 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 x1
word x2 word x2
byte dy byte dy
stack.init()
cx16.r10L = draw as ubyte cx16.r10L = draw as ubyte
sub push_stack(word sxl, word sxr, word sy, byte sdy) { sub push_stack(word sxl, word sxr, word sy, byte sdy) {
if cx16.r12L==MAXDEPTH
return
cx16.r0s = sy+sdy cx16.r0s = sy+sdy
if cx16.r0s>=0 and cx16.r0s<=height-1 { if cx16.r0s>=0 and cx16.r0s<=height-1 {
stack_xl[cx16.r12L] = sxl stack.pushw(sxl as uword)
stack_xr[cx16.r12L] = sxr stack.pushw(sxr as uword)
stack_y[cx16.r12L] = sy stack.pushw(sy as uword)
stack_dy[cx16.r12L] = sdy stack.push(sdy as ubyte)
cx16.r12L++
} }
} }
sub pop_stack() { sub pop_stack() {
cx16.r12L-- dy = stack.pop() as byte
x1 = stack_xl[cx16.r12L] yy = stack.popw() as word
x2 = stack_xr[cx16.r12L] x2 = stack.popw() as word
yy = stack_y[cx16.r12L] x1 = stack.popw() as word
dy = stack_dy[cx16.r12L]
yy+=dy yy+=dy
} }
cx16.r11L = pget(xx as uword, yy as uword) as ubyte ; old_color 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)
push_stack(xx, xx, yy + 1, -1) push_stack(xx, xx, yy + 1, -1)
word left = 0 word left = 0
while cx16.r12L!=0 { while not stack.isempty() {
pop_stack() pop_stack()
xx = x1 xx = x1
while xx >= 0 { while xx >= 0 {

View File

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

View File

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

View File

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

View File

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