diff --git a/src/drivers/libretro/libretro.c b/src/drivers/libretro/libretro.c index 8118900..8825218 100644 --- a/src/drivers/libretro/libretro.c +++ b/src/drivers/libretro/libretro.c @@ -144,30 +144,6 @@ extern CartInfo UNIFCart; extern int show_crosshair; extern int option_ramstate; -#ifdef HAVE_NTSC_FILTER -/* ntsc */ -#include "nes_ntsc.h" -#define NTSC_NONE 0 -#define NTSC_COMPOSITE 1 -#define NTSC_SVIDEO 2 -#define NTSC_RGB 3 -#define NTSC_MONOCHROME 4 - -static unsigned use_ntsc = 0; -static unsigned burst_phase; -static nes_ntsc_t nes_ntsc; -static nes_ntsc_setup_t ntsc_setup; -static pal base_palette[64]; -static uint8_t *ntsc_video_out = NULL; /* for ntsc blit buffer */ - -static void nes_ntsc_cleanup(void) -{ - if (ntsc_video_out) - free(ntsc_video_out); - ntsc_video_out = NULL; -} -#endif /* HAVE_NTSC_FILTER */ - /* emulator-specific callback functions */ void UpdatePPUView(int refreshchr) { } @@ -295,9 +271,13 @@ FILE *FCEUD_UTF8fopen(const char *n, const char *m) #define PAL_DEFAULT (PAL_TOTAL + 1) #define PAL_RAW (PAL_TOTAL + 2) #define PAL_CUSTOM (PAL_TOTAL + 3) + static int external_palette_exist = 0; extern int ipalette; +/* table for currently loaded palette */ +static uint8_t base_palette[192]; + struct st_palettes { char name[32]; char desc[32]; @@ -595,6 +575,83 @@ struct st_palettes palettes[] = { } }; +#ifdef HAVE_NTSC_FILTER +/* ntsc */ +#include "nes_ntsc.h" +#define NTSC_NONE 0 +#define NTSC_COMPOSITE 1 +#define NTSC_SVIDEO 2 +#define NTSC_RGB 3 +#define NTSC_MONOCHROME 4 + +#define NTSC_WIDTH 602 + +static unsigned use_ntsc = 0; +static unsigned burst_phase; +static nes_ntsc_t nes_ntsc; +static nes_ntsc_setup_t ntsc_setup; +static uint8_t *ntsc_video_out = NULL; /* for ntsc blit buffer */ + +static void NTSCFilter_Cleanup(void) +{ + if (ntsc_video_out) + free(ntsc_video_out); + ntsc_video_out = NULL; +} + +static void NTSCFilter_Init(void) +{ + memset(&nes_ntsc, 0, sizeof(nes_ntsc)); + memset(&ntsc_setup, 0, sizeof(ntsc_setup)); + ntsc_video_out = (uint8_t*)malloc(NTSC_WIDTH * NES_HEIGHT * sizeof(uint16_t)); +} + +static void NTSCFilter_Setup(void) +{ + if (ntsc_video_out == NULL) + NTSCFilter_Init(); + + switch (use_ntsc) { + case NTSC_COMPOSITE: + ntsc_setup = nes_ntsc_composite; + break; + case NTSC_SVIDEO: + ntsc_setup = nes_ntsc_svideo; + break; + case NTSC_RGB: + ntsc_setup = nes_ntsc_rgb; + break; + case NTSC_MONOCHROME: + ntsc_setup = nes_ntsc_monochrome; + break; + default: + break; + } + + ntsc_setup.merge_fields = 0; + if ((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; + 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; + + nes_ntsc_init(&nes_ntsc, &ntsc_setup); +} +#endif /* HAVE_NTSC_FILTER */ + +static void ResetPalette(void); +static void retro_set_custom_palette(void); + +static void ResetPalette(void) +{ + retro_set_custom_palette(); +#ifdef HAVE_NTSC_FILTER + NTSCFilter_Setup(); +#endif +} + static bool libretro_supports_bitmasks = false; unsigned retro_api_version(void) @@ -869,7 +926,7 @@ void retro_get_system_av_info(struct retro_system_av_info *info) height = NES_HEIGHT - (overscan_v ? 16 : 0); #endif #ifdef HAVE_NTSC_FILTER - maxwidth = NES_NTSC_OUT_WIDTH(NES_WIDTH); + maxwidth = NTSC_WIDTH; #else maxwidth = NES_WIDTH; #endif @@ -914,12 +971,9 @@ void retro_init(void) static void retro_set_custom_palette(void) { unsigned i; - unsigned palette_changed; - pal color; ipalette = 0; use_raw_palette = false; - palette_changed = 0; if ((current_palette == PAL_DEFAULT) || (current_palette == PAL_CUSTOM) || @@ -941,6 +995,7 @@ static void retro_set_custom_palette(void) /* setup raw palette */ else if (current_palette == PAL_RAW) { + pal color; use_raw_palette = true; for (i = 0; i < 64; i++) { @@ -958,51 +1013,13 @@ static void retro_set_custom_palette(void) for ( i = 0; i < 64; i++ ) { unsigned data = palette_data[i]; - color.r = ( data >> 16 ) & 0xff; - color.g = ( data >> 8 ) & 0xff; - color.b = ( data & 0xff ); - FCEUD_SetPalette( i, color.r, color.g, color.b); - FCEUD_SetPalette( i + 64, color.r, color.g, color.b); - FCEUD_SetPalette( i + 128, color.r, color.g, color.b); - FCEUD_SetPalette( i + 192, color.r, color.g, color.b); -#ifdef HAVE_NTSC_FILTER - palette_changed = 1; - if (use_ntsc) - { - base_palette[i].r = color.r; - base_palette[i].g = color.g; - base_palette[i].b = color.b; - } -#endif + base_palette[ i * 3 + 0 ] = ( data >> 16 ) & 0xff; /* red */ + base_palette[ i * 3 + 1 ] = ( data >> 8 ) & 0xff; /* green */ + base_palette[ i * 3 + 2 ] = ( data >> 0 ) & 0xff; /* blue */ } + FCEUI_SetPaletteArray( base_palette ); } -#ifdef HAVE_NTSC_FILTER - if (use_ntsc) { - switch (use_ntsc) { - case NTSC_COMPOSITE: - ntsc_setup = nes_ntsc_composite; - break; - case NTSC_SVIDEO: - ntsc_setup = nes_ntsc_svideo; - break; - case NTSC_RGB: - ntsc_setup = nes_ntsc_rgb; - break; - case NTSC_MONOCHROME: - ntsc_setup = nes_ntsc_monochrome; - break; - default: - break; - } - if (palette_changed) - ntsc_setup.base_palette = (unsigned char const*)base_palette; - else - ntsc_setup.base_palette = ipalette ? (unsigned char const*)palo : NULL; - nes_ntsc_init(&nes_ntsc, &ntsc_setup); - } -#endif - #if defined(RENDER_GSKIT_PS2) if (ps2) { ps2->updatedPalette = true; @@ -1042,7 +1059,7 @@ void FCEUD_RegionOverride(unsigned region) normal_scanlines = dendy ? 290 : 240; totalscanlines = normal_scanlines + (overclock_enabled ? extrascanlines : 0); FCEUI_SetVidSystem(pal); - retro_set_custom_palette(); + ResetPalette(); } void retro_deinit (void) @@ -1063,7 +1080,7 @@ void retro_deinit (void) libretro_supports_bitmasks = false; DPSW_Cleanup(); #ifdef HAVE_NTSC_FILTER - nes_ntsc_cleanup(); + NTSCFilter_Cleanup(); #endif } @@ -1185,7 +1202,7 @@ static void check_variables(bool startup) } if (palette_updated) - retro_set_custom_palette(); + ResetPalette(); var.key = "fceumm_up_down_allowed"; @@ -1818,43 +1835,48 @@ static void retro_run_blit(uint8_t *gfx) #ifdef HAVE_NTSC_FILTER if (use_ntsc) { - int y; + uint8_t *deemp; unsigned out_width, out_height, out_pitch; + int y; - /*burst_phase ^= 1; - if (ntsc_setup.merge_fields) burst_phase = 0;*/ + burst_phase ^= 1; + if (ntsc_setup.merge_fields) burst_phase = 0; width = overscan_h ? 240 : 256; height = overscan_v ? 224 : 240; - out_width = NES_NTSC_OUT_WIDTH(width); + out_width = overscan_h ? 560 : 602; out_height = height; out_pitch = out_width * sizeof(uint16_t); gfx += (overscan_v ? ((overscan_h ? 8 : 0) + 256 * 8) : (overscan_h ? 8 : 0)); + deemp = XDBuf + (gfx - XBuf); /* get colour emphasis */ - nes_ntsc_blit(&nes_ntsc, (const unsigned char*)gfx, NES_WIDTH, burst_phase, width, height, ntsc_video_out, out_pitch); - -#if 0 /* this doubles the height for proper scaling, disabled for performance reasons */ - out_height <<= 1; - for (y = out_height / 2; --y >= 0;) + nes_ntsc_blit(&nes_ntsc, (unsigned char const*)gfx, (unsigned char const*)deemp, NES_WIDTH, burst_phase, width, height, ntsc_video_out, out_pitch); +#if 0 + if (!retain_height) { - uint8_t const *in = ntsc_video_out + y * out_pitch; - uint8_t *out = ntsc_video_out + y * 2 * out_pitch; - int n; - for (n = out_width; n; --n) + /* this doubles the height for proper scaling, disabled for performance reasons. + * NOTE: buffer height needs to be doubled as well */ + out_height <<= 1; + for (y = out_height / 2; --y >= 0;) { - unsigned prev = *(uint16_t*)in; - unsigned next = *(uint16_t*)(in + out_pitch); - /* mix 16-bit rgb without losing low bits */ - unsigned mixed = prev + next + ((prev ^ next) & 0x0821); - /* darken by 12% */ - *(uint16_t*)out = prev; - *(uint16_t*)(out + out_pitch) = (mixed >> 1) - (mixed >> 4 & 0x18E3); - in += 2; - out += 2; + uint8_t const *in = ntsc_video_out + y * out_pitch; + uint8_t *out = ntsc_video_out + y * 2 * out_pitch; + int n; + for (n = out_width; n; --n) + { + unsigned prev = *(uint16_t *)in; + unsigned next = *(uint16_t *)(in + out_pitch); + /* mix 16-bit rgb without losing low bits */ + unsigned mixed = prev + next + ((prev ^ next) & 0x0821); + /* darken by 12% */ + *(uint16_t *)out = prev; + *(uint16_t *)(out + out_pitch) = (mixed >> 1) - (mixed >> 4 & 0x18E3); + in += 2; + out += 2; + } } } #endif - video_cb(ntsc_video_out, out_width, out_height, out_pitch); } else @@ -1868,11 +1890,10 @@ static void retro_run_blit(uint8_t *gfx) if (use_raw_palette) { - extern uint8 PPU[4]; - int deemp = (PPU[1] >> 5) << 2; - for (y = 0; y < height; y++, gfx += incr) - for (x = 0; x < width; x++, gfx++) - fceu_video_out[y * width + x] = retro_palette[*gfx & 0x3F] | deemp; + uint8_t *deemp = XDBuf + (gfx - XBuf); + for (y = 0; y < height; y++, gfx += incr, deemp += incr) + for (x = 0; x < width; x++, gfx++, deemp++) + fceu_video_out[y * width + x] = retro_palette[*gfx & 0x3F] | (*deemp << 2); } else { @@ -2331,12 +2352,7 @@ bool retro_load_game(const struct retro_game_info *game) if (environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &sav_dir) && sav_dir) FCEUI_SetSaveDirectory(sav_dir); -#ifdef HAVE_NTSC_FILTER - use_ntsc = 0; memset(base_palette, 0, sizeof(base_palette)); - memset(&nes_ntsc, 0, sizeof(nes_ntsc)); - ntsc_video_out = (uint8_t*)malloc(NES_NTSC_OUT_WIDTH(NES_WIDTH) * (NES_HEIGHT * 2) * sizeof(uint16_t)); -#endif FCEUI_Initialize(); @@ -2369,7 +2385,9 @@ bool retro_load_game(const struct retro_game_info *game) /* Save region and dendy mode for region-auto detect */ systemRegion = (dendy << 1) | (retro_get_region() & 1); - retro_set_custom_palette(); + current_palette = 0; + + ResetPalette(); FCEUD_SoundToggle(); set_variables(); check_variables(true); @@ -2494,7 +2512,7 @@ void retro_unload_game(void) ps2 = NULL; #endif #ifdef HAVE_NTSC_FILTER - nes_ntsc_cleanup(); + NTSCFilter_Cleanup(); #endif } diff --git a/src/ntsc/nes_ntsc.c b/src/ntsc/nes_ntsc.c index 004abb6..df57cb0 100644 --- a/src/ntsc/nes_ntsc.c +++ b/src/ntsc/nes_ntsc.c @@ -233,15 +233,16 @@ void nes_ntsc_init( nes_ntsc_t* ntsc, nes_ntsc_setup_t const* setup ) #ifndef NES_NTSC_NO_BLITTERS -void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_row_width, +void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, NES_NTSC_IN_T const* inputD, long in_row_width, int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) { int chunk_count = (in_width - 1) / nes_ntsc_in_chunk; for ( ; in_height; --in_height ) { NES_NTSC_IN_T const* line_in = input; + NES_NTSC_IN_T const* line_inD = inputD; NES_NTSC_BEGIN_ROW( ntsc, burst_phase, - nes_ntsc_black, nes_ntsc_black, NES_NTSC_ADJ_IN( *line_in ) ); + nes_ntsc_black, nes_ntsc_black, NES_NTSC_ADJ_IN( *line_in, *line_inD ) ); nes_ntsc_out_t* restrict line_out = (nes_ntsc_out_t*) rgb_out; int n; ++line_in; @@ -249,20 +250,21 @@ void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_ for ( n = chunk_count; n; --n ) { /* order of input and output pixels must not be altered */ - NES_NTSC_COLOR_IN( 0, NES_NTSC_ADJ_IN( line_in [0] ) ); + NES_NTSC_COLOR_IN( 0, NES_NTSC_ADJ_IN( line_in [0], line_inD[0] ) ); NES_NTSC_RGB_OUT( 0, line_out [0], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 1, line_out [1], NES_NTSC_OUT_DEPTH ); - NES_NTSC_COLOR_IN( 1, NES_NTSC_ADJ_IN( line_in [1] ) ); + NES_NTSC_COLOR_IN( 1, NES_NTSC_ADJ_IN( line_in [1], line_inD[1] ) ); NES_NTSC_RGB_OUT( 2, line_out [2], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 3, line_out [3], NES_NTSC_OUT_DEPTH ); - NES_NTSC_COLOR_IN( 2, NES_NTSC_ADJ_IN( line_in [2] ) ); + NES_NTSC_COLOR_IN( 2, NES_NTSC_ADJ_IN( line_in [2], line_inD[2] ) ); NES_NTSC_RGB_OUT( 4, line_out [4], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 5, line_out [5], NES_NTSC_OUT_DEPTH ); NES_NTSC_RGB_OUT( 6, line_out [6], NES_NTSC_OUT_DEPTH ); line_in += 3; + line_inD += 3; line_out += 7; } @@ -281,7 +283,8 @@ void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_ NES_NTSC_RGB_OUT( 6, line_out [6], NES_NTSC_OUT_DEPTH ); burst_phase = (burst_phase + 1) % nes_ntsc_burst_count; - input += in_row_width; + input += in_row_width; + inputD += in_row_width; rgb_out = (char*) rgb_out + out_pitch; } } diff --git a/src/ntsc/nes_ntsc.h b/src/ntsc/nes_ntsc.h index 6bfa8f1..12568f4 100644 --- a/src/ntsc/nes_ntsc.h +++ b/src/ntsc/nes_ntsc.h @@ -61,8 +61,8 @@ In_row_width is the number of pixels to get to the next input row. Out_pitch is the number of *bytes* to get to the next output row. Output pixel format is set by NES_NTSC_OUT_DEPTH (defaults to 16-bit RGB). */ void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* nes_in, - long in_row_width, int burst_phase, int in_width, int in_height, - void* rgb_out, long out_pitch ); + NES_NTSC_IN_T const* nes_inD, long in_row_width, int burst_phase, int in_width, + int in_height, void* rgb_out, long out_pitch ); /* Number of output pixels written by blitter for given input width. Width might be rounded down slightly; use NES_NTSC_IN_WIDTH() on result to find rounded diff --git a/src/ntsc/nes_ntsc_config.h b/src/ntsc/nes_ntsc_config.h index ed5942b..1a89293 100644 --- a/src/ntsc/nes_ntsc_config.h +++ b/src/ntsc/nes_ntsc_config.h @@ -19,7 +19,7 @@ if you enable emphasis above. */ /* Each raw pixel input value is passed through this. You might want to mask the pixel index if you use the high bits as flags, etc. */ -#define NES_NTSC_ADJ_IN( in ) (in & 0x3F) +#define NES_NTSC_ADJ_IN( in, deemp ) ( in & 0x3F ) | ( deemp << 6 ) /* For each pixel, this is the basic operation: output_color = color_palette [NES_NTSC_ADJ_IN( NES_NTSC_IN_T )] */ diff --git a/src/ppu.c b/src/ppu.c index e45e1f8..187a96c 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -656,10 +656,12 @@ static void Fixit1(void) { void MMC5_hb(int); /* Ugh ugh ugh. */ static void DoLine(void) { - int x; - uint8 *target = NULL; - if (scanline >= 240 && scanline != totalscanlines) - { + int x, colour_emphasis; + uint8 *target = NULL; + uint8 *dtarget = NULL; + + if (scanline >= 240 && scanline != totalscanlines) + { X6502_Run(256 + 69); scanline++; X6502_Run(16); @@ -667,6 +669,7 @@ static void DoLine(void) } target = XBuf + ((scanline < 240 ? scanline : 240) << 8); + dtarget = XDBuf + ((scanline < 240 ? scanline : 240) << 8); if (MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline); @@ -699,7 +702,12 @@ static void DoLine(void) for (x = 63; x >= 0; x--) *(uint32*)&target[x << 2] = ((*(uint32*)&target[x << 2]) & 0x3f3f3f3f) | 0x80808080; - sphitx = 0x100; + //write the actual colour emphasis + colour_emphasis = ((PPU[1] >> 5) << 24) | ((PPU[1] >> 5) << 16) | ((PPU[1] >> 5) << 8) | ((PPU[1] >> 5) << 0); + for (x = 63; x >= 0; x--) + *(uint32*)&dtarget[x << 2] = colour_emphasis; + + sphitx = 0x100; if (ScreenON || SpriteON) FetchSpriteData(); diff --git a/src/video.c b/src/video.c index 099ba80..0017fc1 100644 --- a/src/video.c +++ b/src/video.c @@ -36,6 +36,7 @@ #include "vsuni.h" uint8 *XBuf = NULL; +uint8 *XDBuf = NULL; int show_crosshair = 0; void FCEU_KillVirtualVideo(void) @@ -43,6 +44,9 @@ void FCEU_KillVirtualVideo(void) if (XBuf) free(XBuf); XBuf = 0; + if (XDBuf) + free(XDBuf); + XDBuf = 0; } int FCEU_InitVirtualVideo(void) @@ -50,11 +54,14 @@ int FCEU_InitVirtualVideo(void) /* 256 bytes per scanline, * 240 scanline maximum, +8 for alignment, */ if (!XBuf) XBuf = (uint8*)(FCEU_malloc(256 * (256 + extrascanlines + 8))); + if (!XDBuf) + XDBuf = (uint8*)(FCEU_malloc(256 * (256 + extrascanlines + 8))); - if (!XBuf) + if (!XBuf || !XDBuf) return 0; - memset(XBuf, 128, 256 * (256 + extrascanlines)); + memset(XBuf, 128, 256 * (256 + extrascanlines + 8)); + memset(XDBuf, 128, 256 * (256 + extrascanlines + 8)); return 1; } diff --git a/src/video.h b/src/video.h index 55a5189..9eef95b 100644 --- a/src/video.h +++ b/src/video.h @@ -5,6 +5,7 @@ int FCEU_InitVirtualVideo(void); void FCEU_KillVirtualVideo(void); int SaveSnapshot(void); extern uint8 *XBuf; +extern uint8 *XDBuf; extern int show_crosshair; void FCEU_DrawNumberRow(uint8 *XBuf, int *nstatus, int cur);