diff --git a/src/driver.h b/src/driver.h index 0348058..e7664ad 100644 --- a/src/driver.h +++ b/src/driver.h @@ -136,7 +136,7 @@ void FCEUI_SetBaseDirectory(const char *dir); /* Tells FCE Ultra to copy the palette data pointed to by pal and use it. Data pointed to by pal needs to be 64*3 bytes in length. */ -void FCEUI_SetPaletteArray(uint8 *pal); +void FCEUI_SetPaletteArray(uint8 *pal, int nEntries); /* Sets up sound code to render sound at the specified rate, in samples per second. Only sample rates of 44100, 48000, and 96000 are currently diff --git a/src/drivers/libretro/libretro.c b/src/drivers/libretro/libretro.c index cca512a..aff8c87 100644 --- a/src/drivers/libretro/libretro.c +++ b/src/drivers/libretro/libretro.c @@ -284,6 +284,12 @@ void FCEUD_SetPalette(uint16 index, uint8_t r, uint8_t g, uint8_t b) } #endif +#if defined(PSP) || defined(PS2) + /* PS2 / PSP will only have 256 colors */ + if (index >= 256) + return; +#endif + #ifdef FRONTEND_SUPPORTS_RGB565 retro_palette[index_to_write] = BUILD_PIXEL_RGB565(r >> RED_EXPAND, g >> GREEN_EXPAND, b >> BLUE_EXPAND); #else @@ -368,8 +374,7 @@ void FCEUD_SoundToggle (void) #define PAL_CUSTOM (PAL_INTERNAL + 3) #define PAL_TOTAL PAL_CUSTOM -static int external_palette_exist = 0; -extern int ipalette; +static uint8 external_palette_exist = false; /* table for currently loaded palette */ static uint8_t base_palette[192]; @@ -1163,13 +1168,13 @@ static void NTSCFilter_Setup(void) } ntsc_setup.merge_fields = 0; - if ((GameInfo->type != GIT_VSUNI) && (current_palette == PAL_DEFAULT || current_palette == PAL_RAW)) + if (GameInfo && (GameInfo->type != GIT_VSUNI) && (current_palette == PAL_DEFAULT || current_palette == PAL_RAW)) /* use ntsc default palette instead of internal default palette for that "identity" effect */ - ntsc_setup.base_palette = NULL; + ntsc_setup.palette = NULL; else /* use internal palette, this includes palette presets, external palette and custom palettes * for VS. System games */ - ntsc_setup.base_palette = (unsigned char const *)palo; + ntsc_setup.palette = (unsigned char const *)palo; nes_ntsc_init(&nes_ntsc, &ntsc_setup); } @@ -1740,7 +1745,7 @@ static void retro_set_custom_palette(void) { unsigned i; - ipalette = 0; + palette_game_available = 0; use_raw_palette = false; /* VS UNISystem uses internal palette presets regardless of options */ @@ -1750,13 +1755,13 @@ static void retro_set_custom_palette(void) /* Reset and choose between default internal or external custom palette */ else if (current_palette == PAL_DEFAULT || current_palette == PAL_CUSTOM) { - ipalette = external_palette_exist && (current_palette == PAL_CUSTOM); + palette_game_available = external_palette_exist && (current_palette == PAL_CUSTOM); - /* if ipalette is set to 1, external palette + /* if palette_game_available is set to 1, external palette * is loaded, else it will load default NES palette. * FCEUI_SetPaletteArray() both resets the palette array to * internal default palette and then chooses which one to use. */ - FCEUI_SetPaletteArray( NULL ); + FCEUI_SetPaletteArray( NULL, 0 ); } /* setup raw palette */ @@ -1793,7 +1798,7 @@ static void retro_set_custom_palette(void) base_palette[ i * 3 + 1 ] = ( data >> 8 ) & 0xff; /* green */ base_palette[ i * 3 + 2 ] = ( data >> 0 ) & 0xff; /* blue */ } - FCEUI_SetPaletteArray( base_palette ); + FCEUI_SetPaletteArray( base_palette, 64 ); } } @@ -1895,7 +1900,7 @@ static void check_variables(bool startup) #ifdef HAVE_NTSC_FILTER var.key = "fceumm_ntsc_filter"; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && GameInfo && GameInfo->type != GIT_NSF) { unsigned orig_value = use_ntsc; if (strcmp(var.value, "disabled") == 0) @@ -2896,24 +2901,25 @@ static void retro_run_blit(uint8_t *gfx) pitch -= (crop_overscan_h_left + crop_overscan_h_right) * sizeof(uint16_t); gfx += (crop_overscan_v_top * 256) + crop_overscan_h_left; - if (use_raw_palette) { uint8_t *deemp = XDBuf + (gfx - XBuf); for (y = 0; y < height; y++, gfx += incr, deemp += incr) - for (x = 0; x < width; x++, gfx++, deemp++) { - if (*deemp != 0) { + { + for (x = 0; x < width; x++, gfx++, deemp++) + { + if (*deemp != 0 && GameInfo->type != GIT_NSF) + { fceu_video_out[y * width + x] = retro_palette[256 + (*gfx & 0x3F) + ((*deemp & 0x07) << 6)]; - } else { - fceu_video_out[y * width + x] = retro_palette[*gfx & 0x3F]; + } + else + { + uint8 pixel_mask = use_raw_palette ? 0x3F : 0xFF; + fceu_video_out[y * width + x] = retro_palette[*gfx & pixel_mask]; } } + } } - else - { - for (y = 0; y < height; y++, gfx += incr) - for (x = 0; x < width; x++, gfx++) - fceu_video_out[y * width + x] = retro_palette[*gfx]; - } + video_cb(fceu_video_out, width, height, pitch); } #endif @@ -3583,7 +3589,7 @@ bool retro_load_game(const struct retro_game_info *info) nes_input.type[i] = RETRO_DEVICE_JOYPAD; } - external_palette_exist = ipalette; + external_palette_exist = palette_game_available; if (external_palette_exist) FCEU_printf(" Loading custom palette: %s%cnes.pal\n", system_dir, PATH_DEFAULT_SLASH_C()); diff --git a/src/fceu.c b/src/fceu.c index 35c172b..2b564a1 100644 --- a/src/fceu.c +++ b/src/fceu.c @@ -224,7 +224,7 @@ void ResetGameLoaded(void) MMC5Hack = 0; PEC586Hack = 0; PAL &= 1; - pale = 0; + default_palette_selected = 0; } int UNIFLoad(const char *name, FCEUFILE *fp); diff --git a/src/fceu.h b/src/fceu.h index 7588e77..dd578be 100644 --- a/src/fceu.h +++ b/src/fceu.h @@ -110,7 +110,7 @@ void FCEU_PutImageDummy(void); #endif extern uint8 Exit; -extern uint8 pale; +extern uint8 default_palette_selected; extern uint8 vsdip; #define JOY_A 0x01 diff --git a/src/palette.c b/src/palette.c index 96fde8b..380fb22 100644 --- a/src/palette.c +++ b/src/palette.c @@ -34,15 +34,18 @@ #include "palettes/palettes.h" /* These are dynamically filled/generated palettes: */ -pal palettei[64]; /* Custom palette for an individual game. */ -pal palettec[64]; /* Custom "global" palette. */ +static pal palette_game[512]; /* Custom palette for an individual game. */ +static pal palette_user[512]; /* Custom "global" palette. */ + +uint8 palette_game_available = false; +uint8 palette_user_available = false; static void ChoosePalette(void); static void WritePalette(void); -uint8 pale = 0; +uint8 default_palette_selected = 0; pal *palo; -static pal *palpoint[8] = +static pal *default_palette[8] = { palette, rp2c04_0001, @@ -52,16 +55,57 @@ static pal *palpoint[8] = rp2c03, }; -void FCEUI_SetPaletteArray(uint8 *pal) { - if (!pal) - palpoint[0] = palette; +static void ApplyDeemphasisClassic(int entry, uint8 *r, uint8 *g, uint8 *b) { + static const float rtmul[] = { 1.239f, 0.794f, 1.019f, 0.905f, 1.023f, 0.741f, 0.75f }; + static const float gtmul[] = { 0.915f, 1.086f, 0.98f, 1.026f, 0.908f, 0.987f, 0.75f }; + static const float btmul[] = { 0.743f, 0.882f, 0.653f, 1.277f, 0.979f, 0.101f, 0.75f }; + + int nr, ng, nb, d; + int deemph_bits = entry >> 6; + + if (deemph_bits == 0) return; + + d = deemph_bits - 1; + nr = *r; + ng = *g; + nb = *b; + nr = (int)(nr * rtmul[d]); + ng = (int)(ng * gtmul[d]); + nb = (int)(nb * btmul[d]); + if (nr > 0xFF) nr = 0xFF; + if (ng > 0xFF) ng = 0xFF; + if (nb > 0xFF) nb = 0xFF; + *r = (uint8)nr; + *g = (uint8)ng; + *b = (uint8)nb; +} + +static void ApplyDeemphasisComplete(pal *pal512) { + int i, p, idx; + + /* for each deemph level beyond 0 */ + for (i = 0, idx = 0; i < 8; i++) { + /* for each palette entry */ + for (p = 0; p < 64; p++, idx++) { + pal512[idx] = pal512[p]; + ApplyDeemphasisClassic(idx, &pal512[idx].r, &pal512[idx].g, &pal512[idx].b); + } + } +} + +void FCEUI_SetPaletteArray(uint8 *pal, int nEntries) { + if (!pal || !nEntries) + palette_user_available = false; 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); + palette_user_available = true; + for (x = 0; x < nEntries; x++) { + palette_user[x].r = *((uint8*)pal + x + x + x); + palette_user[x].g = *((uint8*)pal + x + x + x + 1); + palette_user[x].b = *((uint8*)pal + x + x + x + 2); + } + if (nEntries != 512) { + ApplyDeemphasisComplete(palette_user); } } FCEU_ResetPalette(); @@ -124,14 +168,12 @@ void SetNESDeemph(uint8 d, int force) { lastd = d; } -int ipalette = 0; - void FCEU_LoadGamePalette(void) { - uint8 ptmp[192]; + uint8 ptmp[64 * 8 * 3]; RFILE *fp = NULL; char *fn = NULL; - ipalette = 0; + palette_game_available = false; fn = FCEU_MakeFName(FCEUMKF_PALETTE, 0, 0); @@ -142,14 +184,18 @@ void FCEU_LoadGamePalette(void) { if (fp) { int x; - filestream_read(fp, ptmp, 192); + int ssize = filestream_get_size(fp); + int nEntries = ssize / 3; + filestream_read(fp, ptmp, nEntries); filestream_close(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]; + palette_game[x].r = ptmp[x + x + x]; + palette_game[x].g = ptmp[x + x + x + 1]; + palette_game[x].b = ptmp[x + x + x + 2]; } - ipalette = 1; + if (nEntries != 512) + ApplyDeemphasisComplete(palette_game); + palette_game_available = true; } free(fn); } @@ -162,23 +208,30 @@ void FCEU_ResetPalette(void) { } static void ChoosePalette(void) { - if (GameInfo->type == GIT_NSF) - palo = 0; - else if (ipalette) - palo = palettei; - else - palo = palpoint[pale]; + if (GameInfo->type == GIT_NSF) { + palo = default_palette[0]; + } else if (palette_user_available) { + palo = palette_user; + } else if (palette_game_available) { + palo = palette_game; + } else { + palo = default_palette[default_palette_selected]; + ApplyDeemphasisComplete(palo); + } } void WritePalette(void) { int x; + int unvaried = sizeof(unvpalette) / sizeof(unvpalette[0]); - for (x = 0; x < 7; x++) + for (x = 0; x < unvaried; x++) FCEUD_SetPalette(x, unvpalette[x].r, unvpalette[x].g, unvpalette[x].b); - if (GameInfo->type == GIT_NSF) { - } else { - for (x = 0; x < 64; x++) - FCEUD_SetPalette(128 + x, palo[x].r, palo[x].g, palo[x].b); - SetNESDeemph(lastd, 1); + for (x = unvaried; x < 256; x++) + FCEUD_SetPalette(x, 205, 205, 205); + for (x = 0; x < 64; x++) + FCEUD_SetPalette(128 + x, palo[x].r, palo[x].g, palo[x].b); + SetNESDeemph(lastd, 1); + for (x = 0; x < 512; x++) { + FCEUD_SetPalette(256 + x, palo[x].r, palo[x].g, palo[x].b); } } diff --git a/src/palette.h b/src/palette.h index a1bf2e8..d01b807 100644 --- a/src/palette.h +++ b/src/palette.h @@ -6,7 +6,7 @@ typedef struct { } pal; extern pal *palo; -extern int ipalette; +extern uint8 palette_game_available; void FCEU_ResetPalette(void); void FCEU_ResetPalette(void); diff --git a/src/palettes/palettes.h b/src/palettes/palettes.h index 7cb9013..9b5acee 100644 --- a/src/palettes/palettes.h +++ b/src/palettes/palettes.h @@ -1,20 +1,31 @@ -pal rp2c04_0001[64] = { +#define EMPTY_PALETTE_1 { 0, 0, 0}, +#define EMPTY_PALETTE_4 EMPTY_PALETTE_1 EMPTY_PALETTE_1 EMPTY_PALETTE_1 EMPTY_PALETTE_1 +#define EMPTY_PALETTE_16 EMPTY_PALETTE_4 EMPTY_PALETTE_4 EMPTY_PALETTE_4 EMPTY_PALETTE_4 +#define EMPTY_PALETTE_64 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16 +#define EMPTY_PALETTE_DEEMPH_X_7 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 + +pal rp2c04_0001[512] = { #include "rp2c04-0001.h" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c04_0002[64] = { +pal rp2c04_0002[512] = { #include "rp2c04-0002.h" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c04_0003[64] = { +pal rp2c04_0003[512] = { #include "rp2c04-0003.h" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c04_0004[64] = { +pal rp2c04_0004[512] = { #include "rp2c04-0004.h" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c03[64] = { +pal rp2c03[512] = { #include "rp2c03.h" + EMPTY_PALETTE_DEEMPH_X_7 }; @@ -30,7 +41,7 @@ pal unvpalette[7] = { /* Default palette */ -pal palette[64] = { +pal palette[512] = { { 117, 117, 117 }, /* Value 0 */ { 36, 24, 142 }, /* Value 1 */ { 0, 0, 170 }, /* Value 2 */ @@ -95,4 +106,6 @@ pal palette[64] = { { 199, 199, 199 }, /* Value 61 */ { 0, 0, 0 }, /* Value 62 */ { 0, 0, 0 }, /* Value 63 */ + + EMPTY_PALETTE_DEEMPH_X_7 }; diff --git a/src/video.c b/src/video.c index 10b0c96..325ff0a 100644 --- a/src/video.c +++ b/src/video.c @@ -61,7 +61,7 @@ int FCEU_InitVirtualVideo(void) return 0; memset(XBuf, 128, 256 * (256 + extrascanlines + 8)); - memset(XDBuf, 128, 256 * (256 + extrascanlines + 8)); + memset(XDBuf, 0, 256 * (256 + extrascanlines + 8)); return 1; } diff --git a/src/vsuni.c b/src/vsuni.c index 899ba7d..92f8c2e 100644 --- a/src/vsuni.c +++ b/src/vsuni.c @@ -292,8 +292,8 @@ void FCEU_VSUniCheck(uint64 md5partial, int *MapperNo, int *Mirroring) { while (vs->name) { if (md5partial == vs->md5partial) { - if (vs->ppu < RCP2C03B) pale = vs->ppu; - else pale = 5; + if (vs->ppu < RCP2C03B) default_palette_selected = vs->ppu; + else default_palette_selected = 5; *MapperNo = vs->mapper; *Mirroring = vs->mirroring; GameInfo->type = GIT_VSUNI;