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