1 /* NES NTSC video filter */ 2 3 /* nes_ntsc 0.2.2 */ 4 #ifndef NES_NTSC_H 5 #define NES_NTSC_H 6 7 #include "nes_ntsc_config.h" 8 9 #ifdef __cplusplus 10 extern "C" { 11 #endif 12 13 /* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown 14 in parenthesis and should remain fairly stable in future versions. */ 15 typedef struct nes_ntsc_setup_t 16 { 17 /* Basic parameters */ 18 double hue; /* -1 = -180 degrees +1 = +180 degrees */ 19 double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */ 20 double contrast; /* -1 = dark (0.5) +1 = light (1.5) */ 21 double brightness; /* -1 = dark (0.5) +1 = light (1.5) */ 22 double sharpness; /* edge contrast enhancement/blurring */ 23 24 /* Advanced parameters */ 25 double gamma; /* -1 = dark (1.5) +1 = light (0.5) */ 26 double resolution; /* image resolution */ 27 double artifacts; /* artifacts caused by color changes */ 28 double fringing; /* color artifacts caused by brightness changes */ 29 double bleed; /* color bleed (color resolution reduction) */ 30 int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */ 31 float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */ 32 33 unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */ 34 35 /* You can replace the standard NES color generation with an RGB palette. The 36 first replaces all color generation, while the second replaces only the core 37 64-color generation and does standard color emphasis calculations on it. */ 38 unsigned char const* palette;/* optional 512-entry RGB palette in, 3 bytes per color */ 39 unsigned char const* base_palette;/* optional 64-entry RGB palette in, 3 bytes per color */ 40 } nes_ntsc_setup_t; 41 42 /* Video format presets */ 43 extern nes_ntsc_setup_t const nes_ntsc_composite; /* color bleeding + artifacts */ 44 extern nes_ntsc_setup_t const nes_ntsc_svideo; /* color bleeding only */ 45 extern nes_ntsc_setup_t const nes_ntsc_rgb; /* crisp image */ 46 extern nes_ntsc_setup_t const nes_ntsc_monochrome;/* desaturated + artifacts */ 47 48 #ifdef NES_NTSC_EMPHASIS 49 enum { nes_ntsc_palette_size = 64 * 8 }; 50 #else 51 enum { nes_ntsc_palette_size = 64 }; 52 #endif 53 54 /* Initializes and adjusts parameters. Can be called multiple times on the same 55 nes_ntsc_t object. Can pass NULL for either parameter. */ 56 typedef struct nes_ntsc_t nes_ntsc_t; 57 void nes_ntsc_init( nes_ntsc_t* ntsc, nes_ntsc_setup_t const* setup ); 58 59 /* Filters one or more rows of pixels. Input pixels are 6/9-bit palette indicies. 60 In_row_width is the number of pixels to get to the next input row. Out_pitch 61 is the number of *bytes* to get to the next output row. Output pixel format 62 is set by NES_NTSC_OUT_DEPTH (defaults to 16-bit RGB). */ 63 void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* nes_in, 64 NES_NTSC_IN_T const* nes_inD, long in_row_width, int burst_phase, int in_width, 65 int in_height, void* rgb_out, long out_pitch ); 66 67 /* Number of output pixels written by blitter for given input width. Width might 68 be rounded down slightly; use NES_NTSC_IN_WIDTH() on result to find rounded 69 value. Guaranteed not to round 256 down at all. */ 70 #define NES_NTSC_OUT_WIDTH( in_width ) \ 71 ((((in_width) - 1) / nes_ntsc_in_chunk + 1) * nes_ntsc_out_chunk) 72 73 /* Number of input pixels that will fit within given output width. Might be 74 rounded down slightly; use NES_NTSC_OUT_WIDTH() on result to find rounded 75 value. */ 76 #define NES_NTSC_IN_WIDTH( out_width ) \ 77 (((out_width) / nes_ntsc_out_chunk - 1) * nes_ntsc_in_chunk + 1) 78 79 80 /* Interface for user-defined custom blitters */ 81 82 enum { nes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */ 83 enum { nes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */ 84 enum { nes_ntsc_black = 15 }; /* palette index for black */ 85 enum { nes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */ 86 87 /* Begins outputting row and starts three pixels. First pixel will be cut off a bit. 88 Use nes_ntsc_black for unused pixels. Declares variables, so must be before first 89 statement in a block (unless you're using C++). */ 90 #define NES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \ 91 char const* const ktable = \ 92 (char const*) (ntsc)->table [0] + burst * (nes_ntsc_burst_size * sizeof (nes_ntsc_rgb_t));\ 93 NES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, NES_NTSC_ENTRY_, ktable ) 94 95 /* Begins input pixel */ 96 #define NES_NTSC_COLOR_IN( in_index, color_in ) \ 97 NES_NTSC_COLOR_IN_( in_index, color_in, NES_NTSC_ENTRY_, ktable ) 98 99 /* Generates output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0: 100 24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB) 101 16: RRRRRGGG GGGBBBBB (5-6-5 RGB) 102 15: RRRRRGG GGGBBBBB (5-5-5 RGB) 103 0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */ 104 #define NES_NTSC_RGB_OUT( index, rgb_out, bits ) \ 105 NES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 0 ) 106 107 108 /* private */ 109 enum { nes_ntsc_entry_size = 128 }; 110 typedef unsigned long nes_ntsc_rgb_t; 111 struct nes_ntsc_t { 112 nes_ntsc_rgb_t table [nes_ntsc_palette_size] [nes_ntsc_entry_size]; 113 }; 114 enum { nes_ntsc_burst_size = nes_ntsc_entry_size / nes_ntsc_burst_count }; 115 116 #define NES_NTSC_ENTRY_( ktable, n ) \ 117 (nes_ntsc_rgb_t const*) (ktable + (n) * (nes_ntsc_entry_size * sizeof (nes_ntsc_rgb_t))) 118 119 /* deprecated */ 120 /*#define NES_NTSC_RGB24_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 24 ) 121 #define NES_NTSC_RGB16_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 16 ) 122 #define NES_NTSC_RGB15_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 15 ) 123 #define NES_NTSC_RAW_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 0 ) 124 125 enum { nes_ntsc_min_in_width = 256 }; 126 enum { nes_ntsc_min_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_min_in_width ) }; 127 128 enum { nes_ntsc_640_in_width = 271 }; 129 enum { nes_ntsc_640_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_640_in_width ) }; 130 enum { nes_ntsc_640_overscan_left = 8 }; 131 enum { nes_ntsc_640_overscan_right = nes_ntsc_640_in_width - 256 - nes_ntsc_640_overscan_left }; 132 133 enum { nes_ntsc_full_in_width = 283 }; 134 enum { nes_ntsc_full_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_full_in_width ) }; 135 enum { nes_ntsc_full_overscan_left = 16 }; 136 enum { nes_ntsc_full_overscan_right = nes_ntsc_full_in_width - 256 - nes_ntsc_full_overscan_left };*/ 137 138 /* common 3->7 ntsc macros */ 139 #define NES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \ 140 unsigned const nes_ntsc_pixel0_ = (pixel0);\ 141 nes_ntsc_rgb_t const* kernel0 = ENTRY( table, nes_ntsc_pixel0_ );\ 142 unsigned const nes_ntsc_pixel1_ = (pixel1);\ 143 nes_ntsc_rgb_t const* kernel1 = ENTRY( table, nes_ntsc_pixel1_ );\ 144 unsigned const nes_ntsc_pixel2_ = (pixel2);\ 145 nes_ntsc_rgb_t const* kernel2 = ENTRY( table, nes_ntsc_pixel2_ );\ 146 nes_ntsc_rgb_t const* kernelx0;\ 147 nes_ntsc_rgb_t const* kernelx1 = kernel0;\ 148 nes_ntsc_rgb_t const* kernelx2 = kernel0 149 150 #define NES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\ 151 nes_ntsc_rgb_t raw_ =\ 152 kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\ 153 kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\ 154 NES_NTSC_CLAMP_( raw_, shift );\ 155 NES_NTSC_RGB_OUT_( rgb_out, bits, shift );\ 156 } 157 158 /* common ntsc macros */ 159 #define nes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1)) 160 #define nes_ntsc_clamp_mask (nes_ntsc_rgb_builder * 3 / 2) 161 #define nes_ntsc_clamp_add (nes_ntsc_rgb_builder * 0x101) 162 #define NES_NTSC_CLAMP_( io, shift ) {\ 163 nes_ntsc_rgb_t sub = (io) >> (9-(shift)) & nes_ntsc_clamp_mask;\ 164 nes_ntsc_rgb_t clamp = nes_ntsc_clamp_add - sub;\ 165 io |= clamp;\ 166 clamp -= sub;\ 167 io &= clamp;\ 168 } 169 170 #define NES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\ 171 unsigned color_;\ 172 kernelx##index = kernel##index;\ 173 kernel##index = (color_ = (color), ENTRY( table, color_ ));\ 174 } 175 176 /* x is always zero except in snes_ntsc library */ 177 #define NES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\ 178 if ( bits == 16 )\ 179 rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\ 180 if ( bits == 24 || bits == 32 )\ 181 rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\ 182 if ( bits == 15 )\ 183 rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\ 184 if ( bits == 0 )\ 185 rgb_out = raw_ << x;\ 186 } 187 188 #ifdef __cplusplus 189 } 190 #endif 191 192 #endif 193