File: nes_ntsc.h

package info (click to toggle)
libretro-nestopia 1.52.0%2B20230102.gitcb1e24e-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 12,960 kB
  • sloc: cpp: 107,513; xml: 27,221; python: 1,329; ansic: 772; makefile: 634
file content (192 lines) | stat: -rw-r--r-- 8,182 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/* NES NTSC video filter */

/* nes_ntsc 0.2.2 */
#ifndef NES_NTSC_H
#define NES_NTSC_H

#include "nes_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 nes_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 char* palette_out;  /* optional RGB palette out, 3 bytes per color */
	
	/* You can replace the standard NES color generation with an RGB palette. The
	first replaces all color generation, while the second replaces only the core
	64-color generation and does standard color emphasis calculations on it. */
	unsigned char const* palette;/* optional 512-entry RGB palette in, 3 bytes per color */
	unsigned char const* base_palette;/* optional 64-entry RGB palette in, 3 bytes per color */
} nes_ntsc_setup_t;

/* Video format presets */
extern nes_ntsc_setup_t const nes_ntsc_composite; /* color bleeding + artifacts */
extern nes_ntsc_setup_t const nes_ntsc_svideo;    /* color bleeding only */
extern nes_ntsc_setup_t const nes_ntsc_rgb;       /* crisp image */
extern nes_ntsc_setup_t const nes_ntsc_monochrome;/* desaturated + artifacts */

#ifdef NES_NTSC_EMPHASIS
	enum { nes_ntsc_palette_size = 64 * 8 };
#else
	enum { nes_ntsc_palette_size = 64 };
#endif

/* Initializes and adjusts parameters. Can be called multiple times on the same
nes_ntsc_t object. Can pass NULL for either parameter. */
typedef struct nes_ntsc_t nes_ntsc_t;
void nes_ntsc_init( nes_ntsc_t* ntsc, nes_ntsc_setup_t const* setup );

/* Filters one or more rows of pixels. Input pixels are 6/9-bit palette indicies.
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 );

/* 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
value. Guaranteed not to round 256 down at all. */
#define NES_NTSC_OUT_WIDTH( in_width ) \
	((((in_width) - 1) / nes_ntsc_in_chunk + 1) * nes_ntsc_out_chunk)

/* Number of input pixels that will fit within given output width. Might be
rounded down slightly; use NES_NTSC_OUT_WIDTH() on result to find rounded
value. */
#define NES_NTSC_IN_WIDTH( out_width ) \
	(((out_width) / nes_ntsc_out_chunk - 1) * nes_ntsc_in_chunk + 1)


/* Interface for user-defined custom blitters */

enum { nes_ntsc_in_chunk    = 3  }; /* number of input pixels read per chunk */
enum { nes_ntsc_out_chunk   = 7  }; /* number of output pixels generated per chunk */
enum { nes_ntsc_black       = 15 }; /* palette index for black */
enum { nes_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 nes_ntsc_black for unused pixels. Declares variables, so must be before first
statement in a block (unless you're using C++). */
#define NES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \
	char const* const ktable = \
		(char const*) (ntsc)->table [0] + burst * (nes_ntsc_burst_size * sizeof (nes_ntsc_rgb_t));\
	NES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, NES_NTSC_ENTRY_, ktable )

/* Begins input pixel */
#define NES_NTSC_COLOR_IN( in_index, color_in ) \
	NES_NTSC_COLOR_IN_( in_index, color_in, NES_NTSC_ENTRY_, ktable )

/* Generates output pixel. Bits can be 24, 16, 15, 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)
 0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
#define NES_NTSC_RGB_OUT( index, rgb_out, bits ) \
	NES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 0 )


/* private */
enum { nes_ntsc_entry_size = 128 };
typedef unsigned long nes_ntsc_rgb_t;
struct nes_ntsc_t {
	nes_ntsc_rgb_t table [nes_ntsc_palette_size] [nes_ntsc_entry_size];
};
enum { nes_ntsc_burst_size = nes_ntsc_entry_size / nes_ntsc_burst_count };

#define NES_NTSC_ENTRY_( ktable, n ) \
	(nes_ntsc_rgb_t const*) (ktable + (n) * (nes_ntsc_entry_size * sizeof (nes_ntsc_rgb_t)))

/* deprecated */
#define NES_NTSC_RGB24_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 24 )
#define NES_NTSC_RGB16_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 16 )
#define NES_NTSC_RGB15_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 15 )
#define NES_NTSC_RAW_OUT( x, out )   NES_NTSC_RGB_OUT( x, out,  0 )

enum { nes_ntsc_min_in_width  = 256 };
enum { nes_ntsc_min_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_min_in_width ) };

enum { nes_ntsc_640_in_width  = 271 };
enum { nes_ntsc_640_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_640_in_width ) };
enum { nes_ntsc_640_overscan_left  = 8 };
enum { nes_ntsc_640_overscan_right = nes_ntsc_640_in_width - 256 - nes_ntsc_640_overscan_left };

enum { nes_ntsc_full_in_width  = 283 };
enum { nes_ntsc_full_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_full_in_width ) };
enum { nes_ntsc_full_overscan_left  = 16 };
enum { nes_ntsc_full_overscan_right = nes_ntsc_full_in_width - 256 - nes_ntsc_full_overscan_left };

/* common 3->7 ntsc macros */
#define NES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
	unsigned const nes_ntsc_pixel0_ = (pixel0);\
	nes_ntsc_rgb_t const* kernel0  = ENTRY( table, nes_ntsc_pixel0_ );\
	unsigned const nes_ntsc_pixel1_ = (pixel1);\
	nes_ntsc_rgb_t const* kernel1  = ENTRY( table, nes_ntsc_pixel1_ );\
	unsigned const nes_ntsc_pixel2_ = (pixel2);\
	nes_ntsc_rgb_t const* kernel2  = ENTRY( table, nes_ntsc_pixel2_ );\
	nes_ntsc_rgb_t const* kernelx0;\
	nes_ntsc_rgb_t const* kernelx1 = kernel0;\
	nes_ntsc_rgb_t const* kernelx2 = kernel0

#define NES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
	nes_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];\
	NES_NTSC_CLAMP_( raw_, shift );\
	NES_NTSC_RGB_OUT_( rgb_out, bits, shift );\
}

/* common ntsc macros */
#define nes_ntsc_rgb_builder    ((1L << 21) | (1 << 11) | (1 << 1))
#define nes_ntsc_clamp_mask     (nes_ntsc_rgb_builder * 3 / 2)
#define nes_ntsc_clamp_add      (nes_ntsc_rgb_builder * 0x101)
#define NES_NTSC_CLAMP_( io, shift ) {\
	nes_ntsc_rgb_t sub = (io) >> (9-(shift)) & nes_ntsc_clamp_mask;\
	nes_ntsc_rgb_t clamp = nes_ntsc_clamp_add - sub;\
	io |= clamp;\
	clamp -= sub;\
	io &= clamp;\
}

#define NES_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 NES_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 == 0 )\
		rgb_out = raw_ << x;\
}

#ifdef __cplusplus
	}
#endif

#endif