Monday, March 25, 2013

MetaSprite Routine Updated

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