initial commit

This commit is contained in:
R-type
2015-12-14 14:00:35 +01:00
commit 5a96c0ca66
377 changed files with 149124 additions and 0 deletions
+392
View File
@@ -0,0 +1,392 @@
/* Based on nes_ntsc 0.2.2. http://www.slack.net/~ant/ */
#include "colours.h"
#include "atari_ntsc.h"
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
/* Atari change: removal and addition of structure fields.
Values of resolution and sharpness adjusted to make NTSC artifacts look better. */
atari_ntsc_setup_t const atari_ntsc_monochrome = { 0, -1, 0, 0, -.3, .3, .2, -.2, -.2, -1, 0, 0, 0, 0. };
atari_ntsc_setup_t const atari_ntsc_composite = { 0, 0, 0, 0, -.5, .3, -.1, 0, 0, 0, 0, 0, 0, 0. };
atari_ntsc_setup_t const atari_ntsc_svideo = { 0, 0, 0, 0, -.3, .3, .2, -1, -1, 0, 0, 0, 0, 0. };
atari_ntsc_setup_t const atari_ntsc_rgb = { 0, 0, 0, 0, -.3, .3, .7, -1, -1, -1, 0, 0, 0, 0. };
#define alignment_count 4
#define burst_count 1
#define rescale_in 8
#define rescale_out 7
#define artifacts_mid 1.0f
#define fringing_mid 1.0f
/* Atari change: default palette is already at correct hue.
#define std_decoder_hue -15 */
#define std_decoder_hue 0
/* Atari change: only one palette - remove base_palete field. */
#define STD_HUE_CONDITION( setup ) !(setup->palette)
#include "atari_ntsc_impl.h"
/* Atari change: adapted to 4/7 pixel ratio. */
/* 4 input pixels -> 8 composite samples */
pixel_info_t const atari_ntsc_pixels [alignment_count] = {
{ PIXEL_OFFSET( -6, -6 ), { 0, 0, 1, 1 } },
{ PIXEL_OFFSET( -4, -4 ), { 0, 0, 1, 1 } },
{ PIXEL_OFFSET( -2, -2 ), { 0, 0, 1, 1 } },
{ PIXEL_OFFSET( 0, 0 ), { 0, 0, 1, 1 } },
};
/* Atari change: no alternating burst phases - removed merge_kernel_fields function. */
static void correct_errors( atari_ntsc_rgb_t color, atari_ntsc_rgb_t* out )
{
int n;
for ( n = burst_count; n; --n )
{
unsigned i;
for ( i = 0; i < rgb_kernel_size / 2; i++ )
{
/* Atari change: adapted to 4/7 pixel ratio */
atari_ntsc_rgb_t error = color -
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] - out[(i+8)%14+42] -
out [i + 7] - out [i + 5 +14] - out [i + 3 +28] - out [ i+1 +42];
DISTRIBUTE_ERROR( i+1+42, i+3+28, i+5+14, i+7 );
}
out += alignment_count * rgb_kernel_size;
}
}
void atari_ntsc_init( atari_ntsc_t* ntsc, atari_ntsc_setup_t const* setup )
{
/* Atari change: no alternating burst phases - remove merge_fields variable. */
int entry;
init_t impl;
/* Atari change: NES palette generation and reading removed.
Atari palette generation is located in colours_ntsc.c, and colours are read
from setup->yiq_palette. */
if ( !setup )
setup = &atari_ntsc_composite;
init( &impl, setup );
/* Atari change: no alternating burst phases - remove code for merge_fields. */
for ( entry = 0; entry < atari_ntsc_palette_size; entry++ )
{
/* Atari change: Instead of palette generation, load colours
from setup->yiq_palette. */
double y;
double i;
double q;
{
double *yiq_ptr = setup->yiq_palette + 3 * entry;
y = *yiq_ptr++;
i = *yiq_ptr++;
q = *yiq_ptr++;
}
/* Atari change: Convert from CRT TV gamma correction to the sRGB
gamma correction. */
if (setup->gamma >= 0.0)
{
double r, g, b = YIQ_TO_RGB( y, i, q, default_decoder, double, r, g );
r = Colours_Gamma2Linear(r, setup->gamma);
g = Colours_Gamma2Linear(g, setup->gamma);
b = Colours_Gamma2Linear(b, setup->gamma);
r = Colours_Linear2sRGB(r);
g = Colours_Linear2sRGB(g);
b = Colours_Linear2sRGB(b);
q = RGB_TO_YIQ( r, g, b, y, i );
}
i *= rgb_unit;
q *= rgb_unit;
y *= rgb_unit;
y += rgb_offset;
/* Generate kernel */
{
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
/* blue tends to overflow, so clamp it */
atari_ntsc_rgb_t rgb = PACK_RGB( r, g, (b < 0x3E0 ? b: 0x3E0) );
if ( setup->palette_out )
RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] );
if ( ntsc )
{
atari_ntsc_rgb_t* kernel = ntsc->table [entry];
gen_kernel( &impl, y, i, q, kernel );
/* Atari change: no alternating burst phases - remove code for merge_fields. */
correct_errors( rgb, kernel );
}
}
}
}
#ifndef ATARI_NTSC_NO_BLITTERS
/* Atari change: no alternating burst phases - remove burst_phase parameter.
Also removed the atari_ntsc_blit function and added specific blitters for various
pixel formats. */
#include <limits.h>
#if USHRT_MAX == 0xFFFF
typedef unsigned short atari_ntsc_out16_t;
#else
#error "Need 16-bit int type"
#endif
#if UINT_MAX == 0xFFFFFFFF
typedef unsigned int atari_ntsc_out32_t;
#elif ULONG_MAX == 0xFFFFFFFF
typedef unsigned long atari_ntsc_out32_t;
#else
#error "Need 32-bit int type"
#endif
void atari_ntsc_blit_rgb16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* input, long in_row_width,
int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / atari_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
ATARI_NTSC_IN_T const* line_in = input;
/* Atari change: no alternating burst phases - remove burst_phase parameter; adjust to 4/7 pixel ratio. */
ATARI_NTSC_BEGIN_ROW( ntsc,
atari_ntsc_black, atari_ntsc_black, atari_ntsc_black, ATARI_NTSC_ADJ_IN( *line_in ) );
atari_ntsc_out16_t* restrict line_out = (atari_ntsc_out16_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
ATARI_NTSC_COLOR_IN( 0, ATARI_NTSC_ADJ_IN( line_in [0] ) );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 1, ATARI_NTSC_ADJ_IN( line_in [1] ) );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 2, ATARI_NTSC_ADJ_IN( line_in [2] ) );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 3, ATARI_NTSC_ADJ_IN( line_in [3] ) );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_RGB16 );
line_in += 4;
line_out += 7;
}
/* finish final pixels */
ATARI_NTSC_COLOR_IN( 0, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 1, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 2, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 3, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_RGB16 );
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
void atari_ntsc_blit_bgr16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* input, long in_row_width,
int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / atari_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
ATARI_NTSC_IN_T const* line_in = input;
/* Atari change: no alternating burst phases - remove burst_phase parameter; adjust to 4/7 pixel ratio. */
ATARI_NTSC_BEGIN_ROW( ntsc,
atari_ntsc_black, atari_ntsc_black, atari_ntsc_black, ATARI_NTSC_ADJ_IN( *line_in ) );
atari_ntsc_out16_t* restrict line_out = (atari_ntsc_out16_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
ATARI_NTSC_COLOR_IN( 0, ATARI_NTSC_ADJ_IN( line_in [0] ) );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 1, ATARI_NTSC_ADJ_IN( line_in [1] ) );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 2, ATARI_NTSC_ADJ_IN( line_in [2] ) );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 3, ATARI_NTSC_ADJ_IN( line_in [3] ) );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_BGR16 );
line_in += 4;
line_out += 7;
}
/* finish final pixels */
ATARI_NTSC_COLOR_IN( 0, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 1, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 2, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 3, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_BGR16 );
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
void atari_ntsc_blit_argb32( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* input, long in_row_width,
int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / atari_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
ATARI_NTSC_IN_T const* line_in = input;
/* Atari change: no alternating burst phases - remove burst_phase parameter; adjust to 4/7 pixel ratio. */
ATARI_NTSC_BEGIN_ROW( ntsc,
atari_ntsc_black, atari_ntsc_black, atari_ntsc_black, ATARI_NTSC_ADJ_IN( *line_in ) );
atari_ntsc_out32_t* restrict line_out = (atari_ntsc_out32_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
ATARI_NTSC_COLOR_IN( 0, ATARI_NTSC_ADJ_IN( line_in [0] ) );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 1, ATARI_NTSC_ADJ_IN( line_in [1] ) );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 2, ATARI_NTSC_ADJ_IN( line_in [2] ) );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 3, ATARI_NTSC_ADJ_IN( line_in [3] ) );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_ARGB32 );
line_in += 4;
line_out += 7;
}
/* finish final pixels */
ATARI_NTSC_COLOR_IN( 0, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 1, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 2, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 3, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_ARGB32 );
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
void atari_ntsc_blit_bgra32( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* input, long in_row_width,
int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / atari_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
ATARI_NTSC_IN_T const* line_in = input;
/* Atari change: no alternating burst phases - remove burst_phase parameter; adjust to 4/7 pixel ratio. */
ATARI_NTSC_BEGIN_ROW( ntsc,
atari_ntsc_black, atari_ntsc_black, atari_ntsc_black, ATARI_NTSC_ADJ_IN( *line_in ) );
atari_ntsc_out32_t* restrict line_out = (atari_ntsc_out32_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
ATARI_NTSC_COLOR_IN( 0, ATARI_NTSC_ADJ_IN( line_in [0] ) );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 1, ATARI_NTSC_ADJ_IN( line_in [1] ) );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 2, ATARI_NTSC_ADJ_IN( line_in [2] ) );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 3, ATARI_NTSC_ADJ_IN( line_in [3] ) );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_BGRA32 );
line_in += 4;
line_out += 7;
}
/* finish final pixels */
ATARI_NTSC_COLOR_IN( 0, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 1, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 2, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 3, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_BGRA32 );
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
#endif
+229
View File
@@ -0,0 +1,229 @@
/* Atari TIA, CTIA, GTIA and MARIA NTSC video filter */
/* based on nes_ntsc 0.2.2 */
#ifndef ATARI_NTSC_H
#define ATARI_NTSC_H
#include "atari_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 atari_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) */
/* Atari change: no alternating burst phases - remove merge_fields field. */
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */
/* You can replace the standard NES color generation with an RGB palette. The
first replaces all color generation, while the second replaces only the core
64-color generation and does standard color emphasis calculations on it. */
unsigned char const* palette;/* optional 256-entry RGB palette in, 3 bytes per color */
/* Atari change: only one palette - remove base_palette field. */
/* Atari change: additional setup fields */
double burst_phase; /* Phase at which colorburst signal is turned on;
this defines colors of artifacts.
In radians; -1.0 = -180 degrees, 1.0 = +180 degrees */
double *yiq_palette;
} atari_ntsc_setup_t;
/* Video format presets */
extern atari_ntsc_setup_t const atari_ntsc_composite; /* color bleeding + artifacts */
extern atari_ntsc_setup_t const atari_ntsc_svideo; /* color bleeding only */
extern atari_ntsc_setup_t const atari_ntsc_rgb; /* crisp image */
extern atari_ntsc_setup_t const atari_ntsc_monochrome;/* desaturated + artifacts */
enum { atari_ntsc_palette_size = 256 };
/* Initializes and adjusts parameters. Can be called multiple times on the same
atari_ntsc_t object. Can pass NULL for either parameter. */
typedef struct atari_ntsc_t atari_ntsc_t;
void atari_ntsc_init( atari_ntsc_t* ntsc, atari_ntsc_setup_t const* setup );
/* Filters one or more rows of pixels. Input pixels are 6/9-bit palette indicies.
In_row_width is the number of pixels to get to the next input row. Out_pitch
is the number of *bytes* to get to the next output row. Output pixel format
is set by ATARI_NTSC_OUT_DEPTH (defaults to 16-bit RGB). */
/* Atari change: no alternating burst phases - remove burst_phase parameter.
Also removed the atari_ntsc_blit function and added specific blitters for various
pixel formats. */
void atari_ntsc_blit_rgb16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
long in_row_width, int in_width, int in_height,
void* rgb_out, long out_pitch );
void atari_ntsc_blit_bgr16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
long in_row_width, int in_width, int in_height,
void* rgb_out, long out_pitch );
void atari_ntsc_blit_argb32( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
long in_row_width, int in_width, int in_height,
void* rgb_out, long out_pitch );
void atari_ntsc_blit_bgra32( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
long in_row_width, int in_width, int in_height,
void* rgb_out, long out_pitch );
/* Number of output pixels written by blitter for given input width. Width might
be rounded down slightly; use ATARI_NTSC_IN_WIDTH() on result to find rounded
value. Guaranteed not to round 256 down at all. */
#define ATARI_NTSC_OUT_WIDTH( in_width ) \
((((in_width) - 1) / atari_ntsc_in_chunk + 1)* atari_ntsc_out_chunk)
/* Number of input pixels that will fit within given output width. Might be
rounded down slightly; use ATARI_NTSC_OUT_WIDTH() on result to find rounded
value. */
#define ATARI_NTSC_IN_WIDTH( out_width ) \
(((out_width) / atari_ntsc_out_chunk - 1) * atari_ntsc_in_chunk + 1)
/* Interface for user-defined custom blitters. */
enum { atari_ntsc_in_chunk = 4 }; /* number of input pixels read per chunk */
enum { atari_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
enum { atari_ntsc_black = 0 }; /* palette index for black */
enum { atari_ntsc_burst_count = 1 }; /* burst phase cycles through 0, 1, and 2 */
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
Use nes_ntsc_black for unused pixels. Declares variables, so must be before first
statement in a block (unless you're using C++). */
/* Atari change: no alternating burst phases; adapted to 4/7 pixel ratio. */
#define ATARI_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2, pixel3 ) \
char const* const ktable = \
(char const*) (ntsc)->table [0];\
ATARI_NTSC_BEGIN_ROW_8_( pixel0, pixel1, pixel2, pixel3, ATARI_NTSC_ENTRY_, ktable )
/* Begins input pixel */
#define ATARI_NTSC_COLOR_IN( in_index, color_in ) \
ATARI_NTSC_COLOR_IN_( in_index, color_in, ATARI_NTSC_ENTRY_, ktable )
/* Generates output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0:
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
16: RRRRRGGG GGGBBBBB (5-6-5 RGB)
15: RRRRRGG GGGBBBBB (5-5-5 RGB)
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
#define ATARI_NTSC_RGB_OUT( index, rgb_out, bits ) \
ATARI_NTSC_RGB_OUT_14_( index, rgb_out, bits, 0 )
/* private */
enum { atari_ntsc_entry_size = 56 };
typedef unsigned long atari_ntsc_rgb_t;
struct atari_ntsc_t {
atari_ntsc_rgb_t table [atari_ntsc_palette_size] [atari_ntsc_entry_size];
};
enum { atari_ntsc_burst_size = atari_ntsc_entry_size / atari_ntsc_burst_count };
#define ATARI_NTSC_ENTRY_( ktable, n ) \
(atari_ntsc_rgb_t const*) (ktable + (n) * (atari_ntsc_entry_size * sizeof (atari_ntsc_rgb_t)))
/* deprecated */
#define ATARI_NTSC_RGB24_OUT( x, out ) ATARI_NTSC_RGB_OUT( x, out, 24 )
#define ATARI_NTSC_RGB16_OUT( x, out ) ATARI_NTSC_RGB_OUT( x, out, 16 )
#define ATARI_NTSC_RGB15_OUT( x, out ) ATARI_NTSC_RGB_OUT( x, out, 15 )
#define ATARI_NTSC_RAW_OUT( x, out ) ATARI_NTSC_RGB_OUT( x, out, 0 )
enum { atari_ntsc_min_in_width = 320 }; /* minimum width that doesn't cut off active area */
enum { atari_ntsc_min_out_width = ATARI_NTSC_OUT_WIDTH( atari_ntsc_min_in_width ) };
enum { atari_ntsc_640_in_width = 336 }; /* room for 8-pixel left & right overscan borders */
enum { atari_ntsc_640_out_width = ATARI_NTSC_OUT_WIDTH( atari_ntsc_640_in_width ) };
enum { atari_ntsc_640_overscan_left = 8 };
enum { atari_ntsc_640_overscan_right = atari_ntsc_640_in_width - atari_ntsc_min_in_width - atari_ntsc_640_overscan_left };
enum { atari_ntsc_full_in_width = 384 }; /* room for full overscan */
enum { atari_ntsc_full_out_width = ATARI_NTSC_OUT_WIDTH( atari_ntsc_full_in_width ) };
enum { atari_ntsc_full_overscan_left = 32 };
enum { atari_ntsc_full_overscan_right = atari_ntsc_full_in_width - atari_ntsc_min_in_width - atari_ntsc_full_overscan_left };
/* common 4->7 ntsc macros */
/* Atari change: adapted to 4/7 pixel ratio. */
#define ATARI_NTSC_BEGIN_ROW_8_( pixel0, pixel1, pixel2, pixel3, ENTRY, table ) \
unsigned const atari_ntsc_pixel0_ = (pixel0);\
atari_ntsc_rgb_t const* kernel0 = ENTRY( table, atari_ntsc_pixel0_ );\
unsigned const atari_ntsc_pixel1_ = (pixel1);\
atari_ntsc_rgb_t const* kernel1 = ENTRY( table, atari_ntsc_pixel1_ );\
unsigned const atari_ntsc_pixel2_ = (pixel2);\
atari_ntsc_rgb_t const* kernel2 = ENTRY( table, atari_ntsc_pixel2_ );\
unsigned const atari_ntsc_pixel3_ = (pixel3);\
atari_ntsc_rgb_t const* kernel3 = ENTRY( table, atari_ntsc_pixel3_ );\
atari_ntsc_rgb_t const* kernelx0;\
atari_ntsc_rgb_t const* kernelx1 = kernel0;\
atari_ntsc_rgb_t const* kernelx2 = kernel0;\
atari_ntsc_rgb_t const* kernelx3 = kernel0
/* Atari change: adapted to 4/7 pixel ratio. */
#define ATARI_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
atari_ntsc_rgb_t raw_ =\
kernel0 [x ] + kernel1 [(x+5)%7+14] + kernel2 [(x+3)%7+28] + kernel3 [(x+1)%7+42] +\
kernelx0 [(x+7)%14] + kernelx1 [(x+5)%7+21] + kernelx2 [(x+3)%7+35] + kernelx3 [(x+1)%7+49];\
ATARI_NTSC_CLAMP_( raw_, shift );\
ATARI_NTSC_RGB_OUT_( rgb_out, bits, shift );\
}
/* common ntsc macros */
#define atari_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
#define atari_ntsc_clamp_mask (atari_ntsc_rgb_builder * 3 / 2)
#define atari_ntsc_clamp_add (atari_ntsc_rgb_builder * 0x101)
#define ATARI_NTSC_CLAMP_( io, shift ) {\
atari_ntsc_rgb_t sub = (io) >> (9-(shift)) & atari_ntsc_clamp_mask;\
atari_ntsc_rgb_t clamp = atari_ntsc_clamp_add - sub;\
io |= clamp;\
clamp -= sub;\
io &= clamp;\
}
#define ATARI_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
unsigned color_;\
kernelx##index = kernel##index;\
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
}
/* Atari change: modified ATARI_NTSC_RGB_OUT_ so its BITS parameter is
no longer a straight number of bits, but an enumerated value. Then
added a few additional bit formats. Also added the ATARI_NTSC_RGB_FORMAT
enumerated values. */
enum {
ATARI_NTSC_RGB_FORMAT_RGB16,
ATARI_NTSC_RGB_FORMAT_BGR16,
ATARI_NTSC_RGB_FORMAT_ARGB32,
ATARI_NTSC_RGB_FORMAT_BGRA32,
ATARI_NTSC_RGB_FORMAT_RGB15
};
/* x is always zero except in snes_ntsc library */
#define ATARI_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == ATARI_NTSC_RGB_FORMAT_RGB16 )\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
else if ( bits == ATARI_NTSC_RGB_FORMAT_BGR16 )\
rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(8-x)&0x07E0)|(raw_<<(7+x)&0xF800);\
else if ( bits == ATARI_NTSC_RGB_FORMAT_ARGB32 )\
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF) | 0xFF000000;\
else if ( bits == ATARI_NTSC_RGB_FORMAT_BGRA32 )\
rgb_out = (raw_>>(13-x)&0xFF00)|(raw_<<(5+x)&0xFF0000)|(raw_<<(23+x)&0xFF000000) | 0xFF;\
else if ( bits == ATARI_NTSC_RGB_FORMAT_RGB15 )\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
else if ( bits == 0 )\
rgb_out = raw_ << x;\
}
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,25 @@
/* Configure library by modifying this file */
#ifndef ATARI_NTSC_CONFIG_H
#define ATARI_NTSC_CONFIG_H
/* Atari change: remove NES-specific emphasis support */
/* The following affect the built-in blitter only; a custom blitter can
handle things however it wants. */
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
#define ATARI_NTSC_OUT_DEPTH 16
/* Type of input pixel values. You'll probably use unsigned short
if you enable emphasis above. */
#define ATARI_NTSC_IN_T unsigned char
/* Each raw pixel input value is passed through this. You might want to mask
the pixel index if you use the high bits as flags, etc. */
#define ATARI_NTSC_ADJ_IN( in ) in
/* For each pixel, this is the basic operation:
output_color = color_palette [ATARI_NTSC_ADJ_IN( ATARI_NTSC_IN_T )] */
#endif
+455
View File
@@ -0,0 +1,455 @@
/* Based on nes_ntsc 0.2.2. http://www.slack.net/~ant/ */
/* Common implementation of NTSC filters */
#include <assert.h>
#include <math.h>
/* Copyright (C) 2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#define DISABLE_CORRECTION 0
#undef PI
#define PI 3.14159265358979323846f
#ifndef LUMA_CUTOFF
#define LUMA_CUTOFF 0.20
#endif
#ifndef gamma_size
#define gamma_size 1
#endif
#ifndef rgb_bits
#define rgb_bits 8
#endif
#ifndef artifacts_max
#define artifacts_max (artifacts_mid * 1.5f)
#endif
#ifndef fringing_max
#define fringing_max (fringing_mid * 2)
#endif
#ifndef STD_HUE_CONDITION
#define STD_HUE_CONDITION( setup ) 1
#endif
#define ext_decoder_hue (std_decoder_hue + 15)
#define rgb_unit (1 << rgb_bits)
#define rgb_offset (rgb_unit * 2 + 0.5f)
enum { burst_size = atari_ntsc_entry_size / burst_count };
enum { kernel_half = 16 };
enum { kernel_size = kernel_half * 2 + 1 };
typedef struct init_t
{
float to_rgb [burst_count * 6];
float to_float [gamma_size];
float contrast;
float brightness;
float artifacts;
float fringing;
float kernel [rescale_out * kernel_size * 2];
} init_t;
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
float t;\
t = i * cos_b - q * sin_b;\
q = i * sin_b + q * cos_b;\
i = t;\
}
static void init_filters( init_t* impl, atari_ntsc_setup_t const* setup )
{
#if rescale_out > 1
float kernels [kernel_size * 2];
#else
float* const kernels = impl->kernel;
#endif
/* generate luma (y) filter using sinc kernel */
{
/* sinc with rolloff (dsf) */
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
float const maxh = 32;
float const pow_a_n = (float) pow( rolloff, maxh );
float sum;
int i;
/* quadratic mapping to reduce negative (blurring) range */
float to_angle = (float) setup->resolution + 1;
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = i - kernel_half;
float angle = x * to_angle;
/* instability occurs at center point with rolloff very close to 1.0 */
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
{
float rolloff_cos_a = rolloff * (float) cos( angle );
float num = 1 - rolloff_cos_a -
pow_a_n * (float) cos( maxh * angle ) +
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
float dsf = num / den;
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
}
}
/* apply blackman window and find sum */
sum = 0;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
float x = PI * 2 / (kernel_half * 2) * i;
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
}
/* normalize kernel */
sum = 1.0f / sum;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = kernel_size * 3 / 2 - kernel_half + i;
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
/* generate chroma (iq) filter using gaussian kernel */
{
float const cutoff_factor = -0.03125f;
float cutoff = (float) setup->bleed;
int i;
if ( cutoff < 0 )
{
/* keep extreme value accessible only near upper end of scale (1.0) */
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= -30.0f / 0.65f;
}
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
for ( i = -kernel_half; i <= kernel_half; i++ )
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
/* normalize even and odd phases separately */
for ( i = 0; i < 2; i++ )
{
float sum = 0;
int x;
for ( x = i; x < kernel_size; x += 2 )
sum += kernels [x];
sum = 1.0f / sum;
for ( x = i; x < kernel_size; x += 2 )
{
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
}
/*
printf( "luma:\n" );
for ( i = kernel_size; i < kernel_size * 2; i++ )
printf( "%f\n", kernels [i] );
printf( "chroma:\n" );
for ( i = 0; i < kernel_size; i++ )
printf( "%f\n", kernels [i] );
*/
/* generate linear rescale kernels */
#if rescale_out > 1
{
float weight = 1.0f;
float* out = impl->kernel;
int n = rescale_out;
do
{
float remain = 0;
int i;
weight -= 1.0f / rescale_in;
for ( i = 0; i < kernel_size * 2; i++ )
{
float cur = kernels [i];
float m = cur * weight;
*out++ = m + remain;
remain = cur - m;
}
}
while ( --n );
}
#endif
}
/* Atari change: more accurate values taken from
http://en.wikipedia.org/wiki/YIQ */
static float const default_decoder [6] =
{ 0.9563f, 0.6210f, -0.2721f, -0.6474f, -1.1070f, 1.7046f };
static void init( init_t* impl, atari_ntsc_setup_t const* setup )
{
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
#ifdef default_palette_contrast
if ( !setup->palette )
impl->contrast *= default_palette_contrast;
#endif
impl->artifacts = (float) setup->artifacts;
if ( impl->artifacts > 0 )
impl->artifacts *= artifacts_max - artifacts_mid;
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
impl->fringing = (float) setup->fringing;
if ( impl->fringing > 0 )
impl->fringing *= fringing_max - fringing_mid;
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
init_filters( impl, setup );
/* generate gamma table */
if ( gamma_size > 1 )
{
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
int i;
for ( i = 0; i < gamma_size; i++ )
impl->to_float [i] =
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
}
/* setup decoder matricies */
{
/* Atari change:
NTSC colorburst angle in YIQ colorspace. Colorburst is at
180 degrees in YUV - that is, a gold color. In YIQ, gold is at
different angle. However, YIQ is actually YUV turned
33 degrees. So by looking at screenshots at Wikipedia we can
conclude that the colorburst angle is 270+33 in YIQ.
(See http://en.wikipedia.org/wiki/YUV and
http://en.wikipedia.org/wiki/YIQ) */
static float const colorburst_angle = (303.0f) * PI / 180.0f;
float hue = (float) -setup->hue * PI + PI / 180 * ext_decoder_hue + PI * setup->burst_phase - colorburst_angle;
float sat = (float) setup->saturation + 1;
float const* decoder = setup->decoder_matrix;
if ( !decoder )
{
decoder = default_decoder;
if ( STD_HUE_CONDITION( setup ) )
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
}
{
float s = (float) sin( hue ) * sat;
float c = (float) cos( hue ) * sat;
float* out = impl->to_rgb;
int n;
n = burst_count;
do
{
float const* in = decoder;
int n = 3;
do
{
float i = *in++;
float q = *in++;
*out++ = i * c - q * s;
*out++ = i * s + q * c;
}
while ( --n );
if ( burst_count <= 1 )
break;
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
}
while ( --n );
}
}
}
/* kernel generation */
/* Atari change: more accurate values taken from
http://en.wikipedia.org/wiki/YIQ */
#define RGB_TO_YIQ( r, g, b, y, i ) (\
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
(i = (r) * 0.595716f - (g) * 0.274453f - (b) * 0.321263f),\
((r) * 0.211456f - (g) * 0.522591f + (b) * 0.311135f)\
)
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
)
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
enum { rgb_kernel_size = burst_size / alignment_count };
enum { rgb_bias = rgb_unit * 2 * atari_ntsc_rgb_builder };
typedef struct pixel_info_t
{
int offset;
float negate;
float kernel [4];
} pixel_info_t;
#if rescale_in > 1
#define PIXEL_OFFSET_( ntsc, scaled ) \
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
(kernel_size * 2 * scaled))
#define PIXEL_OFFSET( ntsc, scaled ) \
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
(((scaled) + rescale_out * 10) % rescale_out) ),\
(1.0f - (((ntsc) + 100) & 2))
#else
#define PIXEL_OFFSET( ntsc, scaled ) \
(kernel_size / 2 + (ntsc) - (scaled)),\
(1.0f - (((ntsc) + 100) & 2))
#endif
extern pixel_info_t const atari_ntsc_pixels [alignment_count];
/* Generate pixel at all burst phases and column alignments */
static void gen_kernel( init_t* impl, float y, float i, float q, atari_ntsc_rgb_t* out )
{
/* generate for each scanline burst phase */
float const* to_rgb = impl->to_rgb;
int burst_remain = burst_count;
y -= rgb_offset;
do
{
/* Encode yiq into *two* composite signals (to allow control over artifacting).
Convolve these with kernels which: filter respective components, apply
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
into integer. Based on algorithm by NewRisingSun. */
pixel_info_t const* pixel = atari_ntsc_pixels;
int alignment_remain = alignment_count;
do
{
/* negate is -1 when composite starts at odd multiple of 2 */
float const yy = y * impl->fringing * pixel->negate;
float const ic0 = (i + yy) * pixel->kernel [0];
float const qc1 = (q + yy) * pixel->kernel [1];
float const ic2 = (i - yy) * pixel->kernel [2];
float const qc3 = (q - yy) * pixel->kernel [3];
float const factor = impl->artifacts * pixel->negate;
float const ii = i * factor;
float const yc0 = (y + ii) * pixel->kernel [0];
float const yc2 = (y - ii) * pixel->kernel [2];
float const qq = q * factor;
float const yc1 = (y + qq) * pixel->kernel [1];
float const yc3 = (y - qq) * pixel->kernel [3];
float const* k = &impl->kernel [pixel->offset];
int n;
++pixel;
for ( n = rgb_kernel_size; n; --n )
{
float i = k[0]*ic0 + k[2]*ic2;
float q = k[1]*qc1 + k[3]*qc3;
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
if ( rescale_out <= 1 )
k--;
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
k += kernel_size * 2 - 1;
else
k -= kernel_size * 2 * (rescale_out - 1) + 2;
{
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
}
}
}
while ( alignment_count > 1 && --alignment_remain );
if ( burst_count <= 1 )
break;
to_rgb += 6;
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
}
while ( --burst_remain );
}
static void correct_errors( atari_ntsc_rgb_t color, atari_ntsc_rgb_t* out );
/* Atari change: adjust DISTRIBUTE_ERROR to 4/7 pixel ratio. */
#if DISABLE_CORRECTION
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
#define DISTRIBUTE_ERROR( a, b, c, d ) { out [i] += rgb_bias; }
#else
#define CORRECT_ERROR( a ) { out [a] += error; }
#define DISTRIBUTE_ERROR( a, b, c, d ) {\
atari_ntsc_rgb_t fourth = (error + 2 * atari_ntsc_rgb_builder) >> 2;\
fourth &= (rgb_bias >> 1) - atari_ntsc_rgb_builder;\
fourth -= rgb_bias >> 2;\
out [a] += fourth;\
out [b] += fourth;\
out [c] += fourth;\
out [d] += fourth;\
out [i] += error - (fourth * 4);\
}
#endif
#define RGB_PALETTE_OUT( rgb, out_ )\
{\
unsigned char* out = (out_);\
atari_ntsc_rgb_t clamped = (rgb);\
ATARI_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
out [0] = (unsigned char) (clamped >> 21);\
out [1] = (unsigned char) (clamped >> 11);\
out [2] = (unsigned char) (clamped >> 1);\
}
/* blitter related */
#ifndef restrict
#if defined (__GNUC__)
#define restrict __restrict__
#elif defined (_MSC_VER) && _MSC_VER > 1300
#define restrict __restrict
#else
/* no support for restricted pointers */
#define restrict
#endif
#endif
#include <limits.h>
#if ATARI_NTSC_OUT_DEPTH <= 16
#if USHRT_MAX == 0xFFFF
typedef unsigned short atari_ntsc_out_t;
#else
#error "Need 16-bit int type"
#endif
#else
#if UINT_MAX == 0xFFFFFFFF
typedef unsigned int atari_ntsc_out_t;
#elif ULONG_MAX == 0xFFFFFFFF
typedef unsigned long atari_ntsc_out_t;
#else
#error "Need 32-bit int type"
#endif
#endif