File: md_ntsc.h

package info (click to toggle)
genesisplusgx 1.7.4%2Bgit20221128-2
  • links: PTS, VCS
  • area: non-free
  • in suites: sid, trixie
  • size: 16,716 kB
  • sloc: ansic: 111,869; makefile: 235; xml: 12; sh: 2
file content (154 lines) | stat: -rw-r--r-- 6,094 bytes parent folder | download | duplicates (3)
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