palette change to reflect .15 code
[fceu.git] / palette.c
CommitLineData
92764e62 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
39static int ntsccol=0;\r
40static int ntsctint=46+10;\r
41static int ntschue=72;\r
42\r
43/* These are dynamically filled/generated palettes: */\r
44pal palettei[64]; // Custom palette for an individual game.\r
45pal palettec[64]; // Custom "global" palette.\r
46pal paletten[64]; // Mathematically generated palette.\r
47\r
48static void CalculatePalette(void);\r
49static void ChoosePalette(void);\r
50static void WritePalette(void);\r
51uint8 pale=0;\r
52\r
53pal *palo;\r
54static 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
63void 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
82void 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
90static uint8 lastd=0;\r
91void 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
155static 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
199static int ipalette=0;\r
200\r
201void 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
227void FCEU_ResetPalette(void)\r
228{\r
229 //if(FCEUGameInfo)\r
230 {\r
231 ChoosePalette();\r
232 WritePalette();\r
233 }\r
234}\r
235\r
236static 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
251void WritePalette(void)\r
252{\r
253 int x;\r
254\r
255 for(x=0;x<7;x++)\r
6587f346 256 FCEUD_SetPalette(x,unvpalette[x].r,unvpalette[x].g,unvpalette[x].b);\r
92764e62 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
92764e62 261 }\r
262 else\r
263 {\r
264 for(x=0;x<64;x++)\r
6587f346 265 FCEUD_SetPalette(x+128,palo[x].r,palo[x].g,palo[x].b);\r
92764e62 266 SetNESDeemph(lastd,1);\r
267 }\r
268}\r
269\r
270void FCEUI_GetNTSCTH(int *tint, int *hue)\r
271{\r
272 *tint=ntsctint;\r
273 *hue=ntschue;\r
274}\r
275\r
276static int controlselect=0;\r
277static int controllength=0;\r
278\r
279void 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
301void 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
324void 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
329void 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
334void 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