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
|
/* Sega Master System/Game Gear/TI 99/4A NTSC video filter */
/* sms_ntsc 0.2.3 */
#ifndef SMS_NTSC_H
#define SMS_NTSC_H
#include "sms_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 sms_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) */
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */
} sms_ntsc_setup_t;
/* Video format presets */
extern sms_ntsc_setup_t const sms_ntsc_composite; /* color bleeding + artifacts */
extern sms_ntsc_setup_t const sms_ntsc_svideo; /* color bleeding only */
extern sms_ntsc_setup_t const sms_ntsc_rgb; /* crisp image */
extern sms_ntsc_setup_t const sms_ntsc_monochrome;/* desaturated + artifacts */
enum { sms_ntsc_palette_size = 4096 };
/* Initializes and adjusts parameters. Can be called multiple times on the same
sms_ntsc_t object. Can pass NULL for either parameter. */
typedef struct sms_ntsc_t sms_ntsc_t;
void sms_ntsc_init( sms_ntsc_t* ntsc, sms_ntsc_setup_t const* setup );
/* Filters one row of pixels. Input pixel format is set by SMS_NTSC_IN_FORMAT
and output RGB depth is set by SMS_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
In_row_width is the number of pixels to get to the next input row. */
void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline);
/* Number of output pixels written by blitter for given input width. */
#define SMS_NTSC_OUT_WIDTH( in_width ) \
(((in_width) / sms_ntsc_in_chunk + 1) * sms_ntsc_out_chunk)
/* Number of input pixels that will fit within given output width. Might be
rounded down slightly; use SMS_NTSC_OUT_WIDTH() on result to find rounded
value. */
#define SMS_NTSC_IN_WIDTH( out_width ) \
(((out_width) / sms_ntsc_out_chunk - 1) * sms_ntsc_in_chunk + 2)
/* Interface for user-defined custom blitters */
enum { sms_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
enum { sms_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
Declares variables, so must be before first statement in a block (unless you're using C++). */
#define SMS_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2 ) \
SMS_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SMS_NTSC_IN_FORMAT, ntsc )
/* Begins input pixel */
#define SMS_NTSC_COLOR_IN( in_index, ntsc, color_in ) \
SMS_NTSC_COLOR_IN_( in_index, color_in, SMS_NTSC_IN_FORMAT, ntsc )
/* Generates output pixel */
#define SMS_NTSC_RGB_OUT( x, rgb_out ) {\
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];\
SMS_NTSC_CLAMP_( raw_, 0 );\
SMS_NTSC_RGB_OUT_( rgb_out, 0 );\
}
/* private */
enum { sms_ntsc_entry_size = 3 * 14 };
typedef unsigned long sms_ntsc_rgb_t;
struct sms_ntsc_t {
sms_ntsc_rgb_t table [sms_ntsc_palette_size] [sms_ntsc_entry_size];
};
#define SMS_NTSC_BGR12( ntsc, n ) (ntsc)->table [n & 0xFFF]
#define SMS_NTSC_RGB16( ntsc, n ) \
(sms_ntsc_rgb_t const*) ((char const*) (ntsc)->table +\
((n << 10 & 0x7800) | (n & 0x0780) | (n >> 9 & 0x0078)) *\
(sms_ntsc_entry_size * sizeof (sms_ntsc_rgb_t) / 8))
#define SMS_NTSC_RGB15( ntsc, n ) \
(sms_ntsc_rgb_t const*) ((char const*) (ntsc)->table +\
((n << 9 & 0x3C00) | (n & 0x03C0) | (n >> 9 & 0x003C)) *\
(sms_ntsc_entry_size * sizeof (sms_ntsc_rgb_t) / 4))
/* common 3->7 ntsc macros */
#define SMS_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
sms_ntsc_rgb_t raw_;\
unsigned const sms_ntsc_pixel0_ = (pixel0);\
sms_ntsc_rgb_t const* kernel0 = ENTRY( table, sms_ntsc_pixel0_ );\
unsigned const sms_ntsc_pixel1_ = (pixel1);\
sms_ntsc_rgb_t const* kernel1 = ENTRY( table, sms_ntsc_pixel1_ );\
unsigned const sms_ntsc_pixel2_ = (pixel2);\
sms_ntsc_rgb_t const* kernel2 = ENTRY( table, sms_ntsc_pixel2_ );\
sms_ntsc_rgb_t const* kernelx0;\
sms_ntsc_rgb_t const* kernelx1 = kernel0;\
sms_ntsc_rgb_t const* kernelx2 = kernel0
/* common ntsc macros */
#define sms_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
#define sms_ntsc_clamp_mask (sms_ntsc_rgb_builder * 3 / 2)
#define sms_ntsc_clamp_add (sms_ntsc_rgb_builder * 0x101)
#define SMS_NTSC_CLAMP_( io, shift ) {\
sms_ntsc_rgb_t sub = (io) >> (9-(shift)) & sms_ntsc_clamp_mask;\
sms_ntsc_rgb_t clamp = sms_ntsc_clamp_add - sub;\
io |= clamp;\
clamp -= sub;\
io &= clamp;\
}
#define SMS_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 */
#if SMS_NTSC_OUT_DEPTH == 15
#define SMS_NTSC_RGB_OUT_( rgb_out, x ) {\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
}
#elif SMS_NTSC_OUT_DEPTH == 16
#define SMS_NTSC_RGB_OUT_( rgb_out, x) {\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
}
#endif
#ifdef __cplusplus
}
#endif
#endif
|