some warnings fixed, nsf fixed, palettes, more code backported
[fceu.git] / palette.c
diff --git a/palette.c b/palette.c
new file mode 100644 (file)
index 0000000..27342fd
--- /dev/null
+++ b/palette.c
@@ -0,0 +1,370 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002,2003 Xodnizel\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+\r
+#include "types.h"\r
+#include "fce.h"\r
+#include "general.h"\r
+#include "driver.h"\r
+\r
+#include "palette.h"\r
+#include "palettes/palettes.h"\r
+\r
+#include "svga.h"\r
+\r
+#ifndef M_PI\r
+#define M_PI 3.14159265358979323846\r
+#endif\r
+\r
+static int ntsccol=0;\r
+static int ntsctint=46+10;\r
+static int ntschue=72;\r
+\r
+/* These are dynamically filled/generated palettes: */\r
+pal palettei[64];       // Custom palette for an individual game.\r
+pal palettec[64];       // Custom "global" palette.\r
+pal paletten[64];       // Mathematically generated palette.\r
+\r
+static void CalculatePalette(void);\r
+static void ChoosePalette(void);\r
+static void WritePalette(void);\r
+uint8 pale=0;\r
+\r
+pal *palo;\r
+static pal *palpoint[8]=\r
+     {\r
+     palette,\r
+     rp2c04001,\r
+     rp2c04002,\r
+     rp2c04003,\r
+     rp2c05004,\r
+     };\r
+\r
+void FCEUI_SetPaletteArray(uint8 *pal)\r
+{\r
+ if(!pal)\r
+  palpoint[0]=palette;\r
+ else\r
+ {\r
+  int x;\r
+  palpoint[0]=palettec;\r
+  for(x=0;x<64;x++)\r
+  {\r
+   palpoint[0][x].r=*((uint8 *)pal+x+x+x);\r
+   palpoint[0][x].g=*((uint8 *)pal+x+x+x+1);\r
+   palpoint[0][x].b=*((uint8 *)pal+x+x+x+2);\r
+  }\r
+ }\r
+ FCEU_ResetPalette();\r
+}\r
+\r
+\r
+void FCEUI_SetNTSCTH(int n, int tint, int hue)\r
+{\r
+ ntsctint=tint;\r
+ ntschue=hue;\r
+ ntsccol=n;\r
+ FCEU_ResetPalette();\r
+}\r
+\r
+static uint8 lastd=0;\r
+void SetNESDeemph(uint8 d, int force)\r
+{\r
+ static uint16 rtmul[7]={32768*1.239,32768*.794,32768*1.019,32768*.905,32768*1.023,32768*.741,32768*.75};\r
+ static uint16 gtmul[7]={32768*.915,32768*1.086,32768*.98,32768*1.026,32768*.908,32768*.987,32768*.75};\r
+ static uint16 btmul[7]={32768*.743,32768*.882,32768*.653,32768*1.277,32768*.979,32768*.101,32768*.75};\r
+ uint32 r,g,b;\r
+ int x;\r
+\r
+ /* If it's not forced(only forced when the palette changes),\r
+    don't waste cpu time if the same deemphasis bits are set as the last call.\r
+ */\r
+ if(!force)\r
+ {\r
+  if(d==lastd)\r
+   return;\r
+ }\r
+ else   /* Only set this when palette has changed. */\r
+ {\r
+  r=rtmul[6];\r
+  g=rtmul[6];\r
+  b=rtmul[6];\r
+\r
+  for(x=0;x<0x40;x++)\r
+  {\r
+   uint32 m,n,o;\r
+   m=palo[x].r;\r
+   n=palo[x].g;\r
+   o=palo[x].b;\r
+   m=(m*r)>>15;\r
+   n=(n*g)>>15;\r
+   o=(o*b)>>15;\r
+   if(m>0xff) m=0xff;\r
+   if(n>0xff) n=0xff;\r
+   if(o>0xff) o=0xff;\r
+   FCEUD_SetPalette(x|0xC0,m,n,o);\r
+  }\r
+ }\r
+ if(!d) return; /* No deemphasis, so return. */\r
+\r
+ r=rtmul[d-1];\r
+ g=gtmul[d-1];\r
+ b=btmul[d-1];\r
+\r
+ for(x=0;x<0x40;x++)\r
+ {\r
+  uint32 m,n,o;\r
+\r
+  m=palo[x].r;\r
+  n=palo[x].g;\r
+  o=palo[x].b;\r
+  m=(m*r)>>15;\r
+  n=(n*g)>>15;\r
+  o=(o*b)>>15;\r
+  if(m>0xff) m=0xff;\r
+  if(n>0xff) n=0xff;\r
+  if(o>0xff) o=0xff;\r
+\r
+  FCEUD_SetPalette(x|0x40,m,n,o);\r
+ }\r
+\r
+ lastd=d;\r
+}\r
+\r
+/* Converted from Kevin Horton's qbasic palette generator. */\r
+static void CalculatePalette(void)\r
+{\r
+ int x,z;\r
+ int r,g,b;\r
+ double s,luma,theta;\r
+ static uint8 cols[16]={0,24,21,18,15,12,9,6,3,0,33,30,27,0,0,0};\r
+ static uint8 br1[4]={6,9,12,12};\r
+ static double br2[4]={.29,.45,.73,.9};\r
+ static double br3[4]={0,.24,.47,.77};\r
+\r
+ for(x=0;x<=3;x++)\r
+  for(z=0;z<16;z++)\r
+  {\r
+   s=(double)ntsctint/128;\r
+   luma=br2[x];\r
+   if(z==0)  {s=0;luma=((double)br1[x])/12;}\r
+\r
+   if(z>=13)\r
+   {\r
+    s=luma=0;\r
+    if(z==13)\r
+     luma=br3[x];\r
+   }\r
+\r
+   theta=(double)M_PI*(double)(((double)cols[z]*10+ (((double)ntschue/2)+300) )/(double)180);\r
+   r=(int)((luma+s*sin(theta))*256);\r
+   g=(int)((luma-(double)27/53*s*sin(theta)+(double)10/53*s*cos(theta))*256);\r
+   b=(int)((luma-s*cos(theta))*256);\r
+\r
+\r
+   if(r>255) r=255;\r
+   if(g>255) g=255;\r
+   if(b>255) b=255;\r
+   if(r<0) r=0;\r
+   if(g<0) g=0;\r
+   if(b<0) b=0;\r
+\r
+   paletten[(x<<4)+z].r=r;\r
+   paletten[(x<<4)+z].g=g;\r
+   paletten[(x<<4)+z].b=b;\r
+  }\r
+ WritePalette();\r
+}\r
+\r
+static int ipalette=0;\r
+\r
+void FCEU_LoadGamePalette(void)\r
+{\r
+  uint8 ptmp[192];\r
+  FILE *fp;\r
+  char *fn;\r
+\r
+  ipalette=0;\r
+\r
+  fn=FCEU_MakeFName(FCEUMKF_PALETTE,0,0);\r
+\r
+  if((fp=fopen(fn,"rb")))\r
+  {\r
+   int x;\r
+   fread(ptmp,1,192,fp);\r
+   fclose(fp);\r
+   for(x=0;x<64;x++)\r
+   {\r
+    palettei[x].r=ptmp[x+x+x];\r
+    palettei[x].g=ptmp[x+x+x+1];\r
+    palettei[x].b=ptmp[x+x+x+2];\r
+   }\r
+   ipalette=1;\r
+  }\r
+  free(fn);\r
+}\r
+\r
+void FCEU_ResetPalette(void)\r
+{\r
+ //if(FCEUGameInfo)\r
+ {\r
+   ChoosePalette();\r
+   WritePalette();\r
+ }\r
+}\r
+\r
+static void ChoosePalette(void)\r
+{\r
+    if(FCEUGameInfo.type==GIT_NSF)\r
+     palo=0;\r
+    else if(ipalette)\r
+     palo=palettei;\r
+    else if(ntsccol && !PAL && FCEUGameInfo.type!=GIT_VSUNI)\r
+     {\r
+      palo=paletten;\r
+      CalculatePalette();\r
+     }\r
+    else\r
+     palo=palpoint[pale];\r
+}\r
+\r
+void WritePalette(void)\r
+{\r
+    int x;\r
+\r
+    for(x=0;x<7;x++)\r
+     FCEUD_SetPalette(128+x,unvpalette[x].r,unvpalette[x].g,unvpalette[x].b);\r
+    if(FCEUGameInfo.type==GIT_NSF)\r
+    {\r
+     //for(x=0;x<128;x++)\r
+     // FCEUD_SetPalette(x,x,0,x);\r
+     for(x=0;x<7;x++)\r
+      FCEUD_SetPalette(x,unvpalette[x].r,unvpalette[x].g,unvpalette[x].b);\r
+    }\r
+    else\r
+    {\r
+     for(x=0;x<64;x++)\r
+      FCEUD_SetPalette(x,palo[x].r,palo[x].g,palo[x].b);\r
+     SetNESDeemph(lastd,1);\r
+    }\r
+}\r
+\r
+void FCEUI_GetNTSCTH(int *tint, int *hue)\r
+{\r
+ *tint=ntsctint;\r
+ *hue=ntschue;\r
+}\r
+\r
+static int controlselect=0;\r
+static int controllength=0;\r
+\r
+void FCEUI_NTSCDEC(void)\r
+{\r
+       if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI &&!PAL && FCEUGameInfo.type!=GIT_NSF)\r
+        {\r
+         int which;\r
+         if(controlselect)\r
+         {\r
+          if(controllength)\r
+          {\r
+           which=controlselect==1?ntschue:ntsctint;\r
+           which--;\r
+           if(which<0) which=0;\r
+           if(controlselect==1)\r
+            ntschue=which;\r
+           else ntsctint=which;\r
+           CalculatePalette();\r
+          }\r
+          controllength=360;\r
+         }\r
+       }\r
+}\r
+\r
+void FCEUI_NTSCINC(void)\r
+{\r
+                   if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF)\r
+                     if(controlselect)\r
+                     {\r
+                      if(controllength)\r
+                      {\r
+                       switch(controlselect)\r
+                       {\r
+                        case 1:ntschue++;\r
+                               if(ntschue>128) ntschue=128;\r
+                               CalculatePalette();\r
+                               break;\r
+                        case 2:ntsctint++;\r
+                               if(ntsctint>128) ntsctint=128;\r
+                               CalculatePalette();\r
+                               break;\r
+                       }\r
+                      }\r
+                      controllength=360;\r
+                     }\r
+}\r
+\r
+void FCEUI_NTSCSELHUE(void)\r
+{\r
+ if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF){controlselect=1;controllength=360;}\r
+}\r
+\r
+void FCEUI_NTSCSELTINT(void)\r
+{\r
+ if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF){controlselect=2;controllength=360;}\r
+}\r
+\r
+void FCEU_DrawNTSCControlBars(uint8 *XBuf)\r
+{\r
+ uint8 *XBaf;\r
+ int which=0;\r
+ int x,x2;\r
+\r
+ if(!controllength) return;\r
+ controllength--;\r
+ if(!XBuf) return;\r
+\r
+ if(controlselect==1)\r
+ {\r
+  DrawTextTrans(XBuf+128-12+180*256, 256, (uint8 *)"Hue", 0x85);\r
+  which=ntschue<<1;\r
+ }\r
+ else if(controlselect==2)\r
+ {\r
+  DrawTextTrans(XBuf+128-16+180*256, 256, (uint8 *)"Tint", 0x85);\r
+  which=ntsctint<<1;\r
+ }\r
+\r
+ XBaf=XBuf+200*256;\r
+ for(x=0;x<which;x+=2)\r
+ {\r
+  for(x2=6;x2>=-6;x2--)\r
+  {\r
+   XBaf[x-256*x2]=0x85;\r
+  }\r
+ }\r
+ for(;x<256;x+=2)\r
+ {\r
+  for(x2=2;x2>=-2;x2--)\r
+   XBaf[x-256*x2]=0x85;\r
+ }\r
+}\r