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 Genesis/Mega Drive NTSC video filter */
/* md_ntsc 0.1.2 */
#ifndef MD_NTSC_H
#define MD_NTSC_H
#include "md_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 md_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 */
} md_ntsc_setup_t;
/* Video format presets */
extern md_ntsc_setup_t const md_ntsc_composite; /* color bleeding + artifacts */
extern md_ntsc_setup_t const md_ntsc_svideo; /* color bleeding only */
extern md_ntsc_setup_t const md_ntsc_rgb; /* crisp image */
extern md_ntsc_setup_t const md_ntsc_monochrome;/* desaturated + artifacts */
enum { md_ntsc_palette_size = 512 };
/* Initializes and adjusts parameters. Can be called multiple times on the same
md_ntsc_t object. Can pass NULL for either parameter. */
typedef struct md_ntsc_t md_ntsc_t;
void md_ntsc_init( md_ntsc_t* ntsc, md_ntsc_setup_t const* setup );
/* Filters one row of pixels. Input pixel format is set by MD_NTSC_IN_FORMAT
and output RGB depth is set by MD_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 md_ntsc_blit( md_ntsc_t const* ntsc, MD_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 MD_NTSC_OUT_WIDTH( in_width ) \
(((in_width) - 3) / md_ntsc_in_chunk * md_ntsc_out_chunk + md_ntsc_out_chunk)
/* Number of input pixels that will fit within given output width. Might be
rounded down slightly; use MD_NTSC_OUT_WIDTH() on result to find rounded
value. */
#define MD_NTSC_IN_WIDTH( out_width ) \
((out_width) / md_ntsc_out_chunk * md_ntsc_in_chunk - md_ntsc_in_chunk + 3)
/* Interface for user-defined custom blitters */
enum { md_ntsc_in_chunk = 4 }; /* number of input pixels read per chunk */
enum { md_ntsc_out_chunk = 8 }; /* number of output pixels generated per chunk */
enum { md_ntsc_black = 0 }; /* palette index for black */
/* Begin outputting row and start 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 MD_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2, pixel3 ) \
md_ntsc_rgb_t raw_;\
unsigned const md_pixel0_ = (pixel0);\
md_ntsc_rgb_t const* kernel0 = MD_NTSC_IN_FORMAT( ntsc, md_pixel0_ );\
unsigned const md_pixel1_ = (pixel1);\
md_ntsc_rgb_t const* kernel1 = MD_NTSC_IN_FORMAT( ntsc, md_pixel1_ );\
unsigned const md_pixel2_ = (pixel2);\
md_ntsc_rgb_t const* kernel2 = MD_NTSC_IN_FORMAT( ntsc, md_pixel2_ );\
unsigned const md_pixel3_ = (pixel3);\
md_ntsc_rgb_t const* kernel3 = MD_NTSC_IN_FORMAT( ntsc, md_pixel3_ );\
md_ntsc_rgb_t const* kernelx0;\
md_ntsc_rgb_t const* kernelx1 = kernel0;\
md_ntsc_rgb_t const* kernelx2 = kernel0;\
md_ntsc_rgb_t const* kernelx3 = kernel0
/* Begin input pixel */
#define MD_NTSC_COLOR_IN( index, ntsc, color ) \
MD_NTSC_COLOR_IN_( index, color, MD_NTSC_IN_FORMAT, ntsc )
/* Generate output pixel */
#define MD_NTSC_RGB_OUT( x, rgb_out ) {\
raw_ =\
kernel0 [x+ 0] + kernel1 [(x+6)%8+16] + kernel2 [(x+4)%8 ] + kernel3 [(x+2)%8+16] +\
kernelx0 [x+ 8] + kernelx1 [(x+6)%8+24] + kernelx2 [(x+4)%8+8] + kernelx3 [(x+2)%8+24];\
MD_NTSC_CLAMP_( raw_, 0 );\
MD_NTSC_RGB_OUT_( rgb_out, 0 );\
}
/* private */
enum { md_ntsc_entry_size = 2 * 16 };
typedef unsigned long md_ntsc_rgb_t;
struct md_ntsc_t {
md_ntsc_rgb_t table [md_ntsc_palette_size] [md_ntsc_entry_size];
};
#define MD_NTSC_BGR9( ntsc, n ) (ntsc)->table [n & 0x1FF]
#define MD_NTSC_RGB16( ntsc, n ) \
(md_ntsc_rgb_t*) ((char*) (ntsc)->table +\
((n << 9 & 0x3800) | (n & 0x0700) | (n >> 8 & 0x00E0)) *\
(md_ntsc_entry_size * sizeof (md_ntsc_rgb_t) / 32))
#define MD_NTSC_RGB15( ntsc, n ) \
(md_ntsc_rgb_t*) ((char*) (ntsc)->table +\
((n << 8 & 0x1C00) | (n & 0x0380) | (n >> 8 & 0x0070)) *\
(md_ntsc_entry_size * sizeof (md_ntsc_rgb_t) / 16))
/* common ntsc macros */
#define md_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
#define md_ntsc_clamp_mask (md_ntsc_rgb_builder * 3 / 2)
#define md_ntsc_clamp_add (md_ntsc_rgb_builder * 0x101)
#define MD_NTSC_CLAMP_( io, shift ) {\
md_ntsc_rgb_t sub = (io) >> (9-(shift)) & md_ntsc_clamp_mask;\
md_ntsc_rgb_t clamp = md_ntsc_clamp_add - sub;\
io |= clamp;\
clamp -= sub;\
io &= clamp;\
}
#define MD_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 MD_NTSC_OUT_DEPTH == 15
#define MD_NTSC_RGB_OUT_( rgb_out, x ) {\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
}
#elif MD_NTSC_OUT_DEPTH == 16
#define MD_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
|