-
Notifications
You must be signed in to change notification settings - Fork 0
/
dirty_tiles.z80
186 lines (155 loc) · 6.51 KB
/
dirty_tiles.z80
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
; data structures and functions for maintaining a draw-list of bitmaps to draw.
; One main usecase is for marking tiles that need to be redrawn
; These tiles correspond to non-moving locations in the grid- needing to be
; redrawn due to the cursor passing over them, or an overlay being drawn
; over them, etc.
; Really it's just a variable-length array of tuples (screen ptr, bitmap ptr)
; One helper function exists to push data into that array via the xy coords of a
; tile (so, by looking up into the tiles data, we obtain the bitmap ptr, and we
; transform the grid xy into the screen ptr)
; Then there's a draw function, which simple iterates over and draws bitmaps
; for each one (and clears the draw-list after drawing them all)
END_OF_LIST: equ 255
dirty_tiles: defb END_OF_LIST
defs 10*8+1-2 ; shouldn't need anything like this much
defb END_OF_LIST
dirty_tiles_tail: defw dirty_tiles ; pointer to address from dirty_tails or up
draw_list: defb END_OF_LIST
defs 10*8*4+1-2 ; shouldn't need anything like this much
defb END_OF_LIST
draw_list_tail: defw draw_list ; pointer to address from draw_list or up
clear_dirty_tiles_list:
; modifies: HL
ld hl, dirty_tiles
ld (hl), END_OF_LIST ; end marker
ld (dirty_tiles_tail), hl
ret
clear_draw_list:
; modifies: HL
ld hl, draw_list
ld (hl), END_OF_LIST ; end marker
ld (draw_list_tail), hl
ret
push_dirty_tile:
; add an (xy) tile grid coord pair to the dirty list
; (this will be transformed to screen+sprite ptrs in a second step)
; a = (xy) tile data to push
; modifies: HL
ld hl, (dirty_tiles_tail)
ld (hl), a
inc hl
ld (hl), END_OF_LIST ; end marker
ld (dirty_tiles_tail), hl
ret
push_draw_list_bc_de:
; push the sprite ptr (in bc) and the screen ptr (in de)
; to the draw list
; modifies: HL
ld hl, (draw_list_tail)
ld (hl), b
inc hl
ld (hl), c
inc hl
ld (hl), d
inc hl
ld (hl), e
inc hl
ld (hl), END_OF_LIST
ld (draw_list_tail), hl
ret
transform_dirty_to_draw_list:
; step through list of dirty tile (xy) coords
; and determine what to draw at what screen location
; NB this only handles the STATIONARY tiles
; We will need a separate routine for drawing falling or sliding tiles
ld hl, dirty_tiles
@next:
ld a, (hl)
; is it end marker?
cp END_OF_LIST
jr z, @+end
inc hl
push hl
; a = YYYYxxxx
; for screen: multiply both x and y by 8 (and add GRID_X_OFFSET in x direction)
; and put into de
; (reuse helper function "grid_xy_in_C_to_screen_de")
; for tiles: a is (conveniently) already the low byte offset into table
; so we can just put a into c (since bc is aligned to 256-bytes)
ld c, a ; used for bc address AND ALSO used as a backup of a that we need later
; check : IS IT FALLING? or on a slider? if so, do NOT render it now
ld b, tiles_flags / 256
ld a, (bc)
and IS_FALLING_MASK + IS_SLIDER_MASK
jr nz, @falling_dirty ; if FALLING bit is set, treat as a blank tile for redraw
; get screen ptr in de
call grid_xy_in_C_to_screen_de
; get sprite ptr in bc
@draw_tile_anyway:
inc b ; point to tiles
ld a, (bc) ; the actual tile to draw
; multiply a by 128 to get offset into bitmap data
ld c, 0
sra a ; shift lowest bit of a into carry
rr c ; shift carry into c
add a, tiles_bitmaps/256
ld b,a
call push_draw_list_bc_de
pop hl
jr @-next
@falling_dirty:
call grid_xy_in_C_to_screen_de
; determine how many pixels rows below top left grid-aligned we need to draw at
ld a, (bc)
and 15 ; a = 0000pppp where p = number of pixel rows offset
; if EXACTLY ZERO then we should actually just draw the real tile (rather than a blank)
jr z, @draw_tile_anyway
; modify DE accordingly: multiply a by 128 and add to E with overflow to D
; but really that just means flip the top bit of E if A is odd; and
; add the remaining bits to D
srl a
jr nc, @+nocarry
set 7, e
@nocarry:
add d
ld d, a
; screen ptr now in de
; get sprite ptr in bc
; we want bitmap #0 = the 'blank' bitmap
; which is therefore just what tiles_bitmaps+0 points to
; TODO if we have background bitmaps, this needs changing!
ld bc, tiles_bitmaps
call push_draw_list_bc_de
pop hl
jr @-next
@end:
; FIXME - should just inline
call clear_dirty_tiles_list
ret
render_draw_list:
ld hl, draw_list
@_next:
ld a, (hl)
cp END_OF_LIST
jr z, @+_end
ld b, a
inc hl
ld c, (hl)
inc hl
ld d, (hl)
inc hl
ld e, (hl)
inc hl
; we're now going to put bc into hl (and preserve hl first)
push hl
; now put bc into hl
push bc
pop hl
call draw_bitmap_16x16_hl_at_de
; and restore the original hl
; TODO optimize this - see if using IX would save cycles compared to push/pop?
pop hl
jr @-_next
@_end:
call clear_draw_list
ret