diff --git a/filter/snes_ntsc.c b/filter/snes_ntsc.c index f622baf8..6ca96753 100644 --- a/filter/snes_ntsc.c +++ b/filter/snes_ntsc.c @@ -32,6 +32,9 @@ snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1 #include "snes_ntsc_impl.h" +unsigned int snes_ntsc_scanline_offset = 0; +unsigned short snes_ntsc_scanline_mask = 0xffff; + /* 3 input pixels -> 8 composite samples */ pixel_info_t const snes_ntsc_pixels [alignment_count] = { { PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } }, @@ -248,4 +251,140 @@ void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, } } +/* 12.5% scanlines like in snes_ntsc example instead of zsnes's 25% */ +#define PIXEL_OUT( x ) \ + SNES_NTSC_RGB_OUT( x, value, SNES_NTSC_OUT_DEPTH ); \ + line_outa[x] = value; \ + line_outb[x] = value - (value >> snes_ntsc_scanline_offset & snes_ntsc_scanline_mask); + +void snes_ntsc_blit_scanlines( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, + int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) +{ + unsigned value; + int chunk_count = (in_width - 1) / snes_ntsc_in_chunk; + for ( ; in_height; --in_height ) + { + SNES_NTSC_IN_T const* line_in = input; + SNES_NTSC_BEGIN_ROW( ntsc, burst_phase, + snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) ); + snes_ntsc_out_t * restrict line_outa = (snes_ntsc_out_t *) rgb_out; + snes_ntsc_out_t * restrict line_outb = (snes_ntsc_out_t *) ((char *) line_outa + out_pitch); + int n; + ++line_in; + + for ( n = chunk_count; n; --n ) + { + /* order of input and output pixels must not be altered */ + SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); + PIXEL_OUT (0); + PIXEL_OUT (1); + + SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); + PIXEL_OUT (2); + PIXEL_OUT (3); + + SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); + PIXEL_OUT (4); + PIXEL_OUT (5); + PIXEL_OUT (6); + + line_in += 3; + line_outa += 7; + line_outb += 7; + } + + /* finish final pixels */ + SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); + PIXEL_OUT (0); + PIXEL_OUT (1); + + SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); + PIXEL_OUT (2); + PIXEL_OUT (3); + + SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); + PIXEL_OUT (4); + PIXEL_OUT (5); + PIXEL_OUT (6); + + burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; + input += in_row_width; + rgb_out = (char*) rgb_out + 2 * out_pitch; + } +} + +#define PIXEL_OUT_HIRES( x ) \ + SNES_NTSC_HIRES_OUT( x, value, SNES_NTSC_OUT_DEPTH ); \ + line_outa[x] = value; \ + line_outb[x] = value - (value >> snes_ntsc_scanline_offset & snes_ntsc_scanline_mask); + +void snes_ntsc_blit_hires_scanlines( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, + int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) +{ + int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2); + unsigned value; + for ( ; in_height; --in_height ) + { + SNES_NTSC_IN_T const* line_in = input; + SNES_NTSC_HIRES_ROW( ntsc, burst_phase, + snes_ntsc_black, snes_ntsc_black, snes_ntsc_black, + SNES_NTSC_ADJ_IN( line_in [0] ), + SNES_NTSC_ADJ_IN( line_in [1] ) ); + snes_ntsc_out_t* restrict line_outa = (snes_ntsc_out_t*) rgb_out; + snes_ntsc_out_t* restrict line_outb = (snes_ntsc_out_t*) ((char *) line_outa + out_pitch); + int n; + line_in += 2; + + for ( n = chunk_count; n; --n ) + { + /* twice as many input pixels per chunk */ + SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); + PIXEL_OUT_HIRES (0); + + SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); + PIXEL_OUT_HIRES (1); + + SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); + PIXEL_OUT_HIRES (2); + + SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) ); + PIXEL_OUT_HIRES (3); + + SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) ); + PIXEL_OUT_HIRES (4); + + SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) ); + PIXEL_OUT_HIRES (5); + PIXEL_OUT_HIRES (6); + + line_in += 6; + line_outa += 7; + line_outb += 7; + } + + SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); + PIXEL_OUT_HIRES (0); + + SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); + PIXEL_OUT_HIRES (1); + + SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); + PIXEL_OUT_HIRES (2); + + SNES_NTSC_COLOR_IN( 3, snes_ntsc_black ); + PIXEL_OUT_HIRES (3); + + SNES_NTSC_COLOR_IN( 4, snes_ntsc_black ); + PIXEL_OUT_HIRES (4); + + SNES_NTSC_COLOR_IN( 5, snes_ntsc_black ); + PIXEL_OUT_HIRES (5); + PIXEL_OUT_HIRES (6); + + burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; + input += in_row_width; + rgb_out = (char*) rgb_out + out_pitch * 2; + } +} + #endif diff --git a/filter/snes_ntsc.h b/filter/snes_ntsc.h index 0c991386..601bfee2 100644 --- a/filter/snes_ntsc.h +++ b/filter/snes_ntsc.h @@ -39,6 +39,10 @@ extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */ extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */ extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */ +/* Scanline values */ +extern unsigned int snes_ntsc_scanline_offset; +extern unsigned short snes_ntsc_scanline_mask; + /* Initializes and adjusts parameters. Can be called multiple times on the same snes_ntsc_t object. Can pass NULL for either parameter. */ typedef struct snes_ntsc_t snes_ntsc_t; @@ -56,6 +60,14 @@ void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ); +void snes_ntsc_blit_scanlines( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, + long in_row_width, int burst_phase, int in_width, int in_height, + void* rgb_out, long out_pitch ); + +void snes_ntsc_blit_hires_scanlines( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, + 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 low-res blitter for given input width. Width might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded value. Guaranteed not to round 256 down at all. */ diff --git a/filter/snes_ntsc_config.h b/filter/snes_ntsc_config.h index 653b8bc5..da005e26 100644 --- a/filter/snes_ntsc_config.h +++ b/filter/snes_ntsc_config.h @@ -3,6 +3,7 @@ #ifndef SNES_NTSC_CONFIG_H #define SNES_NTSC_CONFIG_H +#ifndef SNES9X_GTK /* Format of source pixels */ #define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB15 /* #define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 */ @@ -14,6 +15,11 @@ handle things however it wants. */ /* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */ #define SNES_NTSC_OUT_DEPTH 15 +#else +#define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 +#define SNES_NTSC_OUT_DEPTH 16 +#endif + /* Type of input pixel values */ #define SNES_NTSC_IN_T unsigned short diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 261bacac..e5b60c28 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -50,10 +50,10 @@ snes9x_gtk_SOURCES = \ src/gtk_sound.cpp \ src/gtk_sound.h \ src/gtk_splash.cpp \ - src/snes_ntsc_config.h \ - src/snes_ntsc.h \ - src/snes_ntsc_impl.h \ - src/snes_ntsc.c \ + ../filter/snes_ntsc_config.h \ + ../filter/snes_ntsc.h \ + ../filter/snes_ntsc_impl.h \ + ../filter/snes_ntsc.c \ src/gtk_2_3_compat.h if HQ2X diff --git a/gtk/src/gtk_config.h b/gtk/src/gtk_config.h index 6612e36d..088ec821 100644 --- a/gtk/src/gtk_config.h +++ b/gtk/src/gtk_config.h @@ -5,7 +5,7 @@ #include #include "gtk_control.h" -#include "snes_ntsc.h" +#include "filter/snes_ntsc.h" enum { HWA_NONE = 0, diff --git a/gtk/src/gtk_display.cpp b/gtk/src/gtk_display.cpp index a007f648..d988bcc6 100644 --- a/gtk/src/gtk_display.cpp +++ b/gtk/src/gtk_display.cpp @@ -5,7 +5,6 @@ #include "gtk_display.h" #include "gtk_display_driver.h" #include "gtk_display_driver_gtk.h" -#include "snes_ntsc.h" #if defined(USE_XV) && defined(GDK_WINDOWING_X11) #include "gtk_display_driver_xv.h" @@ -41,9 +40,6 @@ static unsigned short scanline_masks[] = 0xffff, /* 100% */ }; -extern unsigned int scanline_offset; -extern unsigned short scanline_mask; - /* Scanline constants for standard scanline filter */ static uint8 scanline_shifts[] = { @@ -1097,23 +1093,23 @@ internal_filter (uint8 *src_buffer, case FILTER_NTSC: if (width > 256) - snes_ntsc_blit_hires (&snes_ntsc, - (SNES_NTSC_IN_T *) src_buffer, - src_pitch >> 1, - 0, /* Burst_phase */ - width, - height, - (void *) dst_buffer, - dst_pitch); + snes_ntsc_blit_hires_scanlines (&snes_ntsc, + (SNES_NTSC_IN_T *) src_buffer, + src_pitch >> 1, + 0, /* Burst_phase */ + width, + height, + (void *) dst_buffer, + dst_pitch); else - snes_ntsc_blit (&snes_ntsc, - (SNES_NTSC_IN_T *) src_buffer, - src_pitch >> 1, - 0, /* Burst_phase */ - width, - height, - (void *) dst_buffer, - dst_pitch); + snes_ntsc_blit_scanlines (&snes_ntsc, + (SNES_NTSC_IN_T *) src_buffer, + src_pitch >> 1, + 0, /* Burst_phase */ + width, + height, + (void *) dst_buffer, + dst_pitch); break; case FILTER_SCANLINES: @@ -1502,8 +1498,8 @@ S9xDisplayRefresh (int width, int height) static void ntsc_filter_init () { - scanline_offset = scanline_offsets [gui_config->ntsc_scanline_intensity]; - scanline_mask = scanline_masks [gui_config->ntsc_scanline_intensity]; + snes_ntsc_scanline_offset = scanline_offsets [gui_config->ntsc_scanline_intensity]; + snes_ntsc_scanline_mask = scanline_masks [gui_config->ntsc_scanline_intensity]; snes_ntsc_init (&snes_ntsc, &gui_config->ntsc_setup); } diff --git a/gtk/src/gtk_display.h b/gtk/src/gtk_display.h index 318c6014..ab7fa1a2 100644 --- a/gtk/src/gtk_display.h +++ b/gtk/src/gtk_display.h @@ -12,6 +12,7 @@ #endif #include "filter/epx.h" #include "filter_epx_unsafe.h" +#include "filter/snes_ntsc.h" enum { diff --git a/gtk/src/snes_ntsc.c b/gtk/src/snes_ntsc.c deleted file mode 100644 index 42dc0ab0..00000000 --- a/gtk/src/snes_ntsc.c +++ /dev/null @@ -1,271 +0,0 @@ -/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */ - -#include "snes_ntsc.h" - -/* Copyright (C) 2006-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 }; -snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }; -snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 }; -snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 }; - -#define alignment_count 3 -#define burst_count 3 -#define rescale_in 8 -#define rescale_out 7 - -#define artifacts_mid 1.0f -#define fringing_mid 1.0f -#define std_decoder_hue 0 - -#define rgb_bits 7 /* half normal range to allow for doubled hires pixels */ -#define gamma_size 32 - -#include "snes_ntsc_impl.h" - -unsigned int scanline_offset = 0; -unsigned short scanline_mask = 0xffff; - -/* 3 input pixels -> 8 composite samples */ -pixel_info_t const snes_ntsc_pixels [alignment_count] = { - { PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } }, - { PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } }, - { PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } }, -}; - -static void merge_kernel_fields( snes_ntsc_rgb_t* io ) -{ - int n; - for ( n = burst_size; n; --n ) - { - snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias; - snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias; - snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias; - /* merge colors without losing precision */ - io [burst_size * 0] = - ((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; - io [burst_size * 1] = - ((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; - io [burst_size * 2] = - ((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; - ++io; - } -} - -static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out ) -{ - int n; - for ( n = burst_count; n; --n ) - { - unsigned i; - for ( i = 0; i < rgb_kernel_size / 2; i++ ) - { - snes_ntsc_rgb_t error = color - - out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] - - out [i + 7] - out [i + 5 +14] - out [i + 3 +28]; - DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 ); - } - out += alignment_count * rgb_kernel_size; - } -} - -void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup ) -{ - int merge_fields; - int entry; - init_t impl; - if ( !setup ) - setup = &snes_ntsc_composite; - init( &impl, setup ); - - merge_fields = setup->merge_fields; - if ( setup->artifacts <= -1 && setup->fringing <= -1 ) - merge_fields = 1; - - for ( entry = 0; entry < snes_ntsc_palette_size; entry++ ) - { - /* Reduce number of significant bits of source color. Clearing the - low bits of R and B were least notictable. Modifying green was too - noticeable. */ - int ir = entry >> 8 & 0x1E; - int ig = entry >> 4 & 0x1F; - int ib = entry << 1 & 0x1E; - - #if SNES_NTSC_BSNES_COLORTBL - if ( setup->bsnes_colortbl ) - { - int bgr15 = (ib << 10) | (ig << 5) | ir; - unsigned long rgb16 = setup->bsnes_colortbl [bgr15]; - ir = rgb16 >> 11 & 0x1E; - ig = rgb16 >> 6 & 0x1F; - ib = rgb16 & 0x1E; - } - #endif - - { - float rr = impl.to_float [ir]; - float gg = impl.to_float [ig]; - float bb = impl.to_float [ib]; - - float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i ); - - int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g ); - snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b ); - - snes_ntsc_rgb_t* out = ntsc->table [entry]; - gen_kernel( &impl, y, i, q, out ); - if ( merge_fields ) - merge_kernel_fields( out ); - correct_errors( rgb, out ); - } - } -} - -#ifndef SNES_NTSC_NO_BLITTERS - -/* 12.5% scanlines like in snes_ntsc example instead of zsnes's 25% */ -#define PIXEL_OUT( x ) \ - SNES_NTSC_RGB_OUT( x, value, 16 ); \ - line_outa[x] = value; \ - line_outb[x] = value - (value >> scanline_offset & scanline_mask); - -void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, - int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) -{ - unsigned value; - int chunk_count = (in_width - 1) / snes_ntsc_in_chunk; - for ( ; in_height; --in_height ) - { - SNES_NTSC_IN_T const* line_in = input; - SNES_NTSC_BEGIN_ROW( ntsc, burst_phase, - snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) ); - snes_ntsc_out_t * restrict line_outa = (snes_ntsc_out_t *) rgb_out; - snes_ntsc_out_t * restrict line_outb = (snes_ntsc_out_t *) ((char *) line_outa + out_pitch); - int n; - ++line_in; - - for ( n = chunk_count; n; --n ) - { - /* order of input and output pixels must not be altered */ - SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); - PIXEL_OUT (0); - PIXEL_OUT (1); - - SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); - PIXEL_OUT (2); - PIXEL_OUT (3); - - SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); - PIXEL_OUT (4); - PIXEL_OUT (5); - PIXEL_OUT (6); - - line_in += 3; - line_outa += 7; - line_outb += 7; - } - - /* finish final pixels */ - SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); - PIXEL_OUT (0); - PIXEL_OUT (1); - - SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); - PIXEL_OUT (2); - PIXEL_OUT (3); - - SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); - PIXEL_OUT (4); - PIXEL_OUT (5); - PIXEL_OUT (6); - - burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; - input += in_row_width; - rgb_out = (char*) rgb_out + 2 * out_pitch; - } -} - -#define PIXEL_OUT_HIRES( x ) \ - SNES_NTSC_HIRES_OUT( x, value, 16 ); \ - line_outa[x] = value; \ - line_outb[x] = value - (value >> scanline_offset & scanline_mask); - -void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, - int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) -{ - int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2); - unsigned value; - for ( ; in_height; --in_height ) - { - SNES_NTSC_IN_T const* line_in = input; - SNES_NTSC_HIRES_ROW( ntsc, burst_phase, - snes_ntsc_black, snes_ntsc_black, snes_ntsc_black, - SNES_NTSC_ADJ_IN( line_in [0] ), - SNES_NTSC_ADJ_IN( line_in [1] ) ); - snes_ntsc_out_t* restrict line_outa = (snes_ntsc_out_t*) rgb_out; - snes_ntsc_out_t* restrict line_outb = (snes_ntsc_out_t*) ((char *) line_outa + out_pitch); - int n; - line_in += 2; - - for ( n = chunk_count; n; --n ) - { - /* twice as many input pixels per chunk */ - SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); - PIXEL_OUT_HIRES (0); - - SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); - PIXEL_OUT_HIRES (1); - - SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); - PIXEL_OUT_HIRES (2); - - SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) ); - PIXEL_OUT_HIRES (3); - - SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) ); - PIXEL_OUT_HIRES (4); - - SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) ); - PIXEL_OUT_HIRES (5); - PIXEL_OUT_HIRES (6); - - line_in += 6; - line_outa += 7; - line_outb += 7; - } - - SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); - PIXEL_OUT_HIRES (0); - - SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); - PIXEL_OUT_HIRES (1); - - SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); - PIXEL_OUT_HIRES (2); - - SNES_NTSC_COLOR_IN( 3, snes_ntsc_black ); - PIXEL_OUT_HIRES (3); - - SNES_NTSC_COLOR_IN( 4, snes_ntsc_black ); - PIXEL_OUT_HIRES (4); - - SNES_NTSC_COLOR_IN( 5, snes_ntsc_black ); - PIXEL_OUT_HIRES (5); - PIXEL_OUT_HIRES (6); - - burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; - input += in_row_width; - rgb_out = (char*) rgb_out + out_pitch * 2; - } -} - -#endif diff --git a/gtk/src/snes_ntsc.h b/gtk/src/snes_ntsc.h deleted file mode 100644 index eb150af9..00000000 --- a/gtk/src/snes_ntsc.h +++ /dev/null @@ -1,210 +0,0 @@ -/* SNES NTSC video filter */ - -/* snes_ntsc 0.2.2 */ -#ifndef SNES_NTSC_H -#define SNES_NTSC_H - -#include "snes_ntsc_config.h" - -#ifdef __cplusplus - extern "C" { -#endif - -/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown -in parenthesis and should remain fairly stable in future versions. */ -typedef struct snes_ntsc_setup_t -{ - /* Basic parameters */ - double hue; /* -1 = -180 degrees +1 = +180 degrees */ - double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */ - double contrast; /* -1 = dark (0.5) +1 = light (1.5) */ - double brightness; /* -1 = dark (0.5) +1 = light (1.5) */ - double sharpness; /* edge contrast enhancement/blurring */ - - /* Advanced parameters */ - double gamma; /* -1 = dark (1.5) +1 = light (0.5) */ - double resolution; /* image resolution */ - double artifacts; /* artifacts caused by color changes */ - double fringing; /* color artifacts caused by brightness changes */ - double bleed; /* color bleed (color resolution reduction) */ - int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */ - float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */ - - unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */ -} snes_ntsc_setup_t; - -/* Video format presets */ -extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */ -extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */ -extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */ -extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */ - -/* Initializes and adjusts parameters. Can be called multiple times on the same -snes_ntsc_t object. Can pass NULL for either parameter. */ -typedef struct snes_ntsc_t snes_ntsc_t; -void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup ); - -/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT -and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB. -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. */ -void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, - long in_row_width, int burst_phase, int in_width, int in_height, - void* rgb_out, long out_pitch ); - -void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, - 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 low-res blitter for given input width. Width -might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded -value. Guaranteed not to round 256 down at all. */ -#define SNES_NTSC_OUT_WIDTH( in_width ) \ - ((((in_width) - 1) / snes_ntsc_in_chunk + 1) * snes_ntsc_out_chunk) - -/* Number of low-res input pixels that will fit within given output width. Might be -rounded down slightly; use SNES_NTSC_OUT_WIDTH() on result to find rounded -value. */ -#define SNES_NTSC_IN_WIDTH( out_width ) \ - (((out_width) / snes_ntsc_out_chunk - 1) * snes_ntsc_in_chunk + 1) - - -/* Interface for user-defined custom blitters */ - -enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */ -enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */ -enum { snes_ntsc_black = 0 }; /* palette index for black */ -enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */ - -/* Begins outputting row and starts three pixels. First pixel will be cut off a bit. -Use snes_ntsc_black for unused pixels. Declares variables, so must be before first -statement in a block (unless you're using C++). */ -#define SNES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \ - char const* ktable = \ - (char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\ - SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SNES_NTSC_IN_FORMAT, ktable ) - -/* Begins input pixel */ -#define SNES_NTSC_COLOR_IN( index, color ) \ - SNES_NTSC_COLOR_IN_( index, color, SNES_NTSC_IN_FORMAT, ktable ) - -/* Generates output pixel. Bits can be 24, 16, 15, 14, 32 (treated as 24), or 0: -24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB) -16: RRRRRGGG GGGBBBBB (5-6-5 RGB) -15: RRRRRGG GGGBBBBB (5-5-5 RGB) -14: BBBBBGG GGGRRRRR (5-5-5 BGR, native SNES format) - 0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */ -#define SNES_NTSC_RGB_OUT( index, rgb_out, bits ) \ - SNES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 1 ) - -/* Hires equivalents */ -#define SNES_NTSC_HIRES_ROW( ntsc, burst, pixel1, pixel2, pixel3, pixel4, pixel5 ) \ - char const* ktable = \ - (char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\ - unsigned const snes_ntsc_pixel1_ = (pixel1);\ - snes_ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel1_ );\ - unsigned const snes_ntsc_pixel2_ = (pixel2);\ - snes_ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel2_ );\ - unsigned const snes_ntsc_pixel3_ = (pixel3);\ - snes_ntsc_rgb_t const* kernel3 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel3_ );\ - unsigned const snes_ntsc_pixel4_ = (pixel4);\ - snes_ntsc_rgb_t const* kernel4 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel4_ );\ - unsigned const snes_ntsc_pixel5_ = (pixel5);\ - snes_ntsc_rgb_t const* kernel5 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel5_ );\ - snes_ntsc_rgb_t const* kernel0 = kernel1;\ - snes_ntsc_rgb_t const* kernelx0;\ - snes_ntsc_rgb_t const* kernelx1 = kernel1;\ - snes_ntsc_rgb_t const* kernelx2 = kernel1;\ - snes_ntsc_rgb_t const* kernelx3 = kernel1;\ - snes_ntsc_rgb_t const* kernelx4 = kernel1;\ - snes_ntsc_rgb_t const* kernelx5 = kernel1 - -#define SNES_NTSC_HIRES_OUT( x, rgb_out, bits ) {\ - snes_ntsc_rgb_t raw_ =\ - kernel0 [ x ] + kernel2 [(x+5)%7+14] + kernel4 [(x+3)%7+28] +\ - kernelx0 [(x+7)%7+7] + kernelx2 [(x+5)%7+21] + kernelx4 [(x+3)%7+35] +\ - kernel1 [(x+6)%7 ] + kernel3 [(x+4)%7+14] + kernel5 [(x+2)%7+28] +\ - kernelx1 [(x+6)%7+7] + kernelx3 [(x+4)%7+21] + kernelx5 [(x+2)%7+35];\ - SNES_NTSC_CLAMP_( raw_, 0 );\ - SNES_NTSC_RGB_OUT_( rgb_out, (bits), 0 );\ -} - - -/* private */ -enum { snes_ntsc_entry_size = 128 }; -enum { snes_ntsc_palette_size = 0x2000 }; -typedef unsigned long snes_ntsc_rgb_t; -struct snes_ntsc_t { - snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size]; -}; -enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count }; - -#define SNES_NTSC_RGB16( ktable, n ) \ - (snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 1 & 0x03E0) | (n >> 2 & 0x3C00)) * \ - (snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t))) - -#define SNES_NTSC_RGB15( ktable, n ) \ - (snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 0 & 0x03E0) | (n >> 1 & 0x3C00)) * \ - (snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t))) - -#define SNES_NTSC_BGR15( ktable, n ) \ - (snes_ntsc_rgb_t const*) (ktable + (n & 0x7BFE) * \ - (snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t))) - -/* common 3->7 ntsc macros */ -#define SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \ - unsigned const snes_ntsc_pixel0_ = (pixel0);\ - snes_ntsc_rgb_t const* kernel0 = ENTRY( table, snes_ntsc_pixel0_ );\ - unsigned const snes_ntsc_pixel1_ = (pixel1);\ - snes_ntsc_rgb_t const* kernel1 = ENTRY( table, snes_ntsc_pixel1_ );\ - unsigned const snes_ntsc_pixel2_ = (pixel2);\ - snes_ntsc_rgb_t const* kernel2 = ENTRY( table, snes_ntsc_pixel2_ );\ - snes_ntsc_rgb_t const* kernelx0;\ - snes_ntsc_rgb_t const* kernelx1 = kernel0;\ - snes_ntsc_rgb_t const* kernelx2 = kernel0 - -#define SNES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\ - snes_ntsc_rgb_t raw_ =\ - kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\ - kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\ - SNES_NTSC_CLAMP_( raw_, shift );\ - SNES_NTSC_RGB_OUT_( rgb_out, bits, shift );\ -} - -/* common ntsc macros */ -#define snes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1)) -#define snes_ntsc_clamp_mask (snes_ntsc_rgb_builder * 3 / 2) -#define snes_ntsc_clamp_add (snes_ntsc_rgb_builder * 0x101) -#define SNES_NTSC_CLAMP_( io, shift ) {\ - snes_ntsc_rgb_t sub = (io) >> (9-(shift)) & snes_ntsc_clamp_mask;\ - snes_ntsc_rgb_t clamp = snes_ntsc_clamp_add - sub;\ - io |= clamp;\ - clamp -= sub;\ - io &= clamp;\ -} - -#define SNES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\ - unsigned color_;\ - kernelx##index = kernel##index;\ - kernel##index = (color_ = (color), ENTRY( table, color_ ));\ -} - -/* x is always zero except in snes_ntsc library */ -#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\ - if ( bits == 16 )\ - rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\ - if ( bits == 24 || bits == 32 )\ - rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\ - if ( bits == 15 )\ - rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\ - if ( bits == 14 )\ - rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(9-x)&0x03E0)|(raw_<<(6+x)&0x7C00);\ - if ( bits == 0 )\ - rgb_out = raw_ << x;\ -} - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/gtk/src/snes_ntsc_config.h b/gtk/src/snes_ntsc_config.h deleted file mode 100644 index 88cb0ed1..00000000 --- a/gtk/src/snes_ntsc_config.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Configure library by modifying this file */ - -#ifndef SNES_NTSC_CONFIG_H -#define SNES_NTSC_CONFIG_H - -/* Format of source pixels */ -#define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 -/* #define SNES_NTSC_IN_FORMAT SNES_NTSC_BGR15 */ - -/* The following affect the built-in blitter only; a custom blitter can -handle things however it wants. */ - -/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */ -#define SNES_NTSC_OUT_DEPTH 16 - -/* Type of input pixel values */ -#define SNES_NTSC_IN_T unsigned short - -/* 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 SNES_NTSC_ADJ_IN( in ) in - -/* For each pixel, this is the basic operation: -output_color = SNES_NTSC_ADJ_IN( SNES_NTSC_IN_T ) */ - -#endif diff --git a/gtk/src/snes_ntsc_impl.h b/gtk/src/snes_ntsc_impl.h deleted file mode 100644 index 1d7adc78..00000000 --- a/gtk/src/snes_ntsc_impl.h +++ /dev/null @@ -1,439 +0,0 @@ -/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */ - -/* Common implementation of NTSC filters */ - -#include -#include - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#define DISABLE_CORRECTION 0 - -#undef PI -#define PI 3.14159265358979323846f - -#ifndef LUMA_CUTOFF - #define LUMA_CUTOFF 0.20 -#endif -#ifndef gamma_size - #define gamma_size 1 -#endif -#ifndef rgb_bits - #define rgb_bits 8 -#endif -#ifndef artifacts_max - #define artifacts_max (artifacts_mid * 1.5f) -#endif -#ifndef fringing_max - #define fringing_max (fringing_mid * 2) -#endif -#ifndef STD_HUE_CONDITION - #define STD_HUE_CONDITION( setup ) 1 -#endif - -#define ext_decoder_hue (std_decoder_hue + 15) -#define rgb_unit (1 << rgb_bits) -#define rgb_offset (rgb_unit * 2 + 0.5f) - -enum { burst_size = snes_ntsc_entry_size / burst_count }; -enum { kernel_half = 16 }; -enum { kernel_size = kernel_half * 2 + 1 }; - -typedef struct init_t -{ - float to_rgb [burst_count * 6]; - float to_float [gamma_size]; - float contrast; - float brightness; - float artifacts; - float fringing; - float kernel [rescale_out * kernel_size * 2]; -} init_t; - -#define ROTATE_IQ( i, q, sin_b, cos_b ) {\ - float t;\ - t = i * cos_b - q * sin_b;\ - q = i * sin_b + q * cos_b;\ - i = t;\ -} - -static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup ) -{ -#if rescale_out > 1 - float kernels [kernel_size * 2]; -#else - float* const kernels = impl->kernel; -#endif - - /* generate luma (y) filter using sinc kernel */ - { - /* sinc with rolloff (dsf) */ - float const rolloff = 1 + (float) setup->sharpness * (float) 0.032; - float const maxh = 32; - float const pow_a_n = (float) pow( rolloff, maxh ); - float sum; - int i; - /* quadratic mapping to reduce negative (blurring) range */ - float to_angle = (float) setup->resolution + 1; - to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1); - - kernels [kernel_size * 3 / 2] = maxh; /* default center value */ - for ( i = 0; i < kernel_half * 2 + 1; i++ ) - { - int x = i - kernel_half; - float angle = x * to_angle; - /* instability occurs at center point with rolloff very close to 1.0 */ - if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 ) - { - float rolloff_cos_a = rolloff * (float) cos( angle ); - float num = 1 - rolloff_cos_a - - pow_a_n * (float) cos( maxh * angle ) + - pow_a_n * rolloff * (float) cos( (maxh - 1) * angle ); - float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; - float dsf = num / den; - kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5; - } - } - - /* apply blackman window and find sum */ - sum = 0; - for ( i = 0; i < kernel_half * 2 + 1; i++ ) - { - float x = PI * 2 / (kernel_half * 2) * i; - float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 ); - sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman); - } - - /* normalize kernel */ - sum = 1.0f / sum; - for ( i = 0; i < kernel_half * 2 + 1; i++ ) - { - int x = kernel_size * 3 / 2 - kernel_half + i; - kernels [x] *= sum; - assert( kernels [x] == kernels [x] ); /* catch numerical instability */ - } - } - - /* generate chroma (iq) filter using gaussian kernel */ - { - float const cutoff_factor = -0.03125f; - float cutoff = (float) setup->bleed; - int i; - - if ( cutoff < 0 ) - { - /* keep extreme value accessible only near upper end of scale (1.0) */ - cutoff *= cutoff; - cutoff *= cutoff; - cutoff *= cutoff; - cutoff *= -30.0f / 0.65f; - } - cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff; - - for ( i = -kernel_half; i <= kernel_half; i++ ) - kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff ); - - /* normalize even and odd phases separately */ - for ( i = 0; i < 2; i++ ) - { - float sum = 0; - int x; - for ( x = i; x < kernel_size; x += 2 ) - sum += kernels [x]; - - sum = 1.0f / sum; - for ( x = i; x < kernel_size; x += 2 ) - { - kernels [x] *= sum; - assert( kernels [x] == kernels [x] ); /* catch numerical instability */ - } - } - } - - /* - printf( "luma:\n" ); - for ( i = kernel_size; i < kernel_size * 2; i++ ) - printf( "%f\n", kernels [i] ); - printf( "chroma:\n" ); - for ( i = 0; i < kernel_size; i++ ) - printf( "%f\n", kernels [i] ); - */ - - /* generate linear rescale kernels */ - #if rescale_out > 1 - { - float weight = 1.0f; - float* out = impl->kernel; - int n = rescale_out; - do - { - float remain = 0; - int i; - weight -= 1.0f / rescale_in; - for ( i = 0; i < kernel_size * 2; i++ ) - { - float cur = kernels [i]; - float m = cur * weight; - *out++ = m + remain; - remain = cur - m; - } - } - while ( --n ); - } - #endif -} - -static float const default_decoder [6] = - { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f }; - -static void init( init_t* impl, snes_ntsc_setup_t const* setup ) -{ - impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset; - impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit; - #ifdef default_palette_contrast - if ( !setup->palette ) - impl->contrast *= default_palette_contrast; - #endif - - impl->artifacts = (float) setup->artifacts; - if ( impl->artifacts > 0 ) - impl->artifacts *= artifacts_max - artifacts_mid; - impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid; - - impl->fringing = (float) setup->fringing; - if ( impl->fringing > 0 ) - impl->fringing *= fringing_max - fringing_mid; - impl->fringing = impl->fringing * fringing_mid + fringing_mid; - - init_filters( impl, setup ); - - /* generate gamma table */ - if ( gamma_size > 1 ) - { - float const to_float = 1.0f / (gamma_size - (gamma_size > 1)); - float const gamma = 1.1333f - (float) setup->gamma * 0.5f; - /* match common PC's 2.2 gamma to TV's 2.65 gamma */ - int i; - for ( i = 0; i < gamma_size; i++ ) - impl->to_float [i] = - (float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness; - } - - /* setup decoder matricies */ - { - float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue; - float sat = (float) setup->saturation + 1; - float const* decoder = setup->decoder_matrix; - if ( !decoder ) - { - decoder = default_decoder; - if ( STD_HUE_CONDITION( setup ) ) - hue += PI / 180 * (std_decoder_hue - ext_decoder_hue); - } - - { - float s = (float) sin( hue ) * sat; - float c = (float) cos( hue ) * sat; - float* out = impl->to_rgb; - int n; - - n = burst_count; - do - { - float const* in = decoder; - int n = 3; - do - { - float i = *in++; - float q = *in++; - *out++ = i * c - q * s; - *out++ = i * s + q * c; - } - while ( --n ); - if ( burst_count <= 1 ) - break; - ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */ - } - while ( --n ); - } - } -} - -/* kernel generation */ - -#define RGB_TO_YIQ( r, g, b, y, i ) (\ - (y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\ - (i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\ - ((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\ -) - -#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\ - r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\ - g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\ - (type) (y + to_rgb [4] * i + to_rgb [5] * q)\ -) - -#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1) - -enum { rgb_kernel_size = burst_size / alignment_count }; -enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder }; - -typedef struct pixel_info_t -{ - int offset; - float negate; - float kernel [4]; -} pixel_info_t; - -#if rescale_in > 1 - #define PIXEL_OFFSET_( ntsc, scaled ) \ - (kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \ - (kernel_size * 2 * scaled)) - - #define PIXEL_OFFSET( ntsc, scaled ) \ - PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\ - (((scaled) + rescale_out * 10) % rescale_out) ),\ - (1.0f - (((ntsc) + 100) & 2)) -#else - #define PIXEL_OFFSET( ntsc, scaled ) \ - (kernel_size / 2 + (ntsc) - (scaled)),\ - (1.0f - (((ntsc) + 100) & 2)) -#endif - -extern pixel_info_t const snes_ntsc_pixels [alignment_count]; - -/* Generate pixel at all burst phases and column alignments */ -static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out ) -{ - /* generate for each scanline burst phase */ - float const* to_rgb = impl->to_rgb; - int burst_remain = burst_count; - y -= rgb_offset; - do - { - /* Encode yiq into *two* composite signals (to allow control over artifacting). - Convolve these with kernels which: filter respective components, apply - sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack - into integer. Based on algorithm by NewRisingSun. */ - pixel_info_t const* pixel = snes_ntsc_pixels; - int alignment_remain = alignment_count; - do - { - /* negate is -1 when composite starts at odd multiple of 2 */ - float const yy = y * impl->fringing * pixel->negate; - float const ic0 = (i + yy) * pixel->kernel [0]; - float const qc1 = (q + yy) * pixel->kernel [1]; - float const ic2 = (i - yy) * pixel->kernel [2]; - float const qc3 = (q - yy) * pixel->kernel [3]; - - float const factor = impl->artifacts * pixel->negate; - float const ii = i * factor; - float const yc0 = (y + ii) * pixel->kernel [0]; - float const yc2 = (y - ii) * pixel->kernel [2]; - - float const qq = q * factor; - float const yc1 = (y + qq) * pixel->kernel [1]; - float const yc3 = (y - qq) * pixel->kernel [3]; - - float const* k = &impl->kernel [pixel->offset]; - int n; - ++pixel; - for ( n = rgb_kernel_size; n; --n ) - { - float i = k[0]*ic0 + k[2]*ic2; - float q = k[1]*qc1 + k[3]*qc3; - float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 + - k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset; - if ( rescale_out <= 1 ) - k--; - else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] ) - k += kernel_size * 2 - 1; - else - k -= kernel_size * 2 * (rescale_out - 1) + 2; - { - int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g ); - *out++ = PACK_RGB( r, g, b ) - rgb_bias; - } - } - } - while ( alignment_count > 1 && --alignment_remain ); - - if ( burst_count <= 1 ) - break; - - to_rgb += 6; - - ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */ - } - while ( --burst_remain ); -} - -static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out ); - -#if DISABLE_CORRECTION - #define CORRECT_ERROR( a ) { out [i] += rgb_bias; } - #define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; } -#else - #define CORRECT_ERROR( a ) { out [a] += error; } - #define DISTRIBUTE_ERROR( a, b, c ) {\ - snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\ - fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\ - fourth -= rgb_bias >> 2;\ - out [a] += fourth;\ - out [b] += fourth;\ - out [c] += fourth;\ - out [i] += error - (fourth * 3);\ - } -#endif - -#define RGB_PALETTE_OUT( rgb, out_ )\ -{\ - unsigned char* out = (out_);\ - snes_ntsc_rgb_t clamped = (rgb);\ - SNES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\ - out [0] = (unsigned char) (clamped >> 21);\ - out [1] = (unsigned char) (clamped >> 11);\ - out [2] = (unsigned char) (clamped >> 1);\ -} - -/* blitter related */ - -#ifndef restrict - #if defined (__GNUC__) - #define restrict __restrict__ - #elif defined (_MSC_VER) && _MSC_VER > 1300 - #define restrict __restrict - #else - /* no support for restricted pointers */ - #define restrict - #endif -#endif - -#include - -#if SNES_NTSC_OUT_DEPTH <= 16 - #if USHRT_MAX == 0xFFFF - typedef unsigned short snes_ntsc_out_t; - #else - #error "Need 16-bit int type" - #endif - -#else - #if UINT_MAX == 0xFFFFFFFF - typedef unsigned int snes_ntsc_out_t; - #elif ULONG_MAX == 0xFFFFFFFF - typedef unsigned long snes_ntsc_out_t; - #else - #error "Need 32-bit int type" - #endif - -#endif