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