-
Notifications
You must be signed in to change notification settings - Fork 0
/
4 - sprite buffering.dasm
204 lines (168 loc) · 3.67 KB
/
4 - sprite buffering.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
; Scan Line Buffering
; I am again leaning on a great tutorial https://alienbill.com/2600/101/07buffer.html
; I noticed in my previous example that weird stuff happened to the sprite at the left edge of the screen. If you got close to the left
; edge the player sprite would partially and then fully disappear. I figured it had to be a timing problem, that I had too much going on
; for the sprite to fit in HBlank. I did some cycle counting and yeah, for sure. I then found the tutorial above.
; I read the intro of that page and then came up with my own implementation before looking at his. Works great. So I guess buffering
; is going to be a big deal
processor 6502
include vcs.h
include macro.h
org $F000
ScanlineCount = $80
VBlankTimer = $81
OverscanTimer = $82
PlayerSpriteY = $83
SpriteSliceToDraw = $84
InputUp = $85
InputDown = $86
InputLeft = $87
InputRight = $88
HorizMotionLeft = $89
HorizMotionRight = $90
PlayerSpriteBuffer = $91
Start
CLEAN_START
lda #$AA
sta COLUBK
lda #$34
sta COLUP0
lda #192
sta ScanlineCount
lda #43
sta VBlankTimer
lda #35
sta OverscanTimer
lda #75
sta PlayerSpriteY
lda #0
sta SpriteSliceToDraw
lda #%00100000
sta InputUp
lda #%00010000
sta InputDown
lda #%01000000
sta InputLeft
lda #%10000000
sta InputRight
lda #$10
sta HorizMotionLeft
lda #$F0
sta HorizMotionRight
lda #0
sta PlayerSpriteBuffer
VSync
sta WSYNC
lda #%0010
sta VSYNC
sta WSYNC
sta WSYNC
sta WSYNC
lda #0
sta VSYNC
VBlankStart
lda #%0010
sta VBLANK
lda VBlankTimer
sta TIM64T
VBlankLogic
;Do vblank stuff here
ldy ScanlineCount
;Set the number of lines of player sprite to draw to 0
;this ensures we skip drawing until the right time
lda #0
sta SpriteSliceToDraw
lda InputUp
bit SWCHA
bne CheckMoveDown
dec PlayerSpriteY
CheckMoveDown
lda InputDown
bit SWCHA
bne CheckMoveLeft
inc PlayerSpriteY
CheckMoveLeft
;We'll use register X for our horizontal movement speed
;Default horizontal speed is 0
ldx #0
lda InputLeft
bit SWCHA
bne CheckMoveRight
ldx HorizMotionLeft
CheckMoveRight
lda InputRight
bit SWCHA
bne SetHorizontalMovement
ldx HorizMotionRight
SetHorizontalMovement
stx HMP0
VBlankEnd
lda INTIM
bne VBlankEnd
lda #0
sta VBLANK
sta WSYNC
sta HMOVE
HBlank
;Do pre-line stuff here
sta WSYNC
DrawAndClearPlayerBuffer
;Draw the player buffer to the screen and then clear it out
;This is our only draw call, so this is the only thing that would
;add any cycle overhead to the currently rendering line
lda PlayerSpriteBuffer
sta GRP0
lda #0
sta PlayerSpriteBuffer
;Now we have a whole glorious scanline worth of CPU to do whatever we want for the next line!
DrawScanLine
CheckPlayerOnScanline
;See if this is the line we should draw at
cpy PlayerSpriteY
;If it isn't the line we should start drawing the player sprite at move on
bne BufferPlayerSprite
;If it is the line we should start drawing at set the lines of sprite to draw to 8
lda #8
sta SpriteSliceToDraw
BufferPlayerSprite
;Load the sprite line count
ldx SpriteSliceToDraw
cpx #0
;If the line count is 0 there's nothing to draw so skip drawing
beq SkipPlayerSprite
;Load the sprite line and buffer it
lda SpriteFace-1,X
sta PlayerSpriteBuffer
;Decrement and store the sprite draw line
dex
stx SpriteSliceToDraw
SkipPlayerSprite
FinishScanline
dey
bne HBlank
OverscanStart
lda #%0010
sta VBLANK
lda OverscanTimer
sta TIM64T
OverscanLogic
;Do overscan stuff here
OverscanEnd
lda INTIM
bne OverscanEnd
lda #0
sta VBLANK
sta WSYNC
jmp VSync
SpriteFace
.byte %01111110
.byte %11000011
.byte %10111101
.byte %11111111
.byte %10011001
.byte %10011001
.byte %11111111
.byte %01111110
org $FFFC
.word Start
.word Start