- FloodFill Routine keeps Freezing
- 11 May 2011 07:57:49 am
- Last edited by ZippyDee on 11 May 2011 04:13:53 pm; edited 3 times in total
Hi, I'm quite new to ASM, and I finally finished this floodfill routine that uses no stack whatsoever...or so I thought. It seems to not be working as smoothly as I planned. It keeps freezing, and when I debug in WabbitEmu it seems that it's freezing at $0CAF, on the line "jp $0B65"
Here's my hopefully-not-too-hard-to-read code:
Code:
I wouldn't be surprised if it's something reeeeeally stupid. I'm new to ASM, so I'm sure I made multiple mistakes.
Thanks so much in advance!
-Zippy Dee
EDIT: I edited the code to what I have now. The "Paint" routine is never called, and I'm not sure why...
Here's my hopefully-not-too-hard-to-read code:
Code:
#include ti83plus.inc
#define ProgStart $9D95
#define BUFF1 plotSScreen ; Location of drawing buffer 1
#define BUFF2 0 ; Location of drawing buffer 2 (for grayscale implementation)
.org ProgStart-2
.db $BB, $6D
InitTestData:
;; INIT DATA FOR TESTING
ld hl, 20
push hl
push hl
ld hl, 1
PROGRAM_START:
;; L contains the fill color
;; stack:
;; [0]: y-coordinate
;; [1]: x-coordinate
; Get the fill color and save it to (color)
ld a, l
ld (color), a
; Calculate the byte address for the pixel
; and save it to (addr)
pop hl
ld a, 64
cp l
pop de
ret c
push de
ld d, 0
ld e, l
add hl, hl
add hl, de
add hl, hl
add hl, hl
pop de
ld a, 96
cp e
ret c
ld d, 0
srl e
srl e
srl e
ld a, e
ld (xbyte), a ;save the byte column to (xbyte)
add hl, de
ld (addr), hl
; Calculate the bitmask for the pixel
; and save it to (mask)
and 7
ld b, a
ld a, $80
jr z, ___skiploop
___loop:
rrca
djnz ___loop
___skiploop:
ld (mask), a
; make sure the starting color is not the fill color
ld de, BUFF1
add hl, de
and (hl)
cp 0
jr z, ___zero
ld a, 1
___zero:
ld (icolor), a
ld b, a
ld a, (color)
cp b
ret z ; return if the starting point is the fill color
call TurnByRule
call Loop
bcall(_getkey) ;just to pause it...
ret
Loop:
call GetBoundsPainted
ld a, b
cp 1
jp nz, _1bound
cp 2
jp nz, _2bounds
cp 3
jp nz, _3bounds
cp 4
jp nz, _4bounds
_0bounds:
call Paint
jp EndLoop
_4bounds:
call Paint
ret
_3bounds:
call GetAddr_Mask
or (hl)
ld (hl), a
;remove the mark, and reset rule and findpassage to defaults
xor a
ld (m_mask),a
ld (bool), a
ld a, $0F
jp EndLoop
_2bounds:
; jesus, this one will be tough...
ld a, (m_mask)
cp 0
jr nz, ___skip_place_mark
ld a, (bool)
and 1
cp 0
jr nz, ___skip_place_mark
ld (findpassage), a
ld a, (mask)
ld (m_mask), a
ld hl, (addr)
ld (m_addr), hl
ld a, (dir)
ld (m_dir), a
___skip_place_mark:
call MoveByRule
ld a, (m_mask)
cp 0
jr nz, ___null_mark
ld b, a
ld a, (mask)
cp b
jp nz, Loop
ld hl, (m_addr)
ld a, h
ld b, l
ld hl, (addr)
cp h
jp nz, Loop
ld a, b
cp l
jp nz, Loop
ld a, (dir)
ld b, a
ld a, (m_dir)
cp b
jr z, ___null_mark
ld (dir), a
ld a, (bool)
xor 1
ld (bool), a
xor a
ld (findpassage), a
___null_mark:
xor a
ld (m_mask), a
ld a, (bool)
and 1
cp 0
call nz, Paint
jp Loop
_1bound:
ld a, (bool)
and 1
jr z, __1bound_else
ld a, 1
ld (findpassage), a
jr EndLoop
__1bound_else:
; get opposite corners...
; if both are open
ld a, (dir)
ld b, 4
dec a
push af
___find_bound:
pop af
inc a
push af
push bc
call GetPixelInDir
ld b, a
ld a, (icolor)
cp b
pop bc
jr nz, ___found
djnz ___find_bound
pop af
xor a
ret
___found:
pop af
inc a
inc a
call GetDirOffset
push af
push de
ex de, hl
dec a
call GetDirOffset
ld a, h
or d
ld d, a
ld a, l
or e
ld e, a
call GetPixel
ld b, a
ld a, (icolor)
cp b
pop hl
pop af
jr nz, EndLoop
inc a
call GetDirOffset
ld a, h
or d
ld d, a
ld a, l
or e
ld e, a
call GetPixel
ld b, a
ld a, (icolor)
cp b
call z, Paint
EndLoop:
call MoveByRule
jp Loop
Paint:
;;##################
;;################## This routine is never called for some reason
;;##################
;; Paints the current pixel the fill color
ld a, (color)
cp 0
;jr z, __paint_off
call GetAddr_Mask
or (hl)
ld (hl), a
bcall(_GRBufCpy) ; just for testing purposes.
ret
__paint_off:
call GetAddr_Mask
xor $FF
and (hl)
ld (hl), a
bcall(_GRBufCpy) ; again just for testing purposes.
ret
MoveByRule:
;; Move to next location based on rule
;; OUT:
;; B is 0 if no tile was found to move to. Otherwise, non-zero.
call GetCurPixel
ld b, a
ld a, (icolor)
cp b
jr nz, ___move_dir ; if the current pixel is filled, just move foward
ld a, (dir)
call GetPixelInDir
ld b, a
ld a, (icolor)
cp b
jr nz, ___no_move ; if the pixel at dir is filled, don''t move
; check the corner between the pixel at dir and the pixel to the side specified by rule
; if the pixel is on, just move forward
; otherwise move to that pixel
ld a, (bool)
and 1
ld c, a
ld a, (dir)
call GetDirOffset
push de
inc a
sub c
sub c
call GetDirOffset
pop hl
push af
ld a, h
or d
ld d, a
ld a, l
or e
ld e, a
push de
call GetPixel
ld b, a
ld a, (icolor)
cp b
pop de
pop af
jr nz, ___move_dir
push af
call GetPixelAddr
ld (mask), a
ld a, d
ld (xbyte), a
ld (addr), hl
pop af
ld (dir), a
call TurnByRule
ld b, 1
ret
___move_dir:
ld a, (dir)
call GetDirOffset
call GetPixelAddr
ld (mask), a
ld a, d
ld (xbyte), a
ld (addr), hl
ld a, (bool)
and 1
ld b, a
ld a, (dir)
inc a
sub b
sub b
call remap_dir
ld (dir), a
call TurnByRule
ld b, 1
ret
___no_move:
ld b, 0
ret
TurnByRule:
;; OUT:
;; B is 0 if no tile was found to turn to. Otherwise non-zero.
ld b, 4
___turn_loop:
push bc
ld a, (dir)
call GetPixelInDir
;if pixel is on, dec
ld b, a
ld a, (icolor)
cp b
jr z, __chk_side_turn
ld a, (bool)
and 1
ld b, a
ld a, (dir)
dec a
add a, b
add a, b
call remap_dir
ld (dir), a
pop bc
djnz ___turn_loop
ret
__chk_side_turn:
;jump from push bc
ld a, (bool)
and 1
ld b, a
ld a, (dir)
inc a
sub b
sub b
call remap_dir
push af
call GetPixelInDir
ld b, a
ld a, (icolor)
cp b
pop af
pop bc
ret nz
ld (dir), a
djnz ___turn_loop
ret
remap_dir:
;; Maps the value in A to the range of 0 <= A < 4
cp 4
ret nc
cp 128
jr c, ___add
sub 4
jr remap_dir
___add:
add a, 4
jr remap_dir
GetDirOffset:
;; IN:
;; A contains the direction
call remap_dir
ld b, a
xor a
cp b
jr z, __dir_right
inc a
cp b
jr z, __dir_down
inc a
cp b
jr z, __dir_left
__dir_up:
ld a, b
ld de, $0100
ret
__dir_right:
ld a, b
ld de, $0001
ret
__dir_down:
ld a, b
ld de, $FF00
ret
__dir_left:
ld a, b
ld de, $00FF
ret
GetPixelInDir:
;; IN:
;; A contains the direction
call GetDirOffset
jp GetPixel
GetAddr_Mask:
;; OUT:
;; HL contains the addr of the pixel
;; A contains the mask of the pixel
ld hl, (addr)
ld de, BUFF1
add hl, de
ld a, (mask)
ret
GetBoundsPainted:
;; OUT:
;; B contains the number of painted boundaries
;; bits 0-3 of C contain which bounds are painted (0:right,1:left,2:top,3:bottom)
ld bc, 0
push bc
ld de, $0001
call GetPixel
ld b, a
ld a, (icolor)
cp b
jr nz, ___skip1
pop bc
inc b
ld a, 1
or c
ld c, a
push bc
___skip1:
ld de, $00FF
call GetPixel
ld b, a
ld a, (icolor)
cp b
jr nz, ___skip2
pop bc
inc b
ld a, 2
or c
ld c, a
push bc
___skip2:
ld de, $0100
call GetPixel
ld b, a
ld a, (icolor)
cp b
jr nz, ___skip3
pop bc
inc b
ld a, 4
or c
ld c, a
push bc
___skip3:
ld de, $FF00
call GetPixel
ld b, a
ld a, (icolor)
cp b
pop bc
ret nz
inc b
ld a, 8
or c
ld c, a
ret
GetCurPixel:
;; OUT:
;; A contains the color of the current pixel
ld hl, (addr)
ld de, BUFF1
add hl, de
ld a, (mask)
and (hl)
cp 0
ret z
ld a, 1
ret
GetPixelAddr:
;; IN:
;; D contains y offset
;; E contains x offset
;; OUT:
;; HL contains the addr of the pixel
;; A contains the mask for the pixel, or 0 if the pixel is off screen
;; D contains the xbyte for the pixel
ld hl, (addr)
__x_offset:
ld a, (mask)
ld b, e
ld e, a
ld a, b
cp 0
jr z, __y_offset
cp 1
ld a, (xbyte)
jr z, __shiftRight
rlc e
jr nc, __chk_side
dec a
jr __chk_side
__shiftRight:
rrc e
jr nc, __chk_side
inc a
__chk_side:
cp 12
jr c, __edgeaddr
__y_offset:
push af
ld a, d
cp 0
jr z, __return_addr
cp 1
jr z, __shiftUp
ld bc, -24
add hl, bc
jr __chk_top
__shiftUp:
ld bc, 12
add hl, bc
__chk_top:
push hl
ld bc, -768
add hl, bc
pop hl
pop af
jr c, __edgeaddr
__return_addr:
push af
ld a, e
pop de
ret
__edgeaddr:
ld a, 0
ret
GetPixel:
;; IN:
;; D contains y offset
;; E contains x offset
;; OUT:
;; A contains the color of the pixel (1 or 0)
call GetPixelAddr
cp 0
jr z, __edgepxl
__getpxl:
ld de, BUFF1
add hl, de
and (hl)
ret
__edgepxl:
ld a, (color) ; pixel is off-screen, so return (color)
ret
addr: ; Initial address (no buffer address added) of the byte containing the current pixel (Y*12+X/8)
.dw 0
mask: ; Bitmask for the current pixel
.db 0
xbyte: ; The byte column containing the pixel (basically X/8)
.db 0
dir:
.db 0
m_addr:
.dw 0
m_mask:
.db 0 ;0 means no mark
m_xbyte:
.db 0
m_dir:
.db 0
bool: ; bit 0=rule ;;;;;I dunno why but I had this and findpassage as the same thing before. I still haven''t taken all the "and 1" lines out from when I was testing rule...
.db 0
findpassage:
.db 0
color: ; The fill color (currently 0 or 1. If I implement grayscale it will be 0-3)
.db 1
icolor:
.db 0 ; The color of the starting fill point
.end
I wouldn't be surprised if it's something reeeeeally stupid. I'm new to ASM, so I'm sure I made multiple mistakes.
Thanks so much in advance!
-Zippy Dee
EDIT: I edited the code to what I have now. The "Paint" routine is never called, and I'm not sure why...