-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path2 - drawing (a different way).dasm
151 lines (130 loc) · 3.77 KB
/
2 - drawing (a different way).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
; Drawing the Player 0 sprite a different way
; Part of the adjustment of stepping into this almost 50 year old system is my normal conceptions of
; what does and does not constitute good coding practice doesn't apply. The conditionality of the
; previous example bothers me because reducing conditionality is one of my guiding lights as a
; developer. I can see a way to make the system less conditional, but at the cost of another byte of
; memory. Now in modern times with infinite resources that's a no brainer, but on the VCS I'm not so
; sure. I think a VCS dev would have wrote the harder to reason about code and conserved the RAM
; because they weren't writing living code bases. The code just needed to fit on the cartridge and
; be done on the right date. Nothing else mattered. No one else would ever read it or use it.
;
; So, what follows is an alternate take on the last example where I try to apply what feels like
; better coding practice from a 2021 perspective. I reduce the conditionality of the code, and I
; reduce the duplicated writes to the player 0 register. I do this by adding an additional line to
; the sprite that is blank. The way the TIA chip works in the VCS is it will draw whatever was on the previous
; scanline unless you tell it to do otherwise, so we have to always set the player sprite register to 0
; on lines we're not drawing on, hence:
; lda #0
; sta GRP0
; In this example we simply pad the sprite with an extra line 0 that is always 0. We set our sprite slice
; to draw to 0 in HBlank so we always draw that 0 line. If the current scanline is our player y we set
; the valye of slice to draw to 8 (height) and then decrement. Single draw call, reduced conditionality,
; easier to reason about, but takes up more memory. Better or worse? I don't know! I think its probably
; worse for VCS code because if we do this for every sprite we lose a byte of memory with every sprite. If
; we have 8 sprites we've lost 8 bytes! That's over 6% of total system RAM!
processor 6502
include vcs.h
include macro.h
org $F000
ScanlineCount = $80
VBlankTimer = $81
OverscanTimer = $82
PlayerSpriteY = $83;
SpriteSliceToDraw = $84;
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
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
VBlankEnd
lda INTIM
bne VBlankEnd
lda #0
sta VBLANK
sta WSYNC
HBlank
;Do pre-line stuff here
sta WSYNC
DrawScanLine
SetPlayerSpriteDrawOffset
;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 DrawPlayerSprite
;If it is the line we should start drawing at set the lines of sprite to draw to 8
lda #8
sta SpriteSliceToDraw
DrawPlayerSprite
;Load the sprite line count
ldx SpriteSliceToDraw
;Load the sprite line to draw and draw it
lda SpriteFace,X
sta GRP0
;Decrement and store the sprite draw line
cpx #0
beq AfterPlayerSprite
dex
stx SpriteSliceToDraw
AfterPlayerSprite
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 %00000000
.byte %01111110
.byte %11000011
.byte %10111101
.byte %11111111
.byte %10011001
.byte %10011001
.byte %11111111
.byte %01111110
org $FFFC
.word Start
.word Start