;;; Subroutine: drunkwalk ;;; Spawn a particle, walk it randomly until it's adjacent to a set ;;; pixel, then draw it. If it goes out of bounds, start over (spawn ;;; another). ;;; This is the innermost loop, so it should be as optimized as ;;; possible. ; Here be self-modifying code. All the 'cpx #0' and 'cpy #0' get ; their operands modified by set_limits. ; BEWARE! ; Y and X are backwards: Y holds the X coordinate, and X holds the ; Y coordinate. Has to be, because there's no (zpind),x addressing ; mode. ; TODO: Fix the cycle counts. I did them from my years-old memory, and ; I got at least one wrong, after looking it up again. drunkwalk: oob: ldy RANDOM ; spawn a new particle lda (spawn_x),y sta cursor_x lda (spawn_y),y sta cursor_y tax ldy cursor_x lda lineaddrs_l,x ; 5 sta pixptr ; 3 lda lineaddrs_h,x ; 5 sta pixptr+1 ; 3 move_pixel: bit RANDOM ; 4 ; use top 2 bits (probably more random, definitely faster) bmi lr ; 3/4 bvc down ; 3/4 up: dex ; 2 ; N=1 V=1 up selfmod_ymin = * + 1 cpx #0 ; 2 beq oob ; 3 stx cursor_y jmp check_lru down: inx ; 2 ; N=1 V=0 down selfmod_ymax = * + 1 cpx #0 ; 2 beq oob ; 3 stx cursor_y jmp check_lrd lr: bvc right ; 3/4 left: dey ; 3 ; N=0 V=1 left selfmod_xmin = * + 1 cpy #0 ; 2 beq oob ; 3 sty cursor_x ; check left neighbor (we just vacated the right one) dey lda (pixptr),y bne stick iny jmp check_ud ; 3 ; still have to check Y (up/down) neighbors. right: iny ; 3 ; N=0 V=0 right selfmod_xmax = * + 1 cpy #0 ; 2 beq oob ; 3 sty cursor_x ; check right neighbor (we just vacated the left one) iny lda (pixptr),y bne stick dey ; fall through to check_ud check_ud: ; check up neighbor lda lineaddrs_l-1,x sta pixptr2 lda lineaddrs_h-1,x sta pixptr2+1 lda (pixptr2),y bne stick ; check down neighbor lda lineaddrs_l+1,x sta pixptr2 lda lineaddrs_h+1,x sta pixptr2+1 lda (pixptr2),y bne stick jmp move_pixel ; pixel didn't stick, move it again. check_lru: ; pixel's Y coord changed, must update pointer. lda lineaddrs_l,x ; 5 sta pixptr ; 3 lda lineaddrs_h,x ; 5 sta pixptr+1 ; 3 ; check left neighbor dey lda (pixptr),y bne stick iny ; check right neighbor iny lda (pixptr),y bne stick dey ; check up neighbor lda lineaddrs_l-1,x sta pixptr2 lda lineaddrs_h-1,x sta pixptr2+1 lda (pixptr2),y bne stick jmp move_pixel ; pixel didn't stick, move it again. check_lrd: ; pixel's Y coord changed, must update pointer. lda lineaddrs_l,x ; 5 sta pixptr ; 3 lda lineaddrs_h,x ; 5 sta pixptr+1 ; 3 ; check left neighbor dey lda (pixptr),y bne stick iny ; check right neighbor iny lda (pixptr),y bne stick dey ; check down neighbor lda lineaddrs_l+1,x sta pixptr2 lda lineaddrs_h+1,x sta pixptr2+1 lda (pixptr2),y bne stick jmp move_pixel ; pixel didn't stick, move it again. stick: ; pixel stuck next to an existing pixel, draw it and return. ldx cursor_y lda lineaddrs_l,x sta pixptr lda lineaddrs_h,x sta pixptr+1 ldy cursor_x lda #1 sta (pixptr),y rts