Gradius fixed
[fceu.git] / ppu.c
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 static uint8 sprlinebuf[256+8];
40 extern void BGRender(uint8 *target);
41 extern int tosprite;
42
43
44 static int maxsprites=8;
45
46
47 void FCEUI_DisableSpriteLimitation(int a)
48 {
49  maxsprites=a?64:8;
50 }
51
52
53 //int printed=1;
54 typedef struct {
55         uint8 y,no,atr,x;
56 } SPR __attribute__((aligned(1)));
57
58 typedef struct {
59   //    uint8 ca[2],atr,x;
60         uint8 ca[2],atr,x;
61   //  union {  int z; }
62
63
64 } SPRB __attribute__((aligned(1)));
65
66
67
68 static uint8 nosprites,SpriteBlurp;
69
70 void 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
123
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
200 extern int FSkip;
201 #endif
202
203 void RefreshSprite(uint8 *target)
204 {
205         int n, minx=256;
206         SPRB *spr;
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
222         nosprites--;
223         spr = (SPRB*)SPRBUF+nosprites;
224
225        for(n=nosprites;n>=0;n--,spr--)
226        {
227         register uint32 J;
228
229         J=spr->ca[0]|spr->ca[1];
230
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           }
244                         if(n==0 && SpriteBlurp && !(PPU_status&0x40))
245                         {
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
280          c1=((spr->ca[0]>>1)&0x55)|(spr->ca[1]&0xAA);
281          c2=(spr->ca[0]&0x55)|((spr->ca[1]<<1)&0xAA);
282
283          C = sprlinebuf+x;
284          VB = (PALRAM+0x10)+((atr&3)<<2);
285
286          {
287           J &= 0xff;
288           if(atr&SP_BACK) J |= 0x4000;
289           if (atr&H_FLIP)
290           {
291            if (J&0x02)  C[1]=VB[c1&3]|(J>>8);
292            if (J&0x01)  *C=VB[c2&3]|(J>>8);
293            c1>>=2;c2>>=2;
294            if (J&0x08)  C[3]=VB[c1&3]|(J>>8);
295            if (J&0x04)  C[2]=VB[c2&3]|(J>>8);
296            c1>>=2;c2>>=2;
297            if (J&0x20)  C[5]=VB[c1&3]|(J>>8);
298            if (J&0x10)  C[4]=VB[c2&3]|(J>>8);
299            c1>>=2;c2>>=2;
300            if (J&0x80)  C[7]=VB[c1]|(J>>8);
301            if (J&0x40)  C[6]=VB[c2]|(J>>8);
302           } else  {
303            if (J&0x02)  C[6]=VB[c1&3]|(J>>8);
304            if (J&0x01)  C[7]=VB[c2&3]|(J>>8);
305            c1>>=2;c2>>=2;
306            if (J&0x08)  C[4]=VB[c1&3]|(J>>8);
307            if (J&0x04)  C[5]=VB[c2&3]|(J>>8);
308            c1>>=2;c2>>=2;
309            if (J&0x20)  C[2]=VB[c1&3]|(J>>8);
310            if (J&0x10)  C[3]=VB[c2&3]|(J>>8);
311            c1>>=2;c2>>=2;
312            if (J&0x80)  *C=VB[c1]|(J>>8);
313            if (J&0x40)  C[1]=VB[c2]|(J>>8);
314           }
315          }
316       }
317      }
318
319      nosprites=0;
320      #ifdef FRAMESKIP
321      if(FSkip) return;
322      #endif
323      if (minx == 256) return; // no visible sprites
324
325      {
326       uint8 n=((PPU[1]&4)^4)<<1;
327       if ((int)n < minx) n = minx & 0xfc;
328       loopskie:
329       {
330        uint32 t=*(uint32 *)(sprlinebuf+n);
331        if(t!=0x80808080)
332        {
333         #ifdef LSB_FIRST
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;
337         }
338
339         if(!(t&0x00008000) && (!(t&0x00004000) || (tb&0x00004000))) {
340           tb &= ~0x0000ff00; tb |= t & 0x0000ff00;
341         }
342
343         if(!(t&0x00800000) && (!(t&0x00400000) || (tb&0x00400000))) {
344           tb &= ~0x00ff0000; tb |= t & 0x00ff0000;
345         }
346
347         if(!(t&0x80000000) && (!(t&0x40000000) || (tb&0x40000000))) {
348           tb &= ~0xff000000; tb |= t & 0xff000000;
349         }
350         *(uint32 *)(target+n)=tb;
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 /*
396 void 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
405
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
449                   // Fix this geniestage hack
450                   if(MMC5Hack && geniestage!=1) C = MMC5SPRVRAMADR(vadr);
451                   else C = VRAMADR(vadr);
452
453
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
532 //                                 scanline option is enabled.
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
547 void RefreshSprite(uint8 *target)
548 {
549
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;
570
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)
580                        {
581                         if(n==0 && SpriteBlurp && !(PPU_status&0x40))
582                         {
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
622          if(atr&SP_BACK)
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];
664           }else{
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 */