#ifndef MD_NTSC_H
#define MD_NTSC_H
#include "md_ntsc_config.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct md_ntsc_setup_t
{
double hue;
double saturation;
double contrast;
double brightness;
double sharpness;
double gamma;
double resolution;
double artifacts;
double fringing;
double bleed;
float const* decoder_matrix;
unsigned char* palette_out;
} md_ntsc_setup_t;
extern md_ntsc_setup_t const md_ntsc_composite;
extern md_ntsc_setup_t const md_ntsc_svideo;
extern md_ntsc_setup_t const md_ntsc_rgb;
extern md_ntsc_setup_t const md_ntsc_monochrome;
enum { md_ntsc_palette_size = 512 };
typedef struct md_ntsc_t md_ntsc_t;
void md_ntsc_init( md_ntsc_t* ntsc, md_ntsc_setup_t const* setup );
void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline);
#define MD_NTSC_OUT_WIDTH( in_width ) \
(((in_width) - 3) / md_ntsc_in_chunk * md_ntsc_out_chunk + md_ntsc_out_chunk)
#define MD_NTSC_IN_WIDTH( out_width ) \
((out_width) / md_ntsc_out_chunk * md_ntsc_in_chunk - md_ntsc_in_chunk + 3)
enum { md_ntsc_in_chunk = 4 };
enum { md_ntsc_out_chunk = 8 };
enum { md_ntsc_black = 0 };
#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
#define MD_NTSC_COLOR_IN( index, ntsc, color ) \
MD_NTSC_COLOR_IN_( index, color, MD_NTSC_IN_FORMAT, ntsc )
#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 );\
}
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))
#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_ ));\
}
#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