palette change to reflect .15 code
[fceu.git] / svga.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 1998 BERO
5  *  Copyright (C) 2002 Ben Parnell
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /*                      SVGA High Level Routines
23                           FCE / FCE Ultra
24 */
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <math.h>
28 #include <string.h>
29
30 #include <stdarg.h>
31
32
33 #ifndef M_PI
34 #define M_PI 3.14159265358979323846
35 #endif
36
37 #include "types.h"
38 #include "svga.h"
39 #include "fce.h"
40 #include "general.h"
41 #include "video.h"
42 #include "sound.h"
43 #include "version.h"
44 #include "nsf.h"
45 #include "palette.h"
46 #include "fds.h"
47 #include "netplay.h"
48 #include "state.h"
49 #include "cart.h"
50 #include "input.h"
51
52 #include "vsuni.h"
53
54 FCEUS FSettings;
55
56 static int howlong;
57 static char errmsg[65];
58
59 void FCEU_PrintError(char *format, ...)
60 {
61  char temp[2048];
62
63  va_list ap;
64
65  va_start(ap,format);
66  vsprintf(temp,format,ap);
67  FCEUD_PrintError(temp);
68
69  va_end(ap);
70 }
71
72 void FCEU_DispMessage(char *format, ...)
73 {
74  va_list ap;
75
76  va_start(ap,format);
77  vsprintf(errmsg,format,ap);
78  va_end(ap);
79
80  howlong=180;
81  printf("%s\n", errmsg);
82 }
83
84 void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall)
85 {
86  FSettings.UsrFirstSLine[0]=ntscf;
87  FSettings.UsrLastSLine[0]=ntscl;
88  FSettings.UsrFirstSLine[1]=palf;
89  FSettings.UsrLastSLine[1]=pall;
90  if(PAL)
91  {
92   FSettings.FirstSLine=FSettings.UsrFirstSLine[1];
93   FSettings.LastSLine=FSettings.UsrLastSLine[1];
94  }
95  else
96  {
97   FSettings.FirstSLine=FSettings.UsrFirstSLine[0];
98   FSettings.LastSLine=FSettings.UsrLastSLine[0];
99  }
100
101 }
102
103 void FCEUI_SetVidSystem(int a)
104 {
105  FSettings.PAL=a?1:0;
106  FCEU_ResetVidSys();
107  FCEU_ResetPalette();
108 }
109
110 int FCEUI_GetCurrentVidSystem(int *slstart, int *slend)
111 {
112  if(slstart)
113   *slstart=FSettings.FirstSLine;
114  if(slend)
115   *slend=FSettings.LastSLine;
116  return(PAL);
117 }
118
119 #ifdef NETWORK
120 void FCEUI_SetNetworkPlay(int type)
121 {
122  FSettings.NetworkPlay=type;
123 }
124 #endif
125
126 void FCEUI_SetGameGenie(int a)
127 {
128  FSettings.GameGenie=a?1:0;
129 }
130
131 #ifndef NETWORK
132 #define netplay 0
133 #endif
134
135 static uint8 StateShow=0;
136
137 uint8 Exit=0;
138
139 uint8 DIPS=0;
140 //uint8 vsdip=0;
141 //int coinon=0;
142
143 //uint8 pale=0;
144 uint8 CommandQueue=0;
145
146 static int controlselect=0;
147 static int ntsccol=0;
148 static int ntsctint=46+10;
149 static int ntschue=72;
150 static int controllength=0;
151
152 #if 0
153 pal *palo;
154 static pal *palpoint[8]=
155      {
156      palette,
157      palettevscv,
158      palettevssmb,
159      palettevsmar,
160      palettevsgoon,
161      palettevsslalom,
162      palettevseb,
163      rp2c04001
164      };
165 #endif
166
167 void FCEUI_SetSnapName(int a)
168 {
169  FSettings.SnapName=a;
170 }
171
172 void FCEUI_SaveExtraDataUnderBase(int a)
173 {
174  FSettings.SUnderBase=a;
175 }
176
177 #if 0
178 void FCEUI_SetPaletteArray(uint8 *pal)
179 {
180  if(!pal)
181   palpoint[0]=palette;
182  else
183  {
184   int x;
185   palpoint[0]=palettec;
186   for(x=0;x<64;x++)
187   {
188    palpoint[0][x].r=*((uint8 *)pal+x+x+x);
189    palpoint[0][x].g=*((uint8 *)pal+x+x+x+1);
190    palpoint[0][x].b=*((uint8 *)pal+x+x+x+2);
191   }
192  }
193  FCEU_ResetPalette();
194 }
195 #endif
196
197 void FCEUI_SelectState(int w)
198 {
199  if(netplay!=2 && FCEUGameInfo.type!=GIT_NSF)
200   CommandQueue=42+w;
201 }
202
203 void FCEUI_SaveState(void)
204 {
205  if(netplay!=2 && FCEUGameInfo.type!=GIT_NSF)
206   CommandQueue=40;
207 }
208
209 void FCEUI_LoadState(void)
210 {
211  if(netplay!=2 && FCEUGameInfo.type!=GIT_NSF)
212   CommandQueue=41;
213 }
214
215 int32 FCEUI_GetDesiredFPS(void)
216 {
217   if(PAL)
218    return(838977920); // ~50.007
219   else
220    return(1008307711);  // ~60.1
221 }
222
223 static int dosnapsave=0;
224 void FCEUI_SaveSnapshot(void)
225 {
226  dosnapsave=1;
227 }
228
229 /* I like the sounds of breaking necks. */
230 static void ReallySnap(void)
231 {
232  int x=SaveSnapshot();
233  if(!x)
234   FCEU_DispMessage("Error saving screen snapshot.");
235  else
236   FCEU_DispMessage("Screen snapshot %d saved.",x-1);
237 }
238
239 void DriverInterface(int w, void *d)
240 {
241  switch(w)
242  {
243   case DES_NTSCCOL:ntsccol=*(int *)d;FCEU_ResetPalette();break;
244   case DES_RESET:if(netplay!=2) CommandQueue=30;break;
245   case DES_POWER:if(netplay!=2) CommandQueue=31;break;
246   case DES_GETNTSCTINT:*(int*)d=ntsctint;break;
247   case DES_GETNTSCHUE:*(int*)d=ntschue;break;
248   case DES_SETNTSCTINT:ntsctint=*(int*)d;if(ntsccol)FCEU_ResetPalette();break;
249   case DES_SETNTSCHUE:ntschue=*(int*)d;if(ntsccol)FCEU_ResetPalette();break;
250
251   case DES_FDSINSERT:if(netplay!=2) CommandQueue=2;break;
252   case DES_FDSEJECT:if(netplay!=2) CommandQueue=3;break;
253   case DES_FDSSELECT:if(netplay!=2) CommandQueue=1;break;
254 /*
255   case DES_NSFINC:NSFControl(1);break;
256   case DES_NSFDEC:NSFControl(2);break;
257   case DES_NSFRES:NSFControl(0);break;
258 */
259   case DES_VSUNIDIPSET:CommandQueue=10+(int)d;break;
260   case DES_VSUNITOGGLEDIPVIEW:CommandQueue=10;break;
261   case DES_VSUNICOIN:CommandQueue=19;break;
262   case DES_NTSCSELHUE:if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF){controlselect=1;controllength=360;}break;
263   case DES_NTSCSELTINT:if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF){controlselect=2;controllength=360;}break;
264 #if 0
265   case DES_NTSCDEC:
266                   if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF)
267                   {
268                    char which;
269                    if(controlselect)
270                    {
271                     if(controllength)
272                     {
273                      which=controlselect==1?ntschue:ntsctint;
274                      which--;
275                      if(which<0) which=0;
276                          if(controlselect==1)
277                           ntschue=which;
278                          else ntsctint=which;
279                      CalculatePalette();
280                     }
281                    controllength=360;
282                     }
283                    }
284                   break;
285   case DES_NTSCINC:
286                    if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF)
287                      if(controlselect)
288                      {
289                       if(controllength)
290                       {
291                        switch(controlselect)
292                        {
293                         case 1:ntschue++;
294                                if(ntschue>128) ntschue=128;
295                                CalculatePalette();
296                                break;
297                         case 2:ntsctint++;
298                                if(ntsctint>128) ntsctint=128;
299                                CalculatePalette();
300                                break;
301                        }
302                       }
303                       controllength=360;
304                      }
305                     break;
306 #endif
307   }
308 }
309
310 #if 0
311 static uint8 lastd=0;
312 void SetNESDeemph(uint8 d, int force)
313 {
314  static uint16 rtmul[7]={32768*1.239,32768*.794,32768*1.019,32768*.905,32768*1.023,32768*.741,32768*.75};
315  static uint16 gtmul[7]={32768*.915,32768*1.086,32768*.98,32768*1.026,32768*.908,32768*.987,32768*.75};
316  static uint16 btmul[7]={32768*.743,32768*.882,32768*.653,32768*1.277,32768*.979,32768*.101,32768*.75};
317  uint32 r,g,b;
318  int x;
319
320  /* If it's not forced(only forced when the palette changes),
321     don't waste cpu time if the same deemphasis bits are set as the last call.
322  */
323  if(!force)
324  {
325   if(d==lastd)
326    return;
327  }
328  else   /* Only set this when palette has changed. */
329  {
330   r=rtmul[6];
331   g=rtmul[6];
332   b=rtmul[6];
333
334   for(x=0;x<0x40;x++)
335   {
336    uint32 m,n,o;
337    m=palo[x].r;
338    n=palo[x].g;
339    o=palo[x].b;
340    m=(m*r)>>15;
341    n=(n*g)>>15;
342    o=(o*b)>>15;
343    if(m>0xff) m=0xff;
344    if(n>0xff) n=0xff;
345    if(o>0xff) o=0xff;
346    FCEUD_SetPalette(x|0x40,m,n,o);
347
348
349   }
350  }
351  if(!d) return; /* No deemphasis, so return. */
352
353   r=rtmul[d-1];
354   g=gtmul[d-1];
355   b=btmul[d-1];
356
357     for(x=0;x<0x40;x++)
358     {
359      uint32 m,n,o;
360
361      m=palo[x].r;
362      n=palo[x].g;
363      o=palo[x].b;
364      m=(m*r)>>15;
365      n=(n*g)>>15;
366      o=(o*b)>>15;
367      if(m>0xff) m=0xff;
368      if(n>0xff) n=0xff;
369      if(o>0xff) o=0xff;
370
371      FCEUD_SetPalette(x|0xC0,m,n,o);
372
373     }
374
375  lastd=d;
376 }
377
378 #define HUEVAL  ((double)((double)ntschue/(double)2)+(double)300)
379 #define TINTVAL ((double)((double)ntsctint/(double)128))
380
381 static void CalculatePalette(void)
382 {
383  int x,z;
384  int r,g,b;
385  double s,y,theta;
386  static uint8 cols[16]={0,24,21,18,15,12,9,6,3,0,33,30,27,0,0,0};
387  static uint8 br1[4]={6,9,12,12};
388  static double br2[4]={.29,.45,.73,.9};
389  static double br3[4]={0,.24,.47,.77};
390
391  for(x=0;x<=3;x++)
392   for(z=0;z<16;z++)
393   {
394    s=(double)TINTVAL;
395    y=(double)br2[x];
396    if(z==0)  {s=0;y=((double)br1[x])/12;}
397
398    if(z>=13)
399    {
400     s=y=0;
401     if(z==13)
402      y=(double)br3[x];
403    }
404
405    theta=(double)M_PI*(double)(((double)cols[z]*10+HUEVAL)/(double)180);
406    r=(int)(((double)y+(double)s*(double)sin(theta))*(double)256);
407    g=(int)(((double)y-(double)((double)27/(double)53)*s*(double)sin(theta)+(double)((double)10/(double)53)*s*cos(theta))*(double)256);
408    b=(int)(((double)y-(double)s*(double)cos(theta))*(double)256);
409
410    // TODO:  Fix RGB to compensate for phosphor changes(add to red??).
411
412    if(r>255) r=255;
413    if(g>255) g=255;
414    if(b>255) b=255;
415    if(r<0) r=0;
416    if(g<0) g=0;
417    if(b<0) b=0;
418
419    paletten[(x<<4)+z].r=r;
420    paletten[(x<<4)+z].g=g;
421    paletten[(x<<4)+z].b=b;
422   }
423  WritePalette();
424 }
425 #endif
426
427 #include "drawing.h"
428 #ifdef FRAMESKIP
429 void FCEU_PutImageDummy(void)
430 {
431  if(FCEUGameInfo.type!=GIT_NSF)
432  {
433   if(controllength) controllength--;
434  }
435  if(StateShow) StateShow--; /* DrawState() */
436  if(howlong) howlong--; /* DrawMessage() */
437  #ifdef FPS
438  {
439   extern uint64 frcount;
440   frcount++;
441  }
442  #endif
443
444 }
445 #endif
446
447 void FCEU_PutImage(void)
448 {
449         if(FCEUGameInfo.type==GIT_NSF)
450         {
451          DrawNSF(XBuf);
452          /* Save snapshot after NSF screen is drawn.  Why would we want to
453             do it before?
454          */
455          if(dosnapsave)
456          {
457           ReallySnap();
458           dosnapsave=0;
459          }
460         }
461         else
462         {
463          /* Save snapshot before overlay stuff is written. */
464          if(dosnapsave)
465          {
466           ReallySnap();
467           dosnapsave=0;
468          }
469          if(FCEUGameInfo.type==GIT_VSUNI)
470                  FCEU_VSUniDraw(XBuf);
471          //if(StateShow) DrawState();
472
473          //FCEU_DrawSaveStates(XBuf);
474          //FCEU_DrawMovies(XBuf);
475          //FCEU_DrawNTSCControlBars(XBuf);
476          //FCEU_DrawRecordingStatus(XBuf);
477
478          //if(controllength) {controllength--;DrawBars();}
479         }
480         DrawMessage();
481         #ifdef FPS
482         {
483         extern uint64 frcount;
484         frcount++;
485         }
486         #endif
487         DrawInput(XBuf+8);
488 }
489
490 #if 0
491 static int ipalette=0;
492
493 void LoadGamePalette(void)
494 {
495   uint8 ptmp[192];
496   FILE *fp;
497   ipalette=0;
498   if((fp=fopen(FCEU_MakeFName(FCEUMKF_PALETTE,0,0),"rb")))
499   {
500    int x;
501    fread(ptmp,1,192,fp);
502    fclose(fp);
503    for(x=0;x<64;x++)
504    {
505     palettei[x].r=ptmp[x+x+x];
506     palettei[x].g=ptmp[x+x+x+1];
507     palettei[x].b=ptmp[x+x+x+2];
508    }
509    ipalette=1;
510   }
511 }
512
513 void FCEU_ResetPalette(void)
514 {
515    ChoosePalette();
516    WritePalette();
517 }
518
519 static void ChoosePalette(void)
520 {
521     if(FCEUGameInfo.type==GIT_NSF)
522      palo=NSFPalette;
523     else if(ipalette)
524      palo=palettei;
525     else if(ntsccol && !PAL && FCEUGameInfo.type!=GIT_VSUNI)
526      {
527       palo=paletten;
528       CalculatePalette();
529      }
530     else
531      palo=palpoint[pale];
532 }
533
534 void WritePalette(void)
535 {
536     int x;
537
538     for(x=0;x<6;x++)
539      FCEUD_SetPalette(x+128,unvpalette[x].r,unvpalette[x].g,unvpalette[x].b);
540     if(FCEUGameInfo.type==GIT_NSF)
541     {
542      for(x=0;x<39;x++)
543       FCEUD_SetPalette(x,palo[x].r,palo[x].g,palo[x].b);
544     }
545     else
546     {
547      for(x=0;x<64;x++)
548       FCEUD_SetPalette(x,palo[x].r,palo[x].g,palo[x].b);
549      SetNESDeemph(lastd,1);
550     }
551 }
552
553 void FlushCommandQueue(void)
554 {
555   if(!netplay && CommandQueue) {DoCommand(CommandQueue);CommandQueue=0;}
556 }
557
558 void DoCommand(uint8 c)
559 {
560  switch(c)
561  {
562   case 1:FDSControl(FDS_SELECT);break;
563   case 2:FDSControl(FDS_IDISK);break;
564   case 3:FDSControl(FDS_EJECT);break;
565
566   case 10:DIPS^=2;break;
567   case 11:vsdip^=1;DIPS|=2;break;
568   case 12:vsdip^=2;DIPS|=2;break;
569   case 13:vsdip^=4;DIPS|=2;break;
570   case 14:vsdip^=8;DIPS|=2;break;
571   case 15:vsdip^=0x10;DIPS|=2;break;
572   case 16:vsdip^=0x20;DIPS|=2;break;
573   case 17:vsdip^=0x40;DIPS|=2;break;
574   case 18:vsdip^=0x80;DIPS|=2;break;
575   case 19:coinon=6;break;
576   case 30:ResetNES();break;
577   case 31:PowerNES();break;
578   case 40:CheckStates();StateShow=0;SaveState();break;
579   case 41:CheckStates();StateShow=0;LoadState();break;
580   case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49:
581   case 50: case 51:StateShow=180;CurrentState=c-42;CheckStates();break;
582  }
583 }
584 #endif
585