1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
;;; 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
|