Gradius fixed
[fceu.git] / ppu.c
CommitLineData
98733207 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
36uint8 SPRAM[0x100];
37static uint8 SPRBUF[0x100];
38
9115e7d2 39static uint8 sprlinebuf[256+8];
98733207 40extern void BGRender(uint8 *target);
41extern int tosprite;
42
43
44static int maxsprites=8;
45
46
47void FCEUI_DisableSpriteLimitation(int a)
48{
49 maxsprites=a?64:8;
50}
51
52
53//int printed=1;
54typedef struct {
55 uint8 y,no,atr,x;
56} SPR __attribute__((aligned(1)));
57
58typedef struct {
9115e7d2 59 // uint8 ca[2],atr,x;
60 uint8 ca[2],atr,x;
98733207 61 // union { int z; }
9115e7d2 62
98733207 63
64} SPRB __attribute__((aligned(1)));
65
66
67
68static uint8 nosprites,SpriteBlurp;
69
70void FetchSpriteData(void)
71{
72 SPR *spr;
73 uint8 H;
74 int n,vofs;
75
76 spr=(SPR *)SPRAM;
77 H=8;
78
79 nosprites=SpriteBlurp=0;
80
81 vofs=(unsigned int)(PPU[0]&0x8&(((PPU[0]&0x20)^0x20)>>2))<<9;
82 H+=(PPU[0]&0x20)>>2;
83
84 if(!PPU_hook)
85 for(n=63;n>=0;n--,spr++)
86 {
87 if((unsigned int)(scanline-spr->y)>=H) continue;
88
89 if(nosprites<maxsprites)
90 {
91 if(n==63) SpriteBlurp=1;
92
93 {
94 SPRB dst;
95 uint8 *C;
96 int t;
97 unsigned int vadr;
98
99 t = (int)scanline-(spr->y);
100
101 if (Sprite16)
102 vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
103 else
104 vadr = (spr->no<<4)+vofs;
105
106 if (spr->atr&V_FLIP)
107 {
108 vadr+=7;
109 vadr-=t;
110 vadr+=(PPU[0]&0x20)>>1;
111 vadr-=t&8;
112 }
113 else
114 {
115 vadr+=t;
116 vadr+=t&8;
117 }
118
119 /* Fix this geniestage hack */
120 if(MMC5Hack && geniestage!=1) C = MMC5SPRVRAMADR(vadr);
121 else C = VRAMADR(vadr);
122
9115e7d2 123
98733207 124 dst.ca[0]=C[0];
125 dst.ca[1]=C[8];
126 dst.x=spr->x;
127 dst.atr=spr->atr;
128
129
130 *(uint32 *)&SPRBUF[nosprites<<2]=*(uint32 *)&dst;
131 }
132
133 nosprites++;
134 }
135 else
136 {
137 PPU_status|=0x20;
138 break;
139 }
140 }
141 else
142 for(n=63;n>=0;n--,spr++)
143 {
144 if((unsigned int)(scanline-spr->y)>=H) continue;
145
146 if(nosprites<maxsprites)
147 {
148 if(n==63) SpriteBlurp=1;
149
150 {
151 SPRB dst;
152 uint8 *C;
153 int t;
154 unsigned int vadr;
155
156 t = (int)scanline-(spr->y);
157
158 if (Sprite16)
159 vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
160 else
161 vadr = (spr->no<<4)+vofs;
162
163 if (spr->atr&V_FLIP)
164 {
165 vadr+=7;
166 vadr-=t;
167 vadr+=(PPU[0]&0x20)>>1;
168 vadr-=t&8;
169 }
170 else
171 {
172 vadr+=t;
173 vadr+=t&8;
174 }
175
176 if(MMC5Hack) C = MMC5SPRVRAMADR(vadr);
177 else C = VRAMADR(vadr);
178 dst.ca[0]=C[0];
179 PPU_hook(vadr);
180 dst.ca[1]=C[8];
181 PPU_hook(vadr|8);
182 dst.x=spr->x;
183 dst.atr=spr->atr;
184
185
186 *(uint32 *)&SPRBUF[nosprites<<2]=*(uint32 *)&dst;
187 }
188
189 nosprites++;
190 }
191 else
192 {
193 PPU_status|=0x20;
194 break;
195 }
196 }
197}
198
199#ifdef FRAMESKIP
200extern int FSkip;
201#endif
202
203void RefreshSprite(uint8 *target)
204{
9115e7d2 205 int n, minx=256;
98733207 206 SPRB *spr;
98733207 207
208 if(!nosprites) return;
209 #ifdef FRAMESKIP
210 if(FSkip)
211 {
212 if(!SpriteBlurp)
213 {
214 nosprites=0;
215 return;
216 }
217 else
218 nosprites=1;
219 }
220 #endif
221
98733207 222 nosprites--;
223 spr = (SPRB*)SPRBUF+nosprites;
224
225 for(n=nosprites;n>=0;n--,spr--)
226 {
9115e7d2 227 register uint32 J;
98733207 228
229 J=spr->ca[0]|spr->ca[1];
98733207 230
9115e7d2 231 if (J)
232 {
233 register uint8 atr,c1,c2;
234 uint8 *C;
235 uint8 *VB;
236 int x=spr->x;
237 atr=spr->atr;
238
239 if (x < minx)
240 {
241 if (minx == 256) FCEU_dwmemset(sprlinebuf,0x80808080,256); // only clear sprite buff when we encounter first sprite
242 minx = x;
243 }
98733207 244 if(n==0 && SpriteBlurp && !(PPU_status&0x40))
9115e7d2 245 {
98733207 246 int z,ze=x+8;
247 if(ze>256) {ze=256;}
248 if(ScreenON && (scanline<FSettings.FirstSLine || scanline>FSettings.LastSLine
249 #ifdef FRAMESKIP
250 || FSkip
251 #endif
252 ))
253 BGRender(target);
254
255 if(!(atr&H_FLIP))
256 {
257 for(z=x;z<ze;z++)
258 {
259 if(J&(0x80>>(z-x)))
260 {
261 if(!(target[z]&64))
262 tosprite=z;
263 }
264 }
265 }
266 else
267 {
268 for(z=x;z<ze;z++)
269 {
270 if(J&(1<<(z-x)))
271 {
272 if(!(target[z]&64))
273 tosprite=z;
274 }
275 }
276 }
277 //FCEU_DispMessage("%d, %d:%d",scanline,x,tosprite);
278 }
279
9115e7d2 280 c1=((spr->ca[0]>>1)&0x55)|(spr->ca[1]&0xAA);
281 c2=(spr->ca[0]&0x55)|((spr->ca[1]<<1)&0xAA);
282
98733207 283 C = sprlinebuf+x;
284 VB = (PALRAM+0x10)+((atr&3)<<2);
285
98733207 286 {
9115e7d2 287 J &= 0xff;
288 if(atr&SP_BACK) J |= 0x4000;
98733207 289 if (atr&H_FLIP)
290 {
9115e7d2 291 if (J&0x02) C[1]=VB[c1&3]|(J>>8);
292 if (J&0x01) *C=VB[c2&3]|(J>>8);
98733207 293 c1>>=2;c2>>=2;
9115e7d2 294 if (J&0x08) C[3]=VB[c1&3]|(J>>8);
295 if (J&0x04) C[2]=VB[c2&3]|(J>>8);
98733207 296 c1>>=2;c2>>=2;
9115e7d2 297 if (J&0x20) C[5]=VB[c1&3]|(J>>8);
298 if (J&0x10) C[4]=VB[c2&3]|(J>>8);
98733207 299 c1>>=2;c2>>=2;
9115e7d2 300 if (J&0x80) C[7]=VB[c1]|(J>>8);
301 if (J&0x40) C[6]=VB[c2]|(J>>8);
98733207 302 } else {
9115e7d2 303 if (J&0x02) C[6]=VB[c1&3]|(J>>8);
304 if (J&0x01) C[7]=VB[c2&3]|(J>>8);
98733207 305 c1>>=2;c2>>=2;
9115e7d2 306 if (J&0x08) C[4]=VB[c1&3]|(J>>8);
307 if (J&0x04) C[5]=VB[c2&3]|(J>>8);
98733207 308 c1>>=2;c2>>=2;
9115e7d2 309 if (J&0x20) C[2]=VB[c1&3]|(J>>8);
310 if (J&0x10) C[3]=VB[c2&3]|(J>>8);
98733207 311 c1>>=2;c2>>=2;
9115e7d2 312 if (J&0x80) *C=VB[c1]|(J>>8);
313 if (J&0x40) C[1]=VB[c2]|(J>>8);
98733207 314 }
98733207 315 }
98733207 316 }
9115e7d2 317 }
98733207 318
319 nosprites=0;
320 #ifdef FRAMESKIP
321 if(FSkip) return;
322 #endif
9115e7d2 323 if (minx == 256) return; // no visible sprites
98733207 324
325 {
326 uint8 n=((PPU[1]&4)^4)<<1;
9115e7d2 327 if ((int)n < minx) n = minx & 0xfc;
98733207 328 loopskie:
329 {
330 uint32 t=*(uint32 *)(sprlinebuf+n);
331 if(t!=0x80808080)
332 {
333 #ifdef LSB_FIRST
9115e7d2 334 uint32 tb=*(uint32 *)(target+n);
335 if(!(t&0x00000080) && (!(t&0x00000040) || (tb&0x00000040))) { // have sprite pixel AND (normal sprite OR behind bg with no bg)
336 tb &= ~0x000000ff; tb |= t & 0x000000ff;
98733207 337 }
338
9115e7d2 339 if(!(t&0x00008000) && (!(t&0x00004000) || (tb&0x00004000))) {
340 tb &= ~0x0000ff00; tb |= t & 0x0000ff00;
98733207 341 }
342
9115e7d2 343 if(!(t&0x00800000) && (!(t&0x00400000) || (tb&0x00400000))) {
344 tb &= ~0x00ff0000; tb |= t & 0x00ff0000;
98733207 345 }
346
9115e7d2 347 if(!(t&0x80000000) && (!(t&0x40000000) || (tb&0x40000000))) {
348 tb &= ~0xff000000; tb |= t & 0xff000000;
98733207 349 }
9115e7d2 350 *(uint32 *)(target+n)=tb;
98733207 351 #else
352 if(!(t&0x80000000))
353 {
354 if(!(t&0x40)) // Normal sprite
355 P[n]=sprlinebuf[n];
356 else if(P[n]&64) // behind bg sprite
357 P[n]=sprlinebuf[n];
358 }
359
360 if(!(t&0x800000))
361 {
362 if(!(t&0x4000)) // Normal sprite
363 P[n+1]=(sprlinebuf+1)[n];
364 else if(P[n+1]&64) // behind bg sprite
365 P[n+1]=(sprlinebuf+1)[n];
366 }
367
368 if(!(t&0x8000))
369 {
370 if(!(t&0x400000)) // Normal sprite
371 P[n+2]=(sprlinebuf+2)[n];
372 else if(P[n+2]&64) // behind bg sprite
373 P[n+2]=(sprlinebuf+2)[n];
374 }
375
376 if(!(t&0x80))
377 {
378 if(!(t&0x40000000)) // Normal sprite
379 P[n+3]=(sprlinebuf+3)[n];
380 else if(P[n+3]&64) // behind bg sprite
381 P[n+3]=(sprlinebuf+3)[n];
382 }
383 #endif
384 }
385 }
386 n+=4;
387 if(n) goto loopskie;
388 }
389}
390
391
392
393
394
395/*
396void FetchSpriteData(void)
397{
398 uint8 ns,sb;
399 SPR *spr;
400 uint8 H;
401 int n;
402 int vofs;
403 uint8 P0=PPU[0];
404
9115e7d2 405
98733207 406 spr=(SPR *)SPRAM;
407 H=8;
408
409 ns=sb=0;
410
411 vofs=(unsigned int)(P0&0x8&(((P0&0x20)^0x20)>>2))<<9;
412 H+=(P0&0x20)>>2;
413
414 if(!PPU_hook)
415 for(n=63;n>=0;n--,spr++)
416 {
417 if((unsigned int)(scanline-spr->y)>=H) continue;
418 //printf("%d, %u\n",scanline,(unsigned int)(scanline-spr->y));
419 if(ns<maxsprites)
420 {
421 if(n==63) sb=1;
422
423 {
424 SPRB dst;
425 uint8 *C;
426 int t;
427 unsigned int vadr;
428
429 t = (int)scanline-(spr->y);
430
431 if (Sprite16)
432 vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
433 else
434 vadr = (spr->no<<4)+vofs;
435
436 if (spr->atr&V_FLIP)
437 {
438 vadr+=7;
439 vadr-=t;
440 vadr+=(P0&0x20)>>1;
441 vadr-=t&8;
442 }
443 else
444 {
445 vadr+=t;
446 vadr+=t&8;
447 }
448
9115e7d2 449 // Fix this geniestage hack
98733207 450 if(MMC5Hack && geniestage!=1) C = MMC5SPRVRAMADR(vadr);
451 else C = VRAMADR(vadr);
452
9115e7d2 453
98733207 454 dst.ca[0]=C[0];
455 dst.ca[1]=C[8];
456 dst.x=spr->x;
457 dst.atr=spr->atr;
458
459 *(uint32 *)&SPRBUF[ns<<2]=*(uint32 *)&dst;
460 }
461
462 ns++;
463 }
464 else
465 {
466 PPU_status|=0x20;
467 break;
468 }
469 }
470 else
471 for(n=63;n>=0;n--,spr++)
472 {
473 if((unsigned int)(scanline-spr->y)>=H) continue;
474
475 if(ns<maxsprites)
476 {
477 if(n==63) sb=1;
478
479 {
480 SPRB dst;
481 uint8 *C;
482 int t;
483 unsigned int vadr;
484
485 t = (int)scanline-(spr->y);
486
487 if (Sprite16)
488 vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
489 else
490 vadr = (spr->no<<4)+vofs;
491
492 if (spr->atr&V_FLIP)
493 {
494 vadr+=7;
495 vadr-=t;
496 vadr+=(P0&0x20)>>1;
497 vadr-=t&8;
498 }
499 else
500 {
501 vadr+=t;
502 vadr+=t&8;
503 }
504
505 if(MMC5Hack) C = MMC5SPRVRAMADR(vadr);
506 else C = VRAMADR(vadr);
507 dst.ca[0]=C[0];
508 if(ns<8)
509 {
510 PPU_hook(0x2000);
511 PPU_hook(vadr);
512 }
513 dst.ca[1]=C[8];
514 dst.x=spr->x;
515 dst.atr=spr->atr;
516
517
518 *(uint32 *)&SPRBUF[ns<<2]=*(uint32 *)&dst;
519 }
520
521 ns++;
522 }
523 else
524 {
525 PPU_status|=0x20;
526 break;
527 }
528 }
529 //if(ns>=7)
530 //printf("%d %d\n",scanline,ns);
531 if(ns>8) PPU_status|=0x20; // Handle case when >8 sprites per
9115e7d2 532// scanline option is enabled.
98733207 533 else if(PPU_hook)
534 {
535 for(n=0;n<(8-ns);n++)
536 {
537 PPU_hook(0x2000);
538 PPU_hook(vofs);
539 }
540 }
541 numsprites=ns;
542 SpriteBlurp=sb;
543}
544
545
546
547void RefreshSprite(uint8 *target)
548{
9115e7d2 549
98733207 550 int n,sprindex;
551 SPRB *spr;
552 uint8 *P=target;
553
554 //if (printed) { printf("SPRB: %d SPR: %d\n", sizeof(SPRB), sizeof(SPR)); printed=0; }
555 if(!numsprites) return;
556
557 FCEU_dwmemset(sprlinebuf,0x80808080,256);
558
559 numsprites--;
560 sprindex=numsprites;
561 spr = (SPRB*)SPRBUF;
562
563 // for(n=nosprites;n>=0;n--,spr--)
564 for(n=numsprites;n>=0;n--,sprindex--)
565 {
566 uint8 J,atr,c1,c2;
567 int x=spr[sprindex].x;
568 uint8 *C;
569 uint8 *VB;
9115e7d2 570
98733207 571 P+=x;
572
573 c1=((spr[sprindex].ca[0]>>1)&0x55)|(spr[sprindex].ca[1]&0xAA);
574 c2=(spr[sprindex].ca[0]&0x55)|((spr[sprindex].ca[1]<<1)&0xAA);
575
576 J=spr[sprindex].ca[0]|spr[sprindex].ca[1];
577 atr=spr[sprindex].atr;
578
579 if(J)
9115e7d2 580 {
98733207 581 if(n==0 && SpriteBlurp && !(PPU_status&0x40))
9115e7d2 582 {
98733207 583 int z,ze=x+8;
584 if(ze>256) {ze=256;}
585 if(ScreenON && (scanline<FSettings.FirstSLine || scanline>FSettings.LastSLine
586 #ifdef FRAMESKIP
587 || FSkip
588 #endif
589 ))
590 // nothing wrong with this
591 BGRender(target);
592
593 if(!(atr&H_FLIP))
594 {
595 for(z=x;z<ze;z++)
596 {
597 if(J&(0x80>>(z-x)))
598 {
599 if(!(target[z]&64))
600 tosprite=z;
601 }
602 }
603 }
604 else
605 {
606 for(z=x;z<ze;z++)
607 {
608 if(J&(1<<(z-x)))
609 {
610 if(!(target[z]&64))
611 tosprite=z;
612 }
613 }
614 }
615 //FCEU_DispMessage("%d, %d:%d",scanline,x,tosprite);
616 }
617
618 //C = sprlinebuf+(uint8)x;
619 C = &(sprlinebuf[(uint8)x]);
620 VB = (PALRAM+0x10)+((atr&3)<<2);
621
9115e7d2 622 if(atr&SP_BACK)
98733207 623 {
624 if (atr&H_FLIP)
625 {
626 if (J&0x02) C[1]=VB[c1&3]|0x40;
627 if (J&0x01) *C=VB[c2&3]|0x40;
628 c1>>=2;c2>>=2;
629 if (J&0x08) C[3]=VB[c1&3]|0x40;
630 if (J&0x04) C[2]=VB[c2&3]|0x40;
631 c1>>=2;c2>>=2;
632 if (J&0x20) C[5]=VB[c1&3]|0x40;
633 if (J&0x10) C[4]=VB[c2&3]|0x40;
634 c1>>=2;c2>>=2;
635 if (J&0x80) C[7]=VB[c1]|0x40;
636 if (J&0x40) C[6]=VB[c2]|0x40;
637 } else {
638 if (J&0x02) C[6]=VB[c1&3]|0x40;
639 if (J&0x01) C[7]=VB[c2&3]|0x40;
640 c1>>=2;c2>>=2;
641 if (J&0x08) C[4]=VB[c1&3]|0x40;
642 if (J&0x04) C[5]=VB[c2&3]|0x40;
643 c1>>=2;c2>>=2;
644 if (J&0x20) C[2]=VB[c1&3]|0x40;
645 if (J&0x10) C[3]=VB[c2&3]|0x40;
646 c1>>=2;c2>>=2;
647 if (J&0x80) *C=VB[c1]|0x40;
648 if (J&0x40) C[1]=VB[c2]|0x40;
649 }
650 } else {
651 if (atr&H_FLIP)
652 {
653 if (J&0x02) C[1]=VB[(c1&3)];
654 if (J&0x01) *C=VB[(c2&3)];
655 c1>>=2;c2>>=2;
656 if (J&0x08) C[3]=VB[(c1&3)];
657 if (J&0x04) C[2]=VB[(c2&3)];
658 c1>>=2;c2>>=2;
659 if (J&0x20) C[5]=VB[(c1&3)];
660 if (J&0x10) C[4]=VB[(c2&3)];
661 c1>>=2;c2>>=2;
662 if (J&0x80) C[7]=VB[c1];
663 if (J&0x40) C[6]=VB[c2];
9115e7d2 664 }else{
98733207 665 if (J&0x02) C[6]=VB[(c1&3)];
666 if (J&0x01) C[7]=VB[(c2&3)];
667 c1>>=2;c2>>=2;
668 if (J&0x08) C[4]=VB[(c1&3)];
669 if (J&0x04) C[5]=VB[(c2&3)];
670 c1>>=2;c2>>=2;
671 if (J&0x20) C[2]=VB[(c1&3)];
672 if (J&0x10) C[3]=VB[(c2&3)];
673 c1>>=2;c2>>=2;
674 if (J&0x80) *C=VB[c1];
675 if (J&0x40) C[1]=VB[c2];
676 }
677 }
678 }
679 P-=x;
680 }
681
682 numsprites=0;
683 #ifdef FRAMESKIP
684 if(FSkip) return;
685 #endif
686
687 {
688 uint8 n=((PPU[1]&4)^4)<<1;
689 loopskie:
690 {
691 uint32 t=*((uint32 *)(&(sprlinebuf[n])));
692 if(t!=0x80808080)
693 {
694 #ifdef LSB_FIRST
695 if(!(t&0x80))
696 {
697 if(!(t&0x40)) // Normal sprite
698 P[n]=sprlinebuf[n];
699 else if(P[n]&64) // behind bg sprite
700 P[n]=sprlinebuf[n];
701 }
702
703 if(!(t&0x8000))
704 {
705 if(!(t&0x4000)) // Normal sprite
706 P[n+1]=(sprlinebuf+1)[n];
707 else if(P[n+1]&64) // behind bg sprite
708 P[n+1]=(sprlinebuf+1)[n];
709 }
710
711 if(!(t&0x800000))
712 {
713 if(!(t&0x400000)) // Normal sprite
714 P[n+2]=(sprlinebuf+2)[n];
715 else if(P[n+2]&64) // behind bg sprite
716 P[n+2]=(sprlinebuf+2)[n];
717 }
718
719 if(!(t&0x80000000))
720 {
721 if(!(t&0x40000000)) // Normal sprite
722 P[n+3]=(sprlinebuf+3)[n];
723 else if(P[n+3]&64) // behind bg sprite
724 P[n+3]=(sprlinebuf+3)[n];
725 }
726 #else
727 if(!(t&0x80000000))
728 {
729 if(!(t&0x40)) // Normal sprite
730 P[n]=sprlinebuf[n];
731 else if(P[n]&64) // behind bg sprite
732 P[n]=sprlinebuf[n];
733 }
734
735 if(!(t&0x800000))
736 {
737 if(!(t&0x4000)) // Normal sprite
738 P[n+1]=(sprlinebuf+1)[n];
739 else if(P[n+1]&64) // behind bg sprite
740 P[n+1]=(sprlinebuf+1)[n];
741 }
742
743 if(!(t&0x8000))
744 {
745 if(!(t&0x400000)) // Normal sprite
746 P[n+2]=(sprlinebuf+2)[n];
747 else if(P[n+2]&64) // behind bg sprite
748 P[n+2]=(sprlinebuf+2)[n];
749 }
750
751 if(!(t&0x80))
752 {
753 if(!(t&0x40000000)) // Normal sprite
754 P[n+3]=(sprlinebuf+3)[n];
755 else if(P[n+3]&64) // behind bg sprite
756 P[n+3]=(sprlinebuf+3)[n];
757 }
758 #endif
759 }
760 }
761 n+=4;
762 if(n) goto loopskie;
763 }
764}
765
766
767*/