0 Members and 1 Guest are viewing this topic.
This algorithm:http://en.wikipedia.org/wiki/Flood_fill#Fixed_memory_method_.28right-hand_fill_method.29RULE = rightMARK = nullMARKDIR = nullFINDPASSAGE = false-----if 4 bounds painted paint cur stopelse if 3 bounds painted MARK = null FINDPASSAGE = false RULE = right paint cur move to open bound //####################### else if 2 bounds painted if MARK == null && RULE == right MARK = cur MARKDIR = dir FINDPASSAGE = false else if cur == MARK if dir == MARKDIR MARK = null else RULE = left //.....this stuff here is the "oh no I'm in a loop" stuff. dir = MARKDIR MARK = null FINDPASSAGE = false if MARK == null && RULE == right paint cur move based on RULE //after moving //set "dir" to the next direction //according to RULE (right hand rule or left hand rule)//###################### else if 1 bound painted if RULE == left //then we're in a loop, and this triggers the second stage FINDPASSAGE = true else if both opposite corners are open && MARK == null paint cur move base on RULEelse if 0 bounds painted if RULE == left FINDPASSAGE = true paint cur? move anywhere :P ======================================== How do you follow the right hand rule? Which is next? (Key: _ = empty pixel, # = filled pixel, 0 = current position and direction)if the corner is filled, just move forward ___ _0_ _##...becomes... ___ __0 _##but if the corner is empty, there are two possible ways to move ___ _0_ _#_first possibility ___ _#0 If the current pixel is painted before moving, move here _#_second possibility ___ ___ if the pixel is NOT painted before moving, move around the corner to the next edge _#0 because just going straight would make it now have no borders...
#include "ti83plus.inc"#define progStart $9D95.org progStart-2.db $BB,$6D;these are all flags used in the "bools" address. I didn't use one of the AsmFlags addresses, because that might be in use by whatever program uses this routine.bool_color .equ 0 ;unused for now. only fills black.bool_color2 .equ 1 ;unused for nowbool_rule .equ 2 ;set=right-hand rule,reset=left-hand rulebool_findpath .equ 3 ;set if bool_filled .equ 4 ;whether or not the current pixel has been filled. This is set when paintCur is calledbool_mark .equ 5 ;if reset, mark is null. otherwise, mark is in use. Used in the main loop_init: ld (save_iy),iy ld iy,bools ld hl,(cx) call getPixel and (hl) ret nz ;quit if the current pixel is already filled_main: ;main program loop. call safecopy ;safecopy exists for testing purposes only. res bool_filled,(iy) ld hl,(cx) call getEdgePixels ld (bounds), a ;ld (PlotSScreen),a call SumNibBits ld b,a djnz _not1_1_bound: bit bool_rule,(iy) jr nz,+_ set bool_findpath,(iy) jr ++__: bit bool_mark,(iy) jr nz,+_ ld hl,(OppCornMask_LUT) ld d,0 ld e,(iy+off_cdir) add hl,de ld a,(bounds) and (hl) jr nz,+_ call paintCur_: call MoveByRule_not1: djnz _not2_2_bound: ;if MARK == null && RULE == right bit bool_mark,(iy) jr nz,_2elseif ;MARK = cur ld hl,(cx) ld (mx),hl ;MARKDIR = dir ld a,(cdir) ld (mdir),a ;FINDPASSAGE = false res bool_findpath,(iy) set bool_mark,(iy) ;mark is not null_2elseif: ;else if cur == MARK ld hl,(cx) ld a,(mx) cp l jr nz,_2if ;if dir == MARKDIR ld a,(my) cp h jr nz,_2if ld a,(cdir) ld hl,mdir cp (hl) jr nz,_2else ;MARK = null res bool_mark,(iy) jr _2if_2else: ;else ;RULE = left res bool_rule,(iy) ;dir = MARKDIR ld a,(hl) ld (cdir),a ;MARK = null res bool_mark,(iy) ;FINDPASSAGE = false res bool_findpath,(iy) call TurnByRule_2if: ;if MARK == null && RULE == right bit bool_mark,(iy) jr nz,_move bit bool_rule,(iy) jr z,_move ;paint cur call paintCur ;move based on RULE_move: call MoveByRule jp _main_not2: djnz _not3_3_bound: res bool_mark,(iy) res bool_findpath,(iy) set bool_rule,(iy) call TurnByRule call paintCur call MoveByRule jp _main_not3: djnz _not4_4_bound: ;4 bound call paintCur ld iy,(save_iy) ret ;;QUIT_not4:_0_bound: ld hl,cdir ld (hl),0 call paintCur inc hl inc (hl) ;increase cx jp _mainbools: .db 0 | (1 << bool_color) | (1 << bool_color2) | (1 << bool_rule)cdir: ;current dir. 0=down, 1=left, 2=up, 3=right .db 0cx: ;current x. Set to 10 for testing .db 10cy: ;current y. Set to 10 for testing .db 10mdir: ;mark dir .db 0mx: ;mark x .db 0my: ;mark y .db 0bounds: ;holds the bound data .db 0 ;bit order: FAHCGDBE ;ABC ;here's how that order lines up with surrounding pixels ;DxE ;FGHsave_iy: .dw 0;I reference these using IY+* to load values into other registers. IY points to bools.;Not all of these are used. In fact, I think only off_cdir is used.off_cx .equ cx-boolsoff_cy .equ cy-boolsoff_cdir .equ cdir-boolsoff_mx .equ mx-boolsoff_my .equ my-boolsoff_mdir .equ mdir-boolsoff_bounds .equ bounds-bools ;masks for the pixel straight forward, based on dir .db %00001000, %00000100, %00000010, %00000001FrontByDirMask_LUT: ; %FAHCGDBE %FAHCGDBE %FAHCGDBE %FAHCGDBE .db %00001000, %00000100, %00000010, %00000001 .db %00001000, %00000100, %00000010, %00000001 OppCornMask_LUT: ;masks for the two opposite corners from the edges corresponding with FrontByDirMask_LUT ; %FAHCGDBE %FAHCGDBE %FAHCGDBE %FAHCGDBE .db %01010000, %00110000, %10100000, %1100000 FrontCornRightRuleMask_LUT: ;masks for corners forward/right, based on cdir ; %FAHCGDBE %FAHCGDBE %FAHCGDBE %FAHCGDBE .db %10000000, %0100000, %00010000, %0010000 FrontCornLeftRuleMask_LUT: ;masks for corners forward/right, based on cdir ; %FAHCGDBE %FAHCGDBE %FAHCGDBE %FAHCGDBE .db %00100000, %1000000, %01000000, %00010000 .db 1DirMoveX_LUT: ;LUT for X offsets based on dir. Used in MoveByRule. .db 0,-1,0DirMoveY_LUT: .db 1,0,-1,0 MoveByRule: ;move based on the rule. (this immediately goes into TurnByRule) bit bool_filled,(iy) ld e,(iy+off_cdir) ld d,0 jr z,_moveforward bit bool_rule,(iy) ld b,d ld c,1 ld hl,FrontCornRightRuleMask_LUT jr z,+_ ld c,-1 ld hl,FrontCornLeftRuleMask_LUT_: ld e,(iy+off_cdir) ld d,b add hl,de ld a,(bounds) and (hl) jr nz,_moveforward ld hl,DirMoveX_LUT add hl,de add hl,bc ld a,(cx) add a,(hl) ld (cx),a inc hl inc hl inc hl ld a,(cy) add a,(hl) ld (cy),a_moveforward: ld hl,DirMoveX_LUT add hl,de ld a,(cx) add a,(hl) ld (cx),a inc hl inc hl inc hl ld a,(cy) add a,(hl) ld (cy),a TurnByRule: ;turn based on the rule. ld hl,FrontByDirMask_LUT ld d,0 ld e,(iy+off_cdir) add hl,de ld e,1 bit bool_rule,(iy) jr nz,+_ ld e,-1_: ld b,(iy+off_bounds) xor a ld c,a_frontloop: ;while front on, rotate opposite from rule ;check front ld a,b and (hl) jr z,_sideloop dec c sbc hl,de jr _frontloop_sideloopskip: inc c_sideloop: add hl,de ld a,b and (hl) jr z,_sideloopskip ld a,(cdir) dec e jr nz,_leftrotate add a,c and 3 ld (cdir),a ret_leftrotate: sub c and 3 ld (cdir),a ret SumNibBits: ;Thank you, Runer112, for this routine ;returns the sum of the lower 4 bits of A ;output: A = sum of bits ;destroys HL and %00001111 ld hl,SumNibBits_LUT add a,l ld l,a ld a,(hl) ret nc inc h ld a,(hl) retSumNibBits_LUT: .db 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 ;.db 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5 getPixelByte: ;standard first part of a getPixel routine. Retrieves the byte of the pixel in HL ld a,h ld h,0 ld d,h ld e,l add hl,hl add hl,de add hl,hl add hl,hl ld e,a srl e srl e srl e add hl,de ld de,PlotSScreen add hl,de ret getPixel: ;just a getPixel routine. Nothing to see here. call getPixelByte and 7 ld b,a ld a,$80 ret z rrca djnz $-1 ret paintCur: ;fills the current pixel (cx,cy) and sets the "bool_filled" flag ld hl,(cx) call getPixel or (hl) ld (hl),a set bool_filled,(iy) ret getEdgePixels: ;get all 8 surrounding pixels and put them into A in the order specified at the "bounds" label. push hl ;save x,y for checking offset later call getPixelByte push hl pop ix and 7 jr z,_specLeft cp 7 jr z,_specRight dec a ;get the surrounding bits into the 3 msb of C, D, and E ld b,a ld d,(ix-12) ld e,(ix+12) ld a,(hl) jp z,CheckOffScreen ld c,b ld a,e rrca djnz $-1 ld e,a ld b,c ld a,d rrca djnz $-1 ld d,a ld b,c ld a,(hl) rrca djnz $-1 ;d=ABC00000;a=DXE00000; e=FGH00000 ld c,a jp CheckOffScreen_specLeft: ;special-case for left-side overflow ld d,(ix-12) ld a,(ix-13) rra rr d ld e,(ix+12) ld a,(ix+11) rra rr e ld c,(hl) dec hl ld a,(hl) rra rr c jp CheckOffScreen_specRight: ;special-case for right-side overflow ld d,(ix-11) ld a,(ix-12) rl d rra rra rra ld e,(ix+13) ld a,(ix+12) rl e rra rra rra ld a,(hl) inc hl ld c,(hl) rl c rra rra rra ld c,a CheckOffScreen: pop hl ;recall x,y ld a,l dec a cp 62 jr c,_testx jr z,_fixtop jr _fixbtm_fixtop: ld e,%11100000 jr _testx_fixbtm: ld d,%11100000_testx: ld a,h dec a cp 94 jr c,EdgePixelCombine jr z,_fixright jr _fixleft_fixright: set 5,c set 5,d set 5,e jr EdgePixelCombine_fixleft: set 7,c set 7,d set 7,eEdgePixelCombine: ;Thank you, Runer112, for this routine ;d=ABC00000 ;c=DXE00000 ;e=FGH00000 ld a,c xor d and %10111111 xor d ;a=DBE00000 rlca rlca ;a=00DBE000 xor e and %10111111 xor e ;a=0GDBE000 rrca rrca ;a=000GDBE0 xor d and %01011111 xor d ;a=ABCGDBE0 rrca ;a=0ABCGDBE xor e and %01011111 xor e ;a=FAHCGDBE ret ;-----> Copy the gbuf to the screen, guaranteed ;Input: nothing;Output:graph buffer is copied to the screen, no matter the speed settings;;in f,(c) is an unofficial instruction.;It must be noted that you cannot specify any other register. Only f works.;You may have to add it in order for the routine to work.;if addinstr doesn't work, you may manually insert the opcodes .db 0EDh,070h .addinstr IN F,(C) 70ED 2 NOP 1SafeCopy: ;di ;DI is only required if an interrupt will alter the lcd. ld hl,PlotSScreen ;This can be commented out or another entry placed after it ;so the buffer can be provided by option. ld c,$10 ld a,$80setrow: in f,(c) jp m,setrow out ($10),a ld de,12 ld a,$20col: in f,(c) jp m,col out ($10),a push af ld b,64row: ld a,(hl)rowwait: in f,(c) jp m,rowwait out ($11),a add hl,de djnz row pop af dec h dec h dec h inc hl inc a cp $2c jp nz,col ret