File: sms_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,123 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 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