-
Notifications
You must be signed in to change notification settings - Fork 0
/
8 - playfield color.dasm
278 lines (252 loc) · 6.01 KB
/
8 - playfield color.dasm
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
; Playfield Color
; A sign of a true VCS master coder is granular color control of the playfield. Examples are rare, but
; a few amazing developers have been able to write code to change the playfield color during the scanline rendering code
; without impacting performance or drawing, and while lining up with the playfield. I however am not a VCS coder
; nor do I aim to be one. We will do soemthing far less ambitious: change colors for groups of lines.
;
; We do this exactly the way you'd think we would. Add another lookup table for color. Read and buffer the color
; apply it at HBlank. You might think we could just apply color when we load it but its mid scanline, we have to
; suck up the extra byte of RAM and buffer it.
;
; I made some adjustments to overscan and line count. I brought it down to 190 with 20x19. More NTSC safe. Still,
; you'll notice we've got something wrong with our rendering. Its looping back around. The bottom of the screen
; is stomping on the top. We're at 190 lines so I'm not sure why that would be. But, its not a huge deal we'll figure it out later
processor 6502
include vcs.h
include macro.h
org $F000
;Set up some memory locations we'll use
ScanlineCount = $80
VBlankTimer = $81
OverscanTimer = $82
;Our index in the data table
PlayFieldYIndex = $83
;How many lines we should debounce rendering
PlayFieldLineSkip = $84
;We buffer and then display on the next scanline, like sprites, to save draw cycles
PlayFieldLineBuffer0 = $85
PlayFieldLineBuffer1 = $86
PlayFieldLineBuffer2 = $87
PlayFieldColorBuffer = $88
Start
;From macro.h gets memory and other stuff initialized
CLEAN_START
;Set background color
lda #$04
sta COLUBK
;Mirror the PF
lda #%1111
sta CTRLPF
;Set some variables
lda #190
sta ScanlineCount
lda #43
sta VBlankTimer
lda #35
sta OverscanTimer
lda #0
sta PlayFieldYIndex
lda #0
sta PlayFieldLineSkip
lda #0
sta PlayFieldLineBuffer0
lda #0
sta PlayFieldLineBuffer1
lda #0
sta PlayFieldLineBuffer2
lda #0
sta PlayFieldColorBuffer
;Tell the TV we're starting a new frame
VSync
;Wait until the electron hun is back to origin
sta WSYNC
;Enable VSYNC
lda #%0010
sta VSYNC
;Wait for 3 scanlines. This is a hardware thing and we have to do it
sta WSYNC
sta WSYNC
sta WSYNC
;Disable VSYNC
lda #0
sta VSYNC
;We have 37 scanlines of VBlank time before we start drawing scan lines
;This is a great place to do logic. The tightest code would cycle count here
;but we use a timer instead. Not as tight, but still good.
VBlankStart
;Enable VBlank
lda #%0010
sta VBLANK
;Set the timer
lda VBlankTimer
sta TIM64T
VBlankLogic
;Do vblank stuff here
ldx #0
stx PlayFieldYIndex
VBlankEnd
;Check the timer
lda INTIM
;If its not zero loop
bne VBlankEnd
;Disable VBlank
lda #0
sta VBLANK
;Wait until the electron gun is back at origin
sta WSYNC
;Load the count of scanlines into the Y register
ldy ScanlineCount
;There's a little bit of time before each scanline where you can do some logic
;Only around 10-15 CPU cycles or so, but still something
HBlank
;Do pre-line stuff here
sta WSYNC
;Write the playfield buffers out to the playfield registers
;This seems like a LOT of cycles to have to sacrifice every HBlank - 18 I reckon
lda PlayFieldColorBuffer
sta COLUPF
lda PlayFieldLineBuffer0
sta PF0
lda PlayFieldLineBuffer1
sta PF1
lda PlayFieldLineBuffer2
sta PF2
DrawScanLine
;Our deferred playfield renderer
;We are using a 20x20 playfield to make things easier
;To do that we need to render the same playfield line for 10 scanlines
;So we render line 0 from the playfield for 10 lines, then line 1 for 10 lines
;Giving us an effective resolution of 200 pixels, about what we've got in scanlines
;This code debounces via PlayFieldSkip, counting down to 0, and then renders
;the current playfield lines into the buffers. So, this code is expensive but most of it
;only runs every 10 lines AND the beam isn't waiting on it because we're writing to a buffer
DrawPlayfieldLine
ldx PlayFieldLineSkip
bne EndPlayfieldLine
ldx #10
stx PlayFieldLineSkip
ldx PlayFieldYIndex
lda PFC,X
sta PlayFieldColorBuffer
lda PF0A,X
sta PlayFieldLineBuffer0 ;PF0
lda PF1A,X
sta PlayFieldLineBuffer1 ;PF1
lda PF2A,X
sta PlayFieldLineBuffer2 ;PF2
inx
stx PlayFieldYIndex
EndPlayfieldLine
dec PlayFieldLineSkip
;Do scanline stuff here
FinishScanline
;Reduce our scanline counter
dey
;If we're not on scanline 0 loop back to HBlank
bne HBlank
;We've drawn all our scanlines and now we have around 30 scanlines
;worth of overscan. Another great place for logic
OverscanStart
;Finish our last line
sta WSYNC
;Enable VBlank
lda #%0010
sta VBLANK
;Set up the timer
lda OverscanTimer
sta TIM64T
OverscanLogic
OverscanEnd
;sta WSYNC
;Check the timer
lda INTIM
;If the timer isn't 0 loop
bne OverscanEnd
;Disable VBlank
lda #0
sta VBLANK
;Loop back to vsync
jmp VSync
PF0A
.byte %11110000
.byte %00010000
.byte %00010000
.byte %00010000
.byte %00010000
.byte %00010000
.byte %00010000
.byte %00010000
.byte %00010000
.byte %00010000
.byte %00010000
.byte %00010000
.byte %00010000
.byte %11010000
.byte %11010000
.byte %11010000
.byte %00010000
.byte %00010000
.byte %11110000
PF1A
.byte %11111111
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00110000
.byte %00110000
.byte %00110000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %11111111
PF2A
.byte %11111111
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %11000000
.byte %11000000
.byte %11000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %11111111
PFC
.byte $AA
.byte $A8
.byte $A4
.byte $A2
.byte $A0
.byte $AA
.byte $A8
.byte $A4
.byte $A2
.byte $A0
.byte $AA
.byte $A8
.byte $A4
.byte $A2
.byte $A0
.byte $AA
.byte $A8
.byte $A4
.byte $A0
org $FFFC
.word Start
.word Start