001 .proc evalMetaSprites
002
003 ; metasprite Object in RAM format, one record:
004 ; should be organized as one array of each element
005 ; (example, if there are $10 records, the first $10 bytes are all Ypos
006
007 ; Ypos : byte
008 ; Attribute modifier : byte
009
010 ; vhbcxypp --- Attribute modifier byte (always)
011 ; ||||||||
012 ; ||||||++---- Sprite Colour toggle: EOR with metatile attribs
013 ; |||||+------ Y clipping bit
014 ; ||||+------- X clipping bit
015 ; |||+-------- Clipping or wrap : 0: clip sprites at screen edge, 1: allow wrap
016 ; ||+--------- Background priority bit
017 ; |+---------- Horizontal flipping toggle: EOR metatile attribs
018 ; +----------- Vertical flipping toggle: EOR metatile attribs
019
020 ; Metatile number : byte
021 ; Xpos : byte
022
023 ; --------------------------------------------------------------------------------------------
024
025 ; metasprite format to define metasprite in ROM data:
026
027 ; xxxxxxxx --- Sprite X coordinate (if required)
028 ; yyyyyyyy --- Sprite Y coordinate (if required)
029
030 ; tttttttt --- Tile number (if required)
031
032 ; vhytxxpp --- Attribute byte (always)
033 ; ||||||||
034 ; ||||||++---- Sprite Colour
035 ; |||||+------ Tile number of next sprite (0: required, 1 : Tile number of this sprite + 1, skip if X control was LF)
036 ; ||||+------- Y position of next sprite (0 : required, 0 : unchanged)
037 ; ||++-------- X position of next sprite (01 : required, 00 : X pos of this sprite + 8,
038 ; || 10 : X pos of the first sprite, Y + 8 (CR/LF), 11 : Escape code for last sprite)
039 ; |+---------- Horizontal flipping
040 ; +----------- Vertical flipping
041
042 ; static
043 declareBSS
044 OAMoffset .byte
045 endBSS
046
047 ; temp use zeropage:
048
049 locals
050 sprModifier .byte
051 sprAttrib .byte
052 sprTile .byte
053 sprXpos .byte
054 sprYpos .byte
055
056 sprXbit8 .byte
057 sprYbit8 .byte
058
059 metaspritePointerLo .byte
060 metaspritePointerHi .byte
061
062 sprAdder .byte
063 sprXposStart .byte
064 mSpriteOffset .byte
065 endlocals
066
067 metaspritePointer = local::metaspritePointerLo
068
069 ; init:
070 ldy #::METASPRITE_COUNT
071 sty local::mSpriteOffset
072
073
074 ; skip reserved sprites
075 if lda M::OAMoffset < #::OAM_ROTATION_START
076 lda #::OAM_ROTATION_START
077 endif
078
079 sta M::OAMoffset
080 sta local::sprAdder ; use as temp: save OAMoffset
081
082 DoNextmetasprite:
083
084
085 ; loop through all entries and skip those with att = $FF
086 ; jump to OAM rotation and leave if no more entries
087 ldx local::mSpriteOffset
088
089 repeat
090
091 if dex == negative
092 jmp clearRemainingOAM
093 endif
094
095 mb a, local::sprModifier := mSpriteMemory[ x ]::att ; load Attrib/meta data which is modifier for all
096
097 until tay : iny != zero ; same as: until mSpriteMemory[ x ]::att <> #$FF
098
099 stx local::mSpriteOffset
100
101 mb local::sprYpos := mSpriteMemory[ x ]::yPos
102 mb local::sprXpos := mSpriteMemory[ x ]::xPos
103 sta local::sprXposStart
104
105 mb a, x := mSpriteMemory[ x ]::mTile ; load metatile number
106
107 ; get metatile pointer
108 mb local::metaspritePointerLo := metaspriteNumbersLo[ x ]
109 mb local::metaspritePointerHi := metaspriteNumbersHi[ x ]
110
111 ; from here, Y indexes into ROM data
112 ; first data is Xwidth, Yheight, Tile, and Attribs/command byte
113
114 ldy #0
115
116 ; --------- process width:
117
118 bit local::sprModifier ; copy b7 and b6 into N, V
119
120 if V set ; H flipping:
121 mb local::sprXpos := local::sprXpos + (metaspritePointer)[ y ] ; add width ( is stored 8 less than actual )
122 sta local::sprXposStart
123 if carry set
124 mb local::sprModifier := local::sprModifier ^ # ( 1 << OFFSCREEN_XBIT )
125 endif
126 endif
127
128 iny
129
130 ; --------- end width
131 ; --------- process height:
132
133 if lda local::sprModifier == N set ; V flipping:
134 mb local::sprYpos := local::sprYpos + (metaspritePointer)[ y ] ; add height ( is stored 8 less than actual )
135 lda local::sprModifier
136 if carry set
137 mb a := a ^ #( 1 << OFFSCREEN_YBIT )
138 endif
139 endif
140
141 iny
142
143 ; --------- end height:
144
145 ; set offscreen bits:
146 sta local::sprModifier
147
148 mb local::sprYbit8 := a >> 2 ; put Y 'bit8' into bit 0 local var (only bit0 matters)
149 mb local::sprXbit8 := a >> 1 ; put X 'bit8' into bit 0 local var (only bit0 matters)
150
151 ; ----------------
152
153 mb local::sprTile := (metaspritePointer)[ y ]
154 iny
155
156 ldx local::sprAdder ; X now has OAMoffset
157
158 DoNextTile:
159
160 mb local::sprAttrib := (metaspritePointer)[ y ] ; read attrib and flags
161 iny
162
163 ; if both offscreen bits are clear OR No clipping mode is on
164 if local::sprXbit8 | local::sprYbit8 >> 1 == carry clear || local::sprModifier & #%00010000
165
166 mb OAM_SHADOW[ x + 2] := local::sprAttrib & #%11000011 ^ local::sprModifier
167 mb OAM_SHADOW[ x + 3] := local::sprXpos
168 mb OAM_SHADOW[ x + 0] := local::sprYpos
169 mb OAM_SHADOW[ x + 1] := local::sprTile
170
171 if x := x + 4 == zero
172 ldx #::OAM_ROTATION_START
173 endif
174
175 endif
176
177 sec ; sec carry to end making reg A hold #8
178 mb a := local::sprAttrib & #$F0
179 rol
180 asl
181 asl ; test bit 3, 2 as C, N
182
183 ; if X MODIFIER value is 00 or 01:
184 if C clear
185 asl ; A will have #8
186 if C set ; X MODIFIER IS 01
187 mb a := (metaspritePointer)[ y ]
188 iny
189 clc
190 endif
191
192 ; HERE. either way, carry clear
193
194 if { flagSet local::sprModifier, 6 } ; if bit6 (h mirror)
195 ; negate adder
196 mb a := a ^ #$FF
197 sec
198 endif
199
200 sta local::sprAdder
201
202 mb local::sprXpos := a +c local::sprXpos
203
204 ror
205 if a ^ local::sprAdder == N set ; if carry and adder sign are different:
206 inc local::sprXbit8 ; toggle offscreen bit
207 endif
208
209 else
210 if N clear ; X MODIFIER IS 10 ; 9615 cycles
211
212 ; this idea takes the same # of cycles as the clearer code:
213 ; -------------------------------------------------------
214 ; asl ; reg A holds #8
215 ; and local::sprModifier
216 ; cmp #1 ; only bit8 could be set, copy it into C
217 ; rol local::sprXbit8
218
219 mb local::sprXbit8 := local::sprModifier >> 3
220 mb local::sprXpos := local::sprXposStart
221
222 lda #8
223 jmp Add8toYPos
224 endif
225 ; else: X MODIFIER IS 11:
226 stx local::sprAdder ; save OAM offset here
227 ;---------------
228 jmp DoNextmetasprite ; if = 0 then bail and do next RAm based metasprite
229
230 endif
231
232 ; -----------END X pos
233
234 ; ----------- Y pos
235
236 ; load Ypos? Skip all this if not 0
237 if ! local::sprAttrib & #%00001000
238
239 mb a := (metaspritePointer)[ y ]
240 iny
241
242 Add8toYPos: ; jump here if CR/LF code
243
244 clc
245 if flagSet local::sprModifier ; if bit7 (v mirror)
246 mb a := a ^ #$FF
247 sec
248 endif
249
250 sta local::sprAdder
251
252 mb local::sprYpos := a +c local::sprYpos
253
254 ror
255 if a ^ local::sprAdder == N set
256 inc local::sprYbit8
257 endif
258
259 endif
260 ; -----------END Y pos
261
262 ; -----------check tile:
263
264 ; BIT4: check if 0: load tile, else use next tile
265
266 inc local::sprTile ; inc by default
267
268 if ! local::sprAttrib & #%00000100
269 mb local::sprTile := (metaspritePointer)[ y ]
270 iny
271 endif
272
273 ; -------end tile processing
274
275 jmp DoNextTile
276
277 ; --------------------------------------------------------------------------------------------
278
279 clearRemainingOAM:
280
281 OAMnext = local::sprAdder ; alias
282
283 ; --------------------------------------------------------------------------------------------
284
285 ldx OAMnext ; x holds start of next blank spot
286
287 ; take away blank spaces from total slots if we wrapped
288 if OAMnext <= M::OAMoffset
289 mb a := OAMnext - #::OAM_ROTATION_START
290 endif
291
292 mb a := a - M::OAMoffset ; bytes used
293 mb a := a >> 2 ; slots used
294 sta OAMnext ; use as temp, since this value is in reg X
295
296 mb y := #(64 - ( ::OAM_ROTATION_START / 4 ) ) - OAMnext ; total avaliable slots MINUS slots used
297 lda #$FF
298
299 cpy #00
300 while not zero do
301
302 sta OAM_SHADOW, x
303 mb x := x + 4
304 if zero
305 ldx #::OAM_ROTATION_START
306 endif
307 dey
308 endwhile
309
310 mb M::OAMoffset := M::OAMoffset + #::OAM_ROTATION_AMOUNT
311
312 rts
313
314 .endproc
No comments:
Post a Comment