savestate and other bugfixes
[fceu.git] / palette.c
1 /* FCE Ultra - NES/Famicom Emulator\r
2  *\r
3  * Copyright notice for this file:\r
4  *  Copyright (C) 2002,2003 Xodnizel\r
5  *\r
6  * This program is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 2 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * This program is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with this program; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  */\r
20 \r
21 #include <stdio.h>\r
22 #include <stdlib.h>\r
23 #include <math.h>\r
24 \r
25 #include "types.h"\r
26 #include "fce.h"\r
27 #include "general.h"\r
28 #include "driver.h"\r
29 \r
30 #include "palette.h"\r
31 #include "palettes/palettes.h"\r
32 \r
33 #include "svga.h"\r
34 \r
35 #ifndef M_PI\r
36 #define M_PI 3.14159265358979323846\r
37 #endif\r
38 \r
39 static int ntsccol=0;\r
40 static int ntsctint=46+10;\r
41 static int ntschue=72;\r
42 \r
43 /* These are dynamically filled/generated palettes: */\r
44 pal palettei[64];       // Custom palette for an individual game.\r
45 pal palettec[64];       // Custom "global" palette.\r
46 pal paletten[64];       // Mathematically generated palette.\r
47 \r
48 static void CalculatePalette(void);\r
49 static void ChoosePalette(void);\r
50 static void WritePalette(void);\r
51 uint8 pale=0;\r
52 \r
53 pal *palo;\r
54 static pal *palpoint[8]=\r
55      {\r
56      palette,\r
57      rp2c04001,\r
58      rp2c04002,\r
59      rp2c04003,\r
60      rp2c05004,\r
61      };\r
62 \r
63 void FCEUI_SetPaletteArray(uint8 *pal)\r
64 {\r
65  if(!pal)\r
66   palpoint[0]=palette;\r
67  else\r
68  {\r
69   int x;\r
70   palpoint[0]=palettec;\r
71   for(x=0;x<64;x++)\r
72   {\r
73    palpoint[0][x].r=*((uint8 *)pal+x+x+x);\r
74    palpoint[0][x].g=*((uint8 *)pal+x+x+x+1);\r
75    palpoint[0][x].b=*((uint8 *)pal+x+x+x+2);\r
76   }\r
77  }\r
78  FCEU_ResetPalette();\r
79 }\r
80 \r
81 \r
82 void FCEUI_SetNTSCTH(int n, int tint, int hue)\r
83 {\r
84  ntsctint=tint;\r
85  ntschue=hue;\r
86  ntsccol=n;\r
87  FCEU_ResetPalette();\r
88 }\r
89 \r
90 static uint8 lastd=0;\r
91 void SetNESDeemph(uint8 d, int force)\r
92 {\r
93  static uint16 rtmul[7]={32768*1.239,32768*.794,32768*1.019,32768*.905,32768*1.023,32768*.741,32768*.75};\r
94  static uint16 gtmul[7]={32768*.915,32768*1.086,32768*.98,32768*1.026,32768*.908,32768*.987,32768*.75};\r
95  static uint16 btmul[7]={32768*.743,32768*.882,32768*.653,32768*1.277,32768*.979,32768*.101,32768*.75};\r
96  uint32 r,g,b;\r
97  int x;\r
98 \r
99  /* If it's not forced(only forced when the palette changes),\r
100     don't waste cpu time if the same deemphasis bits are set as the last call.\r
101  */\r
102  if(!force)\r
103  {\r
104   if(d==lastd)\r
105    return;\r
106  }\r
107  else   /* Only set this when palette has changed. */\r
108  {\r
109   r=rtmul[6];\r
110   g=rtmul[6];\r
111   b=rtmul[6];\r
112 \r
113   for(x=0;x<0x40;x++)\r
114   {\r
115    uint32 m,n,o;\r
116    m=palo[x].r;\r
117    n=palo[x].g;\r
118    o=palo[x].b;\r
119    m=(m*r)>>15;\r
120    n=(n*g)>>15;\r
121    o=(o*b)>>15;\r
122    if(m>0xff) m=0xff;\r
123    if(n>0xff) n=0xff;\r
124    if(o>0xff) o=0xff;\r
125    FCEUD_SetPalette(x|0xC0,m,n,o);\r
126   }\r
127  }\r
128  if(!d) return; /* No deemphasis, so return. */\r
129 \r
130  r=rtmul[d-1];\r
131  g=gtmul[d-1];\r
132  b=btmul[d-1];\r
133 \r
134  for(x=0;x<0x40;x++)\r
135  {\r
136   uint32 m,n,o;\r
137 \r
138   m=palo[x].r;\r
139   n=palo[x].g;\r
140   o=palo[x].b;\r
141   m=(m*r)>>15;\r
142   n=(n*g)>>15;\r
143   o=(o*b)>>15;\r
144   if(m>0xff) m=0xff;\r
145   if(n>0xff) n=0xff;\r
146   if(o>0xff) o=0xff;\r
147 \r
148   FCEUD_SetPalette(x|0x40,m,n,o);\r
149  }\r
150 \r
151  lastd=d;\r
152 }\r
153 \r
154 /* Converted from Kevin Horton's qbasic palette generator. */\r
155 static void CalculatePalette(void)\r
156 {\r
157  int x,z;\r
158  int r,g,b;\r
159  double s,luma,theta;\r
160  static uint8 cols[16]={0,24,21,18,15,12,9,6,3,0,33,30,27,0,0,0};\r
161  static uint8 br1[4]={6,9,12,12};\r
162  static double br2[4]={.29,.45,.73,.9};\r
163  static double br3[4]={0,.24,.47,.77};\r
164 \r
165  for(x=0;x<=3;x++)\r
166   for(z=0;z<16;z++)\r
167   {\r
168    s=(double)ntsctint/128;\r
169    luma=br2[x];\r
170    if(z==0)  {s=0;luma=((double)br1[x])/12;}\r
171 \r
172    if(z>=13)\r
173    {\r
174     s=luma=0;\r
175     if(z==13)\r
176      luma=br3[x];\r
177    }\r
178 \r
179    theta=(double)M_PI*(double)(((double)cols[z]*10+ (((double)ntschue/2)+300) )/(double)180);\r
180    r=(int)((luma+s*sin(theta))*256);\r
181    g=(int)((luma-(double)27/53*s*sin(theta)+(double)10/53*s*cos(theta))*256);\r
182    b=(int)((luma-s*cos(theta))*256);\r
183 \r
184 \r
185    if(r>255) r=255;\r
186    if(g>255) g=255;\r
187    if(b>255) b=255;\r
188    if(r<0) r=0;\r
189    if(g<0) g=0;\r
190    if(b<0) b=0;\r
191 \r
192    paletten[(x<<4)+z].r=r;\r
193    paletten[(x<<4)+z].g=g;\r
194    paletten[(x<<4)+z].b=b;\r
195   }\r
196  WritePalette();\r
197 }\r
198 \r
199 static int ipalette=0;\r
200 \r
201 void FCEU_LoadGamePalette(void)\r
202 {\r
203   uint8 ptmp[192];\r
204   FILE *fp;\r
205   char *fn;\r
206 \r
207   ipalette=0;\r
208 \r
209   fn=FCEU_MakeFName(FCEUMKF_PALETTE,0,0);\r
210 \r
211   if((fp=fopen(fn,"rb")))\r
212   {\r
213    int x;\r
214    fread(ptmp,1,192,fp);\r
215    fclose(fp);\r
216    for(x=0;x<64;x++)\r
217    {\r
218     palettei[x].r=ptmp[x+x+x];\r
219     palettei[x].g=ptmp[x+x+x+1];\r
220     palettei[x].b=ptmp[x+x+x+2];\r
221    }\r
222    ipalette=1;\r
223   }\r
224   free(fn);\r
225 }\r
226 \r
227 void FCEU_ResetPalette(void)\r
228 {\r
229  //if(FCEUGameInfo)\r
230  {\r
231    ChoosePalette();\r
232    WritePalette();\r
233  }\r
234 }\r
235 \r
236 static void ChoosePalette(void)\r
237 {\r
238     if(FCEUGameInfo.type==GIT_NSF)\r
239      palo=0;\r
240     else if(ipalette)\r
241      palo=palettei;\r
242     else if(ntsccol && !PAL && FCEUGameInfo.type!=GIT_VSUNI)\r
243      {\r
244       palo=paletten;\r
245       CalculatePalette();\r
246      }\r
247     else\r
248      palo=palpoint[pale];\r
249 }\r
250 \r
251 void WritePalette(void)\r
252 {\r
253     int x;\r
254 \r
255     for(x=0;x<7;x++)\r
256      FCEUD_SetPalette(x,unvpalette[x].r,unvpalette[x].g,unvpalette[x].b);\r
257     if(FCEUGameInfo.type==GIT_NSF)\r
258     {\r
259      //for(x=0;x<128;x++)\r
260      // FCEUD_SetPalette(x,x,0,x);\r
261     }\r
262     else\r
263     {\r
264      for(x=0;x<64;x++)\r
265       FCEUD_SetPalette(x+128,palo[x].r,palo[x].g,palo[x].b);\r
266      SetNESDeemph(lastd,1);\r
267     }\r
268 }\r
269 \r
270 void FCEUI_GetNTSCTH(int *tint, int *hue)\r
271 {\r
272  *tint=ntsctint;\r
273  *hue=ntschue;\r
274 }\r
275 \r
276 static int controlselect=0;\r
277 static int controllength=0;\r
278 \r
279 void FCEUI_NTSCDEC(void)\r
280 {\r
281         if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI &&!PAL && FCEUGameInfo.type!=GIT_NSF)\r
282         {\r
283          int which;\r
284          if(controlselect)\r
285          {\r
286           if(controllength)\r
287           {\r
288            which=controlselect==1?ntschue:ntsctint;\r
289            which--;\r
290            if(which<0) which=0;\r
291            if(controlselect==1)\r
292             ntschue=which;\r
293            else ntsctint=which;\r
294            CalculatePalette();\r
295           }\r
296           controllength=360;\r
297          }\r
298         }\r
299 }\r
300 \r
301 void FCEUI_NTSCINC(void)\r
302 {\r
303                    if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF)\r
304                      if(controlselect)\r
305                      {\r
306                       if(controllength)\r
307                       {\r
308                        switch(controlselect)\r
309                        {\r
310                         case 1:ntschue++;\r
311                                if(ntschue>128) ntschue=128;\r
312                                CalculatePalette();\r
313                                break;\r
314                         case 2:ntsctint++;\r
315                                if(ntsctint>128) ntsctint=128;\r
316                                CalculatePalette();\r
317                                break;\r
318                        }\r
319                       }\r
320                       controllength=360;\r
321                      }\r
322 }\r
323 \r
324 void FCEUI_NTSCSELHUE(void)\r
325 {\r
326  if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF){controlselect=1;controllength=360;}\r
327 }\r
328 \r
329 void FCEUI_NTSCSELTINT(void)\r
330 {\r
331  if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF){controlselect=2;controllength=360;}\r
332 }\r
333 \r
334 void FCEU_DrawNTSCControlBars(uint8 *XBuf)\r
335 {\r
336  uint8 *XBaf;\r
337  int which=0;\r
338  int x,x2;\r
339 \r
340  if(!controllength) return;\r
341  controllength--;\r
342  if(!XBuf) return;\r
343 \r
344  if(controlselect==1)\r
345  {\r
346   DrawTextTrans(XBuf+128-12+180*256, 256, (uint8 *)"Hue", 0x85);\r
347   which=ntschue<<1;\r
348  }\r
349  else if(controlselect==2)\r
350  {\r
351   DrawTextTrans(XBuf+128-16+180*256, 256, (uint8 *)"Tint", 0x85);\r
352   which=ntsctint<<1;\r
353  }\r
354 \r
355  XBaf=XBuf+200*256;\r
356  for(x=0;x<which;x+=2)\r
357  {\r
358   for(x2=6;x2>=-6;x2--)\r
359   {\r
360    XBaf[x-256*x2]=0x85;\r
361   }\r
362  }\r
363  for(;x<256;x+=2)\r
364  {\r
365   for(x2=2;x2>=-2;x2--)\r
366    XBaf[x-256*x2]=0x85;\r
367  }\r
368 }\r