Wednesday, March 27, 2013

Updated MetaSprite Code (again)

001 002 .proc evalMetaSprites 003 004 ; metasprite Object in RAM format, one record: 005 ; should be organized as one array of each element 006 ; (example, if there are $10 records, the first $10 bytes are all Ypos 007 008 ; Ypos : byte 009 ; Attribute modifier : byte 010 011 ; vhbcxypp --- Attribute modifier byte 012 ; |||||||| 013 ; ||||||++---- Sprite Colour toggle: EOR with metatile attribs 014 ; |||||+------ Y clipping bit 015 ; ||||+------- X clipping bit 016 ; |||+-------- Clipping or wrap : 0: clip sprites at screen edge, 1: allow wrap 017 ; ||+--------- Background priority bit 018 ; |+---------- Horizontal flipping toggle: EOR metatile attribs 019 ; +----------- Vertical flipping toggle: EOR metatile attribs 020 021 ; Metatile number : byte 022 ; Xpos : byte 023 024 ; -------------------------------------------------------------------------------------------- 025 026 ; metasprite format to define metasprite in ROM data: 027 028 ; xxxxxxxx --- Sprite X coordinate (if required) 029 ; yyyyyyyy --- Sprite Y coordinate (if required) 030 031 ; tttttttt --- Tile number (if required) 032 033 ; vhytxxpp --- Attribute byte (always) 034 ; |||||||| 035 ; ||||||++---- Sprite Colour 036 ; |||||+------ Tile number of next sprite (0: required, 1 : Tile number of this sprite + 1, skip if X control was LF) 037 ; ||||+------- Y position of next sprite (0 : required, 0 : unchanged) 038 ; ||++-------- X position of next sprite (01 : required, 00 : X pos of this sprite + 8, 039 ; || 10 : X pos of the first sprite, Y + 8 (CR/LF), 11 : Escape code for last sprite) 040 ; |+---------- Horizontal flipping 041 ; +----------- Vertical flipping 042 043 ; static 044 declareBSS 045 OAMoffset .byte 046 endBSS 047 048 ; notallOnScreen use zeropage: 049 050 locals 051 sprModifier .byte 052 sprAttrib .byte 053 sprTile .byte 054 sprXpos .byte 055 sprYpos .byte 056 057 sprXbit8 .byte 058 sprYbit8 .byte 059 060 metaspritePointerLo .byte 061 metaspritePointerHi .byte 062 063 sprAdder .byte 064 sprXposStart .byte 065 mSpriteOffset .byte 066 carryYplusHeight .byte 067 carryXplusWidth .byte 068 endlocals 069 070 notallOnScreen = local::sprAdder 071 saveOAMOffset = local::sprTile 072 metaspritePointer = local::metaspritePointerLo 073 074 ; init: 075 ldy #::METASPRITE_COUNT 076 sty local::mSpriteOffset 077 078 079 ; skip reserved sprites 080 if lda M::OAMoffset < #::OAM_ROTATION_START 081 lda #::OAM_ROTATION_START 082 endif 083 084 sta M::OAMoffset 085 sta saveOAMOffset ; use as notallOnScreen: save OAMoffset 086 087 DoNextmetasprite: 088 089 090 ; loop through all entries and skip those with att = $FF 091 ; jump to OAM rotation and leave if no more entries 092 ldx local::mSpriteOffset 093 094 repeat 095 096 if dex == negative 097 jmp clearRemainingOAM 098 endif 099 100 mb a, local::sprModifier := mSpriteMemory[ x ]::att ; load Attrib/meta data which is modifier for all 101 102 until tay : iny != zero ; same as: until mSpriteMemory[ x ]::att <> #$FF 103 104 mb local::sprYbit8 := a >> 2 ; put Y 'bit8' into bit 0 local var (only bit0 matters) 105 mb local::sprXbit8 := a >> 1 ; put X 'bit8' into bit 0 local var (only bit0 matters) 106 107 stx local::mSpriteOffset 108 109 mb local::sprYpos := mSpriteMemory[ x ]::yPos 110 mb local::sprXpos := mSpriteMemory[ x ]::xPos 111 sta local::sprXposStart 112 113 mb a, x := mSpriteMemory[ x ]::mTile ; load metatile number 114 115 ; get metatile pointer 116 mb local::metaspritePointerLo := metaspriteNumbersLo[ x ] 117 mb local::metaspritePointerHi := metaspriteNumbersHi[ x ] 118 119 ; first data from metatile string is Xwidth, Yheight, Tile, and Attribs/command byte 120 121 ldy #0 122 sty notallOnScreen 123 124 mb a := local::sprXpos + (metaspritePointer)[ y ] ; add width ( is stored 8 less than actual ) 125 tax ; x has right side of object X coord 126 rol local::carryXplusWidth 127 128 iny 129 mb a := local::sprYpos + (metaspritePointer)[ y ] ; add height ( is stored 8 less than actual ) 130 tay ; y has bottom of object Y coord 131 rol local::carryYplusHeight 132 133 ; ----------- check if all onscreen 134 135 if local::sprModifier & #010000 goto AllOnScreen 136 137 tya ; y has bottom of object Y coord 138 cmp #238 139 rol 140 ora local::sprXbit8 141 ora local::sprYbit8 142 ora local::carryXplusWidth 143 ora local::carryYplusHeight 144 and #1 145 146 if sta notallOnScreen == zero goto AllOnscreen 147 148 ; ------ end check all onscreen 149 150 ; ----------- check if all offscreen 151 152 ; check if all offscreen for X 153 lda local::carryXplusWidth 154 eor #1 155 and local::sprXbit8 156 and #1 157 bne DoNextmetasprite 158 159 ; check all offscreen for Y 160 lda local::carryYplusHeight 161 eor #1 162 and local::sprYbit8 163 and #1 164 bne DoNextmetasprite 165 166 ; check offscreen special case, bottom of screen area: 167 lda local::sprYpos 168 cmp #239 169 rol 170 eor #1 ; b0 = 0 if y > 238 171 ora local::sprYbit8 ; b0 still = 0 if sprYbit8 = 0 172 and #1 173 beq DoNextmetasprite 174 175 ; ------------ end check offscreen 176 177 AllOnscreen: 178 179 bit local::sprModifier ; copy b7 and b6 into N, V 180 181 if V set ; H flipping: 182 mb local::sprXpos := x ; x has right side of object X coord 183 mb local::sprXposStart := x 184 185 if ror local::carryXplusWidth == carry set 186 mb local::sprModifier := local::sprModifier ^ # ( 1 << OFFSCREEN_XBIT ) 187 endif 188 endif 189 190 iny 191 192 ; --------- end width 193 ; --------- process height: 194 195 ror local::carryYplusHeight 196 if lda local::sprModifier == N set ; V flipping: 197 mb local::sprYpos := y ; ; y holds Ypos + height..add height ( is stored 8 less than actual ) 198 if carry set 199 mb a := a ^ #( 1 << OFFSCREEN_YBIT ) 200 endif 201 endif 202 203 sta local::sprModifier 204 205 mb local::sprYbit8 := a >> 2 ; put Y 'bit8' into bit 0 local var (only bit0 matters) 206 mb local::sprXbit8 := a >> 1 ; put X 'bit8' into bit 0 local var (only bit0 matters) 207 208 ; --------------------------- 209 210 ldx saveOAMOffset ; X now has OAMoffset 211 212 ldy #2 ; start at tile entry 213 214 mb local::sprTile := (metaspritePointer)[ y ] 215 iny 216 217 ; if all sprites are onscreen, jump to sped up routine: 218 219 if notallOnScreen == zero 220 jmp DrawFast 221 endif 222 223 DoNextTile: 224 225 mb local::sprAttrib := (metaspritePointer)[ y ] ; read attrib and flags 226 iny 227 228 ; if both offscreen bits are clear OR No clipping mode is on 229 230 if ( local::sprYpos < #239 && ( local::sprXbit8 | local::sprYbit8 >> 1 == carry clear )) 231 232 mb OAM_SHADOW[ x + 2] := local::sprAttrib & #%11000011 ^ local::sprModifier 233 mb OAM_SHADOW[ x + 3] := local::sprXpos 234 mb OAM_SHADOW[ x + 0] := local::sprYpos 235 mb OAM_SHADOW[ x + 1] := local::sprTile 236 237 if x := x + 4 == zero 238 ldx #::OAM_ROTATION_START 239 endif 240 241 endif 242 243 sec ; sec carry to end making reg A hold #8 244 mb a := local::sprAttrib & #$F0 245 rol 246 asl 247 asl ; test bit 3, 2 as C, N 248 249 ; if X MODIFIER value is 00 or 01: 250 if C clear 251 asl ; A will have #8 252 if C set ; X MODIFIER IS 01 253 mb a := (metaspritePointer)[ y ] 254 iny 255 clc 256 endif 257 258 ; HERE. either way, carry clear 259 260 if { flagSet local::sprModifier, 6 } ; if bit6 (h mirror) 261 ; negate adder 262 mb a := a ^ #$FF 263 sec 264 endif 265 266 sta local::sprAdder 267 268 mb local::sprXpos := a +c local::sprXpos 269 270 ror 271 if a ^ local::sprAdder == N set ; if carry and adder sign are different: 272 inc local::sprXbit8 ; toggle offscreen bit 273 endif 274 275 else 276 if N clear ; X MODIFIER IS 10 277 278 ; this idea takes the same # of cycles as the clearer code: 279 ; ------------------------------------------------------- 280 ; asl ; reg A holds #8 281 ; and local::sprModifier 282 ; cmp #1 ; only bit8 could be set, copy it into C 283 ; rol local::sprXbit8 284 285 mb local::sprXbit8 := local::sprModifier >> 3 286 mb local::sprXpos := local::sprXposStart 287 288 lda #8 289 jmp Add8toYPos 290 endif 291 ; else: X MODIFIER IS 11: 292 stx saveOAMOffset ; save OAM offset here 293 ;--------------- 294 jmp DoNextmetasprite ; if = 0 then bail and do next RAm based metasprite 295 296 endif 297 298 ; -----------END X pos 299 300 ; ----------- Y pos 301 302 ; load Ypos? Skip all this if not 0 303 if ! local::sprAttrib & #001000 304 305 mb a := (metaspritePointer)[ y ] 306 iny 307 308 Add8toYPos: ; jump here if CR/LF code 309 310 clc 311 if flagSet local::sprModifier ; if bit7 (v mirror) 312 mb a := a ^ #$FF 313 sec 314 endif 315 316 sta local::sprAdder 317 mb local::sprYpos := a +c local::sprYpos 318 319 ror 320 if a ^ local::sprAdder == N set 321 inc local::sprYbit8 322 endif 323 324 endif 325 ; -----------END Y pos 326 327 ; -----------check tile: 328 329 ; BIT4: check if 0: load tile, else use next tile 330 331 inc local::sprTile ; inc by default 332 333 if ! local::sprAttrib & #000100 334 mb local::sprTile := (metaspritePointer)[ y ] 335 iny 336 endif 337 338 ; -------end tile processing 339 340 jmp DoNextTile 341 342 ; super fast, no clipping version: 343 344 DrawFast: 345 346 mb local::sprAttrib := (metaspritePointer)[ y ] ; read attrib and flags 347 iny 348 349 mb OAM_SHADOW[ x + 2] := local::sprAttrib & #%11000011 ^ local::sprModifier 350 mb OAM_SHADOW[ x + 3] := local::sprXpos 351 mb OAM_SHADOW[ x + 0] := local::sprYpos 352 mb OAM_SHADOW[ x + 1] := local::sprTile 353 354 if x := x + 4 == zero 355 ldx #::OAM_ROTATION_START 356 endif 357 358 sec ; sec carry to end making reg A hold #8 359 mb a := local::sprAttrib & #$F0 360 rol 361 asl 362 asl ; test bit 3, 2 as C, N 363 364 ; if X MODIFIER value is 00 or 01: 365 if C clear 366 asl ; A will have #8 367 if C set ; X MODIFIER IS 01 368 mb a := (metaspritePointer)[ y ] 369 iny 370 clc 371 endif 372 373 ; HERE. either way, carry clear 374 375 if { flagSet local::sprModifier, 6 } ; if bit6 (h mirror) 376 ; negate adder 377 mb a := a ^ #$FF 378 sec 379 endif 380 381 mb local::sprXpos := a +c local::sprXpos 382 383 else 384 if N clear ; X MODIFIER IS 10 385 mb local::sprXpos := local::sprXposStart 386 387 lda #8 388 jmp Add8toYPosFast 389 endif 390 ; else: X MODIFIER IS 11: 391 stx saveOAMOffset ; save OAM offset here 392 ;--------------- 393 jmp DoNextmetasprite ; if = 0 then bail and do next RAm based metasprite 394 395 endif 396 397 ; -----------END X pos 398 399 ; ----------- Y pos 400 401 ; load Ypos? Skip all this if not 0 402 if ! local::sprAttrib & #001000 403 404 mb a := (metaspritePointer)[ y ] 405 iny 406 407 Add8toYPosFast: ; jump here if CR/LF code 408 409 clc 410 if flagSet local::sprModifier ; if bit7 (v mirror) 411 mb a := a ^ #$FF 412 sec 413 endif 414 415 mb local::sprYpos := a +c local::sprYpos 416 endif 417 ; -----------END Y pos 418 419 ; -----------check tile: 420 421 ; BIT4: check if 0: load tile, else use next tile 422 423 inc local::sprTile ; inc by default 424 425 if ! local::sprAttrib & #000100 426 mb local::sprTile := (metaspritePointer)[ y ] 427 iny 428 endif 429 430 ; -------end tile processing 431 432 jmp DrawFast 433 434 ; -------------------------------------------------------------------------------------------- 435 436 clearRemainingOAM: 437 OAMnext = saveOAMOffset ; alias 438 439 ; -------------------------------------------------------------------------------------------- 440 441 ldx OAMnext ; x holds start of next blank spot 442 443 ; take away blank spaces from total slots if we wrapped 444 if OAMnext <= M::OAMoffset 445 mb a := OAMnext - #::OAM_ROTATION_START 446 endif 447 448 mb a := a - M::OAMoffset ; bytes used 449 mb a := a >> 2 ; slots used 450 sta OAMnext ; use as notallOnScreen, since this value is in reg X 451 452 mb y := #(64 - ( ::OAM_ROTATION_START / 4 ) ) - OAMnext ; total avaliable slots MINUS slots used 453 lda #$FF 454 455 cpy #00 456 while not zero do 457 458 sta OAM_SHADOW, x 459 mb x := x + 4 460 if zero 461 ldx #::OAM_ROTATION_START 462 endif 463 dey 464 endwhile 465 466 mb M::OAMoffset := M::OAMoffset + #::OAM_ROTATION_AMOUNT 467 468 rts 469 470 .endproc

No comments:

Post a Comment