| 1 | /** |
| 2 | * For whatever reason, breaking this out of fce.c made sprites not corrupt |
| 3 | */ |
| 4 | |
| 5 | |
| 6 | #include <string.h> |
| 7 | #include <stdio.h> |
| 8 | #include <stdlib.h> |
| 9 | |
| 10 | #include "types.h" |
| 11 | #include "x6502.h" |
| 12 | #include "fce.h" |
| 13 | #include "sound.h" |
| 14 | #include "svga.h" |
| 15 | #include "netplay.h" |
| 16 | #include "general.h" |
| 17 | #include "endian.h" |
| 18 | #include "version.h" |
| 19 | #include "memory.h" |
| 20 | |
| 21 | #include "cart.h" |
| 22 | #include "nsf.h" |
| 23 | #include "fds.h" |
| 24 | #include "ines.h" |
| 25 | #include "unif.h" |
| 26 | #include "cheat.h" |
| 27 | |
| 28 | #define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V)>>10][(V)] |
| 29 | //#define MMC5BGVRAMADR(V) &MMC5BGVPage[(V)>>10][(V)] |
| 30 | #define VRAMADR(V) &VPage[(V)>>10][(V)] |
| 31 | |
| 32 | #define V_FLIP 0x80 |
| 33 | #define H_FLIP 0x40 |
| 34 | #define SP_BACK 0x20 |
| 35 | |
| 36 | uint8 SPRAM[0x100]; |
| 37 | static uint8 SPRBUF[0x100]; |
| 38 | |
| 39 | uint8 sprlinebuf[256+8]; |
| 40 | |
| 41 | int32 sphitx; |
| 42 | uint8 sphitdata; |
| 43 | int spork=0; /* spork the world. Any sprites on this line? |
| 44 | Then this will be set to 1. Needed for zapper |
| 45 | emulation and *gasp* sprite emulation. |
| 46 | */ |
| 47 | |
| 48 | |
| 49 | extern void BGRender(uint8 *target); |
| 50 | |
| 51 | |
| 52 | static int maxsprites=8; |
| 53 | static int sprlinebuf_empty=0; |
| 54 | |
| 55 | |
| 56 | void FCEUI_DisableSpriteLimitation(int a) |
| 57 | { |
| 58 | maxsprites=a?64:8; |
| 59 | } |
| 60 | |
| 61 | |
| 62 | //int printed=1; |
| 63 | typedef struct { |
| 64 | uint8 y,no,atr,x; |
| 65 | } SPR __attribute__((aligned(1))); |
| 66 | |
| 67 | typedef struct { |
| 68 | // uint8 ca[2],atr,x; |
| 69 | uint8 ca[2],atr,x; |
| 70 | // union { int z; } |
| 71 | |
| 72 | |
| 73 | } SPRB __attribute__((aligned(1))); |
| 74 | |
| 75 | |
| 76 | |
| 77 | static uint8 nosprites,SpriteBlurp; |
| 78 | |
| 79 | void FetchSpriteData(void) |
| 80 | { |
| 81 | SPR *spr; |
| 82 | uint8 H; |
| 83 | int n,vofs; |
| 84 | |
| 85 | spr=(SPR *)SPRAM; |
| 86 | H=8; |
| 87 | |
| 88 | nosprites=SpriteBlurp=0; |
| 89 | |
| 90 | vofs=(unsigned int)(PPU[0]&0x8&(((PPU[0]&0x20)^0x20)>>2))<<9; |
| 91 | H+=(PPU[0]&0x20)>>2; |
| 92 | |
| 93 | if(!PPU_hook) |
| 94 | for(n=63;n>=0;n--,spr++) |
| 95 | { |
| 96 | if((unsigned int)(scanline-spr->y)>=H) continue; |
| 97 | |
| 98 | if(nosprites<maxsprites) |
| 99 | { |
| 100 | if(n==63) SpriteBlurp=1; |
| 101 | |
| 102 | { |
| 103 | SPRB dst; |
| 104 | uint8 *C; |
| 105 | int t; |
| 106 | unsigned int vadr; |
| 107 | |
| 108 | t = (int)scanline-(spr->y); |
| 109 | |
| 110 | if (Sprite16) |
| 111 | vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4); |
| 112 | else |
| 113 | vadr = (spr->no<<4)+vofs; |
| 114 | |
| 115 | if (spr->atr&V_FLIP) |
| 116 | { |
| 117 | vadr+=7; |
| 118 | vadr-=t; |
| 119 | vadr+=(PPU[0]&0x20)>>1; |
| 120 | vadr-=t&8; |
| 121 | } |
| 122 | else |
| 123 | { |
| 124 | vadr+=t; |
| 125 | vadr+=t&8; |
| 126 | } |
| 127 | |
| 128 | /* Fix this geniestage hack */ |
| 129 | if(MMC5Hack && geniestage!=1) C = MMC5SPRVRAMADR(vadr); |
| 130 | else C = VRAMADR(vadr); |
| 131 | |
| 132 | |
| 133 | dst.ca[0]=C[0]; |
| 134 | dst.ca[1]=C[8]; |
| 135 | dst.x=spr->x; |
| 136 | dst.atr=spr->atr; |
| 137 | |
| 138 | |
| 139 | *(uint32 *)&SPRBUF[nosprites<<2]=*(uint32 *)&dst; |
| 140 | } |
| 141 | |
| 142 | nosprites++; |
| 143 | } |
| 144 | else |
| 145 | { |
| 146 | PPU_status|=0x20; |
| 147 | break; |
| 148 | } |
| 149 | } |
| 150 | else |
| 151 | for(n=63;n>=0;n--,spr++) |
| 152 | { |
| 153 | if((unsigned int)(scanline-spr->y)>=H) continue; |
| 154 | |
| 155 | if(nosprites<maxsprites) |
| 156 | { |
| 157 | if(n==63) SpriteBlurp=1; |
| 158 | |
| 159 | { |
| 160 | SPRB dst; |
| 161 | uint8 *C; |
| 162 | int t; |
| 163 | unsigned int vadr; |
| 164 | |
| 165 | t = (int)scanline-(spr->y); |
| 166 | |
| 167 | if (Sprite16) |
| 168 | vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4); |
| 169 | else |
| 170 | vadr = (spr->no<<4)+vofs; |
| 171 | |
| 172 | if (spr->atr&V_FLIP) |
| 173 | { |
| 174 | vadr+=7; |
| 175 | vadr-=t; |
| 176 | vadr+=(PPU[0]&0x20)>>1; |
| 177 | vadr-=t&8; |
| 178 | } |
| 179 | else |
| 180 | { |
| 181 | vadr+=t; |
| 182 | vadr+=t&8; |
| 183 | } |
| 184 | |
| 185 | if(MMC5Hack) C = MMC5SPRVRAMADR(vadr); |
| 186 | else C = VRAMADR(vadr); |
| 187 | dst.ca[0]=C[0]; |
| 188 | if(nosprites<8) |
| 189 | { |
| 190 | PPU_hook(0x2000); |
| 191 | PPU_hook(vadr); |
| 192 | } |
| 193 | dst.ca[1]=C[8]; |
| 194 | dst.x=spr->x; |
| 195 | dst.atr=spr->atr; |
| 196 | |
| 197 | |
| 198 | *(uint32 *)&SPRBUF[nosprites<<2]=*(uint32 *)&dst; |
| 199 | } |
| 200 | |
| 201 | nosprites++; |
| 202 | } |
| 203 | else |
| 204 | { |
| 205 | PPU_status|=0x20; |
| 206 | break; |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | if(nosprites>8) PPU_status|=0x20; /* Handle case when >8 sprites per |
| 211 | scanline option is enabled. */ |
| 212 | else if(PPU_hook) |
| 213 | { |
| 214 | for(n=0;n<(8-nosprites);n++) |
| 215 | { |
| 216 | PPU_hook(0x2000); |
| 217 | PPU_hook(vofs); |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | } |
| 222 | |
| 223 | #ifdef FRAMESKIP |
| 224 | extern int FSkip; |
| 225 | #endif |
| 226 | |
| 227 | void RefreshSprites(void) |
| 228 | { |
| 229 | int n; |
| 230 | SPRB *spr; |
| 231 | |
| 232 | spork=0; |
| 233 | if(!nosprites) return; |
| 234 | #ifdef FRAMESKIP |
| 235 | if(FSkip) |
| 236 | { |
| 237 | if(!SpriteBlurp) |
| 238 | { |
| 239 | nosprites=0; |
| 240 | return; |
| 241 | } |
| 242 | else |
| 243 | nosprites=1; |
| 244 | } |
| 245 | #endif |
| 246 | |
| 247 | nosprites--; |
| 248 | spr = (SPRB*)SPRBUF+nosprites; |
| 249 | |
| 250 | if (!sprlinebuf_empty) |
| 251 | { |
| 252 | FCEU_dwmemset(sprlinebuf,0x80808080,256); |
| 253 | sprlinebuf_empty = 1; |
| 254 | } |
| 255 | |
| 256 | for(n=nosprites;n>=0;n--,spr--) |
| 257 | { |
| 258 | register uint32 J; |
| 259 | |
| 260 | J=spr->ca[0]|spr->ca[1]; |
| 261 | |
| 262 | if (J) |
| 263 | { |
| 264 | register uint8 atr,c1,c2; |
| 265 | uint8 *C; |
| 266 | uint8 *VB; |
| 267 | int x=spr->x; |
| 268 | atr=spr->atr; |
| 269 | |
| 270 | if(n==0 && SpriteBlurp && !(PPU_status&0x40)) |
| 271 | { |
| 272 | sphitx=x; |
| 273 | sphitdata=J; |
| 274 | if(atr&H_FLIP) |
| 275 | sphitdata= ((J<<7)&0x80) | |
| 276 | ((J<<5)&0x40) | |
| 277 | ((J<<3)&0x20) | |
| 278 | ((J<<1)&0x10) | |
| 279 | ((J>>1)&0x08) | |
| 280 | ((J>>3)&0x04) | |
| 281 | ((J>>5)&0x02) | |
| 282 | ((J>>7)&0x01); |
| 283 | } |
| 284 | |
| 285 | |
| 286 | c1=((spr->ca[0]>>1)&0x55)|(spr->ca[1]&0xAA); |
| 287 | c2=(spr->ca[0]&0x55)|((spr->ca[1]<<1)&0xAA); |
| 288 | |
| 289 | C = sprlinebuf+x; |
| 290 | VB = (PALRAM+0x10)+((atr&3)<<2); |
| 291 | |
| 292 | { |
| 293 | J &= 0xff; |
| 294 | if(atr&SP_BACK) J |= 0x4000; |
| 295 | if (atr&H_FLIP) |
| 296 | { |
| 297 | if (J&0x02) C[1]=VB[c1&3]|(J>>8); |
| 298 | if (J&0x01) *C=VB[c2&3]|(J>>8); |
| 299 | c1>>=2;c2>>=2; |
| 300 | if (J&0x08) C[3]=VB[c1&3]|(J>>8); |
| 301 | if (J&0x04) C[2]=VB[c2&3]|(J>>8); |
| 302 | c1>>=2;c2>>=2; |
| 303 | if (J&0x20) C[5]=VB[c1&3]|(J>>8); |
| 304 | if (J&0x10) C[4]=VB[c2&3]|(J>>8); |
| 305 | c1>>=2;c2>>=2; |
| 306 | if (J&0x80) C[7]=VB[c1]|(J>>8); |
| 307 | if (J&0x40) C[6]=VB[c2]|(J>>8); |
| 308 | } else { |
| 309 | if (J&0x02) C[6]=VB[c1&3]|(J>>8); |
| 310 | if (J&0x01) C[7]=VB[c2&3]|(J>>8); |
| 311 | c1>>=2;c2>>=2; |
| 312 | if (J&0x08) C[4]=VB[c1&3]|(J>>8); |
| 313 | if (J&0x04) C[5]=VB[c2&3]|(J>>8); |
| 314 | c1>>=2;c2>>=2; |
| 315 | if (J&0x20) C[2]=VB[c1&3]|(J>>8); |
| 316 | if (J&0x10) C[3]=VB[c2&3]|(J>>8); |
| 317 | c1>>=2;c2>>=2; |
| 318 | if (J&0x80) *C=VB[c1]|(J>>8); |
| 319 | if (J&0x40) C[1]=VB[c2]|(J>>8); |
| 320 | } |
| 321 | } |
| 322 | sprlinebuf_empty = 0; |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | nosprites=0; |
| 327 | spork=1; |
| 328 | } |
| 329 | |
| 330 | |
| 331 | void CopySprites(uint8 *target) |
| 332 | { |
| 333 | uint8 n=((PPU[1]&4)^4)<<1; |
| 334 | //if ((int)n < minx) n = minx & 0xfc; |
| 335 | loopskie: |
| 336 | { |
| 337 | uint32 t=*(uint32 *)(sprlinebuf+n); |
| 338 | if(t!=0x80808080) |
| 339 | { |
| 340 | #ifdef LSB_FIRST |
| 341 | uint32 tb=*(uint32 *)(target+n); |
| 342 | if(!(t&0x00000080) && (!(t&0x00000040) || (tb&0x00000040))) { // have sprite pixel AND (normal sprite OR behind bg with no bg) |
| 343 | tb &= ~0x000000ff; tb |= t & 0x000000ff; |
| 344 | } |
| 345 | |
| 346 | if(!(t&0x00008000) && (!(t&0x00004000) || (tb&0x00004000))) { |
| 347 | tb &= ~0x0000ff00; tb |= t & 0x0000ff00; |
| 348 | } |
| 349 | |
| 350 | if(!(t&0x00800000) && (!(t&0x00400000) || (tb&0x00400000))) { |
| 351 | tb &= ~0x00ff0000; tb |= t & 0x00ff0000; |
| 352 | } |
| 353 | |
| 354 | if(!(t&0x80000000) && (!(t&0x40000000) || (tb&0x40000000))) { |
| 355 | tb &= ~0xff000000; tb |= t & 0xff000000; |
| 356 | } |
| 357 | *(uint32 *)(target+n)=tb; |
| 358 | #else |
| 359 | #error not implemented |
| 360 | #endif |
| 361 | } |
| 362 | } |
| 363 | n+=4; |
| 364 | if(n) goto loopskie; |
| 365 | } |
| 366 | |
| 367 | |