diff --git a/src/common/tv_filters/AtariNTSC.cxx b/src/common/tv_filters/AtariNTSC.cxx index 2e3bd06cc..9fa36eaf9 100644 --- a/src/common/tv_filters/AtariNTSC.cxx +++ b/src/common/tv_filters/AtariNTSC.cxx @@ -43,14 +43,13 @@ void AtariNTSC::initializePalette(const uInt8* palette) // Palette stores R/G/B data for 'palette_size' entries for ( uInt32 entry = 0; entry < palette_size; ++entry ) { - float r = myImpl.to_float [*palette++]; - float g = myImpl.to_float [*palette++]; - float b = myImpl.to_float [*palette++]; - - float y, i, q = RGB_TO_YIQ( r, g, b, y, i ); + float r = myImpl.to_float [*palette++], + g = myImpl.to_float [*palette++], + b = myImpl.to_float [*palette++]; + float y, i, q; RGB_TO_YIQ( r, g, b, y, i, q ); // Generate kernel - int ir, ig, ib = YIQ_TO_RGB( y, i, q, myImpl.to_rgb, int, ir, ig ); + int ir, ig, ib; YIQ_TO_RGB( y, i, q, myImpl.to_rgb.data(), ir, ig, ib ); uInt32 rgb = PACK_RGB( ir, ig, ib ); uInt32* kernel = myColorTable[entry]; @@ -77,7 +76,7 @@ void AtariNTSC::enableThreading(bool enable) } else { - systemThreads = std::max(1u, std::min(4u, systemThreads - 1)); + systemThreads = std::max(1, std::min(4, systemThreads - 1)); myWorkerThreads = systemThreads - 1; myTotalThreads = systemThreads; @@ -306,15 +305,14 @@ void AtariNTSC::renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline uInt32 AtariNTSC::getRGBPhosphor(const uInt32 c, const uInt32 p) const { -#define TO_RGB(color, red, green, blue) \ - const uInt8 red = uInt8(color >> 16); \ - const uInt8 green = uInt8(color >> 8);\ - const uInt8 blue = uInt8(color); - - TO_RGB(c, rc, gc, bc) - TO_RGB(p, rp, gp, bp) - // Mix current calculated frame with previous displayed frame + const uInt8 rc = uInt8(c >> 16); + const uInt8 gc = uInt8(c >> 8); + const uInt8 bc = uInt8(c); + const uInt8 rp = uInt8(p >> 16); + const uInt8 gp = uInt8(p >> 8); + const uInt8 bp = uInt8(p); + const uInt8 rn = myPhosphorPalette[rc][rp]; const uInt8 gn = myPhosphorPalette[gc][gp]; const uInt8 bn = myPhosphorPalette[bc][bp]; @@ -325,8 +323,8 @@ inline uInt32 AtariNTSC::getRGBPhosphor(const uInt32 c, const uInt32 p) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::init(init_t& impl, const Setup& setup) { - impl.brightness = setup.brightness * (0.5f * rgb_unit) + rgb_offset; - impl.contrast = setup.contrast * (0.5f * rgb_unit) + rgb_unit; + impl.brightness = setup.brightness * (0.5F * rgb_unit) + rgb_offset; + impl.contrast = setup.contrast * (0.5F * rgb_unit) + rgb_unit; impl.artifacts = setup.artifacts; if ( impl.artifacts > 0 ) @@ -343,8 +341,8 @@ void AtariNTSC::init(init_t& impl, const Setup& setup) /* generate gamma table */ if (true) /* was (gamma_size > 1) */ { - float const to_float = 1.0f / (gamma_size - 1/*(gamma_size > 1)*/); - float const gamma = 1.1333f - setup.gamma * 0.5f; + float const to_float = 1.F / (gamma_size - 1/*(gamma_size > 1)*/); + float const gamma = 1.1333F - 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++ ) @@ -360,13 +358,13 @@ void AtariNTSC::init(init_t& impl, const Setup& setup) float s = sinf( hue ) * sat; float c = cosf( hue ) * sat; - float* out = impl.to_rgb; + float* out = impl.to_rgb.data(); int n; n = burst_count; do { - float const* in = default_decoder; + float const* in = default_decoder.data(); int n2 = 3; do { @@ -378,7 +376,7 @@ void AtariNTSC::init(init_t& impl, const Setup& setup) while ( --n2 ); #if 0 // burst_count is always 0 if ( burst_count > 1 ) - ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */ + ROTATE_IQ( s, c, 0.866025F, -0.5F ); /* +120 degrees */ #endif } while ( --n ); @@ -388,18 +386,18 @@ void AtariNTSC::init(init_t& impl, const Setup& setup) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::initFilters(init_t& impl, const Setup& setup) { - float kernels [kernel_size * 2]; + std::array kernels; /* generate luma (y) filter using sinc kernel */ { /* sinc with rolloff (dsf) */ - float const rolloff = 1 + setup.sharpness * 0.032f; + float const rolloff = 1 + setup.sharpness * 0.032F; constexpr float maxh = 32; float const pow_a_n = powf( rolloff, maxh ); float sum; /* quadratic mapping to reduce negative (blurring) range */ float to_angle = setup.resolution + 1; - to_angle = BSPF::PI_f / maxh * LUMA_CUTOFF * (to_angle * to_angle + 1.f); + to_angle = BSPF::PI_f / maxh * luma_cutoff * (to_angle * to_angle + 1.f); kernels [kernel_size * 3 / 2] = maxh; /* default center value */ for ( int i = 0; i < kernel_half * 2 + 1; i++ ) @@ -407,7 +405,7 @@ void AtariNTSC::initFilters(init_t& impl, const Setup& setup) 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 > 1.056f || pow_a_n < 0.981f ) + if ( x || pow_a_n > 1.056F || pow_a_n < 0.981F ) { float rolloff_cos_a = rolloff * cosf( angle ); float num = 1 - rolloff_cos_a - @@ -415,7 +413,7 @@ void AtariNTSC::initFilters(init_t& impl, const Setup& setup) pow_a_n * rolloff * cosf( (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 - 0.5f; + kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - 0.5F; } } @@ -424,12 +422,12 @@ void AtariNTSC::initFilters(init_t& impl, const Setup& setup) for ( int i = 0; i < kernel_half * 2 + 1; i++ ) { float x = BSPF::PI_f * 2 / (kernel_half * 2) * i; - float blackman = 0.42f - 0.5f * cosf( x ) + 0.08f * cosf( x * 2 ); + float blackman = 0.42F - 0.5F * cosf( x ) + 0.08F * cosf( x * 2 ); sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman); } /* normalize kernel */ - sum = 1.0f / sum; + sum = 1.0F / sum; for ( int i = 0; i < kernel_half * 2 + 1; i++ ) { int x = kernel_size * 3 / 2 - kernel_half + i; @@ -439,7 +437,7 @@ void AtariNTSC::initFilters(init_t& impl, const Setup& setup) /* generate chroma (iq) filter using gaussian kernel */ { - constexpr float cutoff_factor = -0.03125f; + constexpr float cutoff_factor = -0.03125F; float cutoff = setup.bleed; if ( cutoff < 0 ) @@ -448,9 +446,9 @@ void AtariNTSC::initFilters(init_t& impl, const Setup& setup) cutoff *= cutoff; cutoff *= cutoff; cutoff *= cutoff; - cutoff *= -30.0f / 0.65f; + cutoff *= -30.0F / 0.65F; } - cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff; + cutoff = cutoff_factor - 0.65F * cutoff_factor * cutoff; for ( int i = -kernel_half; i <= kernel_half; i++ ) kernels [kernel_size / 2 + i] = expf( i * i * cutoff ); @@ -463,7 +461,7 @@ void AtariNTSC::initFilters(init_t& impl, const Setup& setup) for ( x = i; x < kernel_size; x += 2 ) sum += kernels [x]; - sum = 1.0f / sum; + sum = 1.0F / sum; for ( x = i; x < kernel_size; x += 2 ) { kernels [x] *= sum; @@ -472,13 +470,13 @@ void AtariNTSC::initFilters(init_t& impl, const Setup& setup) } /* generate linear rescale kernels */ - float weight = 1.0f; - float* out = impl.kernel; + float weight = 1.0F; + float* out = impl.kernel.data(); int n = rescale_out; do { float remain = 0; - weight -= 1.0f / rescale_in; + weight -= 1.0F / rescale_in; for ( int i = 0; i < kernel_size * 2; i++ ) { float cur = kernels [i]; @@ -495,7 +493,7 @@ void AtariNTSC::initFilters(init_t& impl, const Setup& setup) void AtariNTSC::genKernel(init_t& impl, float y, float i, float q, uInt32* out) { /* generate for each scanline burst phase */ - float const* to_rgb = impl.to_rgb; + float const* to_rgb = impl.to_rgb.data(); int burst_remain = burst_count; y -= rgb_offset; do @@ -504,7 +502,7 @@ void AtariNTSC::genKernel(init_t& impl, float y, float i, float q, uInt32* out) 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; + pixel_info_t const* pixel = atari_ntsc_pixels.data(); int alignment_remain = alignment_count; do { @@ -538,7 +536,7 @@ void AtariNTSC::genKernel(init_t& impl, float y, float i, float q, uInt32* out) else k -= kernel_size * 2 * (rescale_out - 1) + 2; { - int r, g, b = YIQ_TO_RGB( fy, fi, fq, to_rgb, int, r, g ); + int r, g, b; YIQ_TO_RGB( fy, fi, fq, to_rgb, r, g, b ); *out++ = PACK_RGB( r, g, b ) - rgb_bias; } } @@ -550,24 +548,26 @@ void AtariNTSC::genKernel(init_t& impl, float y, float i, float q, uInt32* out) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const AtariNTSC::Setup AtariNTSC::TV_Composite = { - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.15f, 0.0f, 0.0f, 0.0f + 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.15F, 0.0F, 0.0F, 0.0F }; const AtariNTSC::Setup AtariNTSC::TV_SVideo = { - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.45f, -1.0f, -1.0f, 0.0f + 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.45F, -1.0F, -1.0F, 0.0F }; const AtariNTSC::Setup AtariNTSC::TV_RGB = { - 0.0f, 0.0f, 0.0f, 0.0f, 0.2f, 0.0f, 0.70f, -1.0f, -1.0f, -1.0f + 0.0F, 0.0F, 0.0F, 0.0F, 0.2F, 0.0F, 0.70F, -1.0F, -1.0F, -1.0F }; const AtariNTSC::Setup AtariNTSC::TV_Bad = { - 0.1f, -0.3f, 0.3f, 0.25f, 0.2f, 0.0f, 0.1f, 0.5f, 0.5f, 0.5f + 0.1F, -0.3F, 0.3F, 0.25F, 0.2F, 0.0F, 0.1F, 0.5F, 0.5F, 0.5F }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const AtariNTSC::pixel_info_t AtariNTSC::atari_ntsc_pixels[alignment_count] = { - { PIXEL_OFFSET( -4, -9 ), { 1, 1, 1, 1 } }, - { PIXEL_OFFSET( 0, -5 ), { 1, 1, 1, 1 } }, -}; +const std::array +AtariNTSC::atari_ntsc_pixels = { { + { PIXEL_OFFSET1(-4, -9), PIXEL_OFFSET2(-4), { 1, 1, 1, 1 } }, + { PIXEL_OFFSET1( 0, -5), PIXEL_OFFSET2( 0), { 1, 1, 1, 1 } } +} }; -const float AtariNTSC::default_decoder[6] = { - 0.9563f, 0.6210f, -0.2721f, -0.6474f, -1.1070f, 1.7046f +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const std::array AtariNTSC::default_decoder = { + 0.9563F, 0.6210F, -0.2721F, -0.6474F, -1.1070F, 1.7046F }; diff --git a/src/common/tv_filters/AtariNTSC.hxx b/src/common/tv_filters/AtariNTSC.hxx index 6fc1f95da..c2a126c22 100644 --- a/src/common/tv_filters/AtariNTSC.hxx +++ b/src/common/tv_filters/AtariNTSC.hxx @@ -151,16 +151,20 @@ class AtariNTSC rgb_bias = rgb_unit * 2 * rgb_builder, std_decoder_hue = 0, - ext_decoder_hue = std_decoder_hue + 15 + ext_decoder_hue = std_decoder_hue + 15, + + atari_ntsc_clamp_mask = rgb_builder * 3 / 2, + atari_ntsc_clamp_add = rgb_builder * 0x101 ; - #define artifacts_mid 1.5f - #define artifacts_max 2.5f - #define fringing_mid 1.0f - #define fringing_max 2.0f - #define rgb_offset (rgb_unit * 2 + 0.5f) - - #define LUMA_CUTOFF 0.20f + static constexpr float + artifacts_mid = 1.5F, + artifacts_max = 2.5F, + fringing_mid = 1.0F, + fringing_max = 2.0F, + rgb_offset = (rgb_unit * 2 + 0.5F), + luma_cutoff = 0.20F + ; uInt32 myColorTable[palette_size][entry_size]; uInt8 myPhosphorPalette[256][256]; @@ -172,18 +176,18 @@ class AtariNTSC struct init_t { - float to_rgb [burst_count * 6]; - float to_float [gamma_size]; + std::array to_rgb; + std::array to_float; float contrast; float brightness; float artifacts; float fringing; - float kernel [rescale_out * kernel_size * 2]; + std::array kernel; init_t() : contrast(0.0), brightness(0.0), artifacts(0.0), fringing(0.0) { - std::fill(to_rgb, to_rgb + burst_count * 6, 0.0); - std::fill(to_float, to_float + gamma_size, 0.0); - std::fill(kernel, kernel + rescale_out * kernel_size * 2, 0.0); + to_rgb.fill(0.0); + to_float.fill(0.0); + kernel.fill(0.0); } }; init_t myImpl; @@ -192,11 +196,11 @@ class AtariNTSC { int offset; float negate; - float kernel [4]; + std::array kernel; }; - static const pixel_info_t atari_ntsc_pixels[alignment_count]; + static const std::array atari_ntsc_pixels; - static const float default_decoder[6]; + static const std::array default_decoder; void init(init_t& impl, const Setup& setup); void initFilters(init_t& impl, const Setup& setup); @@ -220,57 +224,60 @@ class AtariNTSC kernel##index = (color_ = (color), myColorTable[color_]);\ } - // Generates output in the specified 32-bit format (x = junk bits). - // native: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format) + // Generates output in the specified 32-bit format. // 8888: 00000000 RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8-8 32-bit ARGB) #define ATARI_NTSC_RGB_OUT_8888( index, rgb_out ) {\ uInt32 raw_ =\ kernel0 [index ] + kernel1 [(index+10)%7+14] +\ kernelx0 [(index+7)%14] + kernelx1 [(index+ 3)%7+14+7];\ - ATARI_NTSC_CLAMP_( raw_, 0 );\ + ATARI_NTSC_CLAMP( raw_, 0 );\ rgb_out = (raw_>>5 & 0x00FF0000)|(raw_>>3 & 0x0000FF00)|(raw_>>1 & 0x000000FF);\ } // Common ntsc macros - #define atari_ntsc_clamp_mask (rgb_builder * 3 / 2) - #define atari_ntsc_clamp_add (rgb_builder * 0x101) - #define ATARI_NTSC_CLAMP_( io, shift ) {\ - uInt32 sub = (io) >> (9-(shift)) & atari_ntsc_clamp_mask;\ - uInt32 clamp = atari_ntsc_clamp_add - sub;\ - io |= clamp;\ - clamp -= sub;\ - io &= clamp;\ + static inline constexpr void ATARI_NTSC_CLAMP( uInt32& io, uInt32 shift ) { + uInt32 sub = io >> (9-(shift)) & atari_ntsc_clamp_mask; + uInt32 clamp = atari_ntsc_clamp_add - sub; + io |= clamp; + clamp -= sub; + io &= clamp; } - // Kernel generation + static inline constexpr void RGB_TO_YIQ(float r, float g, float b, + float& y, float& i, float& q) { + y = r * 0.299F + g * 0.587F + b * 0.114F; + i = r * 0.595716F - g * 0.274453F - b * 0.321263F; + q = r * 0.211456F - g * 0.522591F + b * 0.311135F; + } + static inline constexpr void YIQ_TO_RGB(float y, float i, float q, + const float* to_rgb, int& ir, int& ig, int& ib) { + ir = static_cast(y + to_rgb[0] * i + to_rgb[1] * q); + ig = static_cast(y + to_rgb[2] * i + to_rgb[3] * q); + ib = static_cast(y + to_rgb[4] * i + to_rgb[5] * q); + } + + static inline constexpr uInt32 PACK_RGB( int r, int g, int b ) { + return r << 21 | g << 11 | b << 1; + } + + // Converted from C-style macros; I don't even pretend to understand the logic here :) + static inline constexpr int PIXEL_OFFSET1( int ntsc, int scaled ) { + return (kernel_size / 2 + ((ntsc) - (scaled) / rescale_out * rescale_in) + + ((((scaled) + rescale_out * 10) % rescale_out) != 0) + + (rescale_out - (((scaled) + rescale_out * 10) % rescale_out)) % rescale_out + + (kernel_size * 2 * (((scaled) + rescale_out * 10) % rescale_out))); + } + static inline constexpr int PIXEL_OFFSET2( int ntsc ) { + return 1.0F - (((ntsc) + 100) & 2); + } + + #if 0 // DEAD CODE #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;\ } - #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)\ - ) - #ifndef PACK_RGB - #define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1) - #endif - - #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)) #define DISTRIBUTE_ERROR( a, b, c ) {\ uInt32 fourth = (error + 2 * rgb_builder) >> 2;\ @@ -285,11 +292,12 @@ class AtariNTSC #define RGB_PALETTE_OUT( rgb, out_ ) {\ unsigned char* out = (out_);\ uInt32 clamped = (rgb);\ - ATARI_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\ + 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);\ } + #endif }; #endif diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 047898c27..ced7741d2 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -232,7 +232,7 @@ void NTSCFilter::convertToAdjustable(Adjustable& adjustable, AtariNTSC::Setup NTSCFilter::myCustomSetup = AtariNTSC::TV_Composite; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const NTSCFilter::AdjustableTag NTSCFilter::ourCustomAdjustables[10] = { +const std::array NTSCFilter::ourCustomAdjustables = { { { "contrast", &myCustomSetup.contrast }, { "brightness", &myCustomSetup.brightness }, { "hue", &myCustomSetup.hue }, @@ -243,4 +243,4 @@ const NTSCFilter::AdjustableTag NTSCFilter::ourCustomAdjustables[10] = { { "artifacts", &myCustomSetup.artifacts }, { "fringing", &myCustomSetup.fringing }, { "bleeding", &myCustomSetup.bleed } -}; +} }; diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx index a1e26b2bf..3530b877b 100644 --- a/src/common/tv_filters/NTSCFilter.hxx +++ b/src/common/tv_filters/NTSCFilter.hxx @@ -109,12 +109,12 @@ class NTSCFilter // Perform Blargg filtering on input buffer, place results in // output buffer - inline void render(uInt8* src_buf, uInt32 src_width, uInt32 src_height, + inline void render(const uInt8* src_buf, uInt32 src_width, uInt32 src_height, uInt32* dest_buf, uInt32 dest_pitch) { myNTSC.render(src_buf, src_width, src_height, dest_buf, dest_pitch); } - inline void render(uInt8* src_buf, uInt32 src_width, uInt32 src_height, + inline void render(const uInt8* src_buf, uInt32 src_width, uInt32 src_height, uInt32* dest_buf, uInt32 dest_pitch, uInt32* prev_buf) { myNTSC.render(src_buf, src_width, src_height, dest_buf, dest_pitch, prev_buf); @@ -156,7 +156,7 @@ class NTSCFilter float* value; }; uInt32 myCurrentAdjustable; - static const AdjustableTag ourCustomAdjustables[10]; + static const std::array ourCustomAdjustables; private: // Following constructors and assignment operators not supported