From d597f21e01fd8f3b27236f1516ba1163e7d79f4a Mon Sep 17 00:00:00 2001 From: Persune Date: Mon, 23 Oct 2023 02:13:29 +0800 Subject: [PATCH] Use standard RGB-YIQ matrix coefficients https://forums.nesdev.org/viewtopic.php?p=172817#p172817 Bisqwit originally intended to match a certain palette using different display primaries ("FCC D65"). This resulted in colors that looked off. The modification here is to more closely match Bisqwit's own palette generator, which uses a more standard RGB-YIQ matrix. at hue 0, saturation 1.0, contrast 1.0, brightness 1.0, gamma 2.2 https://bisqwit.iki.fi/utils/nespalette.php IQ component coefficients are derived from the NTSC base matrix of luminance and color-difference. with color reduction factors and an additional 33 degree rotation of each respective component. https://www.nesdev.org/wiki/NTSC_video#Converting_YUV_to_signal_RGB --- Core/NES/BisqwitNtscFilter.cpp | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/Core/NES/BisqwitNtscFilter.cpp b/Core/NES/BisqwitNtscFilter.cpp index 53f054fff..1d5b3bcea 100644 --- a/Core/NES/BisqwitNtscFilter.cpp +++ b/Core/NES/BisqwitNtscFilter.cpp @@ -65,7 +65,7 @@ BisqwitNtscFilter::BisqwitNtscFilter(Emulator* emu) : BaseVideoFilter(emu) //Adjust outputbuffer to start at the middle of the picture outputBuffer += frameInfo.Width * (frameInfo.Height / 2); - DecodeFrame(120, 239 - GetOverscan().Bottom, _ppuOutputBuffer, outputBuffer, GetVideoPhaseOffset() + 120*341*_signalsPerPixel); + DecodeFrame(120, 239 - GetOverscan().Bottom, _ppuOutputBuffer, outputBuffer, GetVideoPhaseOffset() + 120 * 341 * _signalsPerPixel); _workDone = true; } @@ -133,14 +133,29 @@ void BisqwitNtscFilter::OnBeforeApplyFilter() _y = contrast / _yWidth; - _ir = (int)(contrast * 1.994681e-6 * saturation / _iWidth); - _qr = (int)(contrast * 9.915742e-7 * saturation / _qWidth); - - _ig = (int)(contrast * 9.151351e-8 * saturation / _iWidth); - _qg = (int)(contrast * -6.334805e-7 * saturation / _qWidth); - - _ib = (int)(contrast * -1.012984e-6 * saturation / _iWidth); - _qb = (int)(contrast * 1.667217e-6 * saturation / _qWidth); + // https://forums.nesdev.org/viewtopic.php?p=172817#p172817 + // Bisqwit originally intended to match a certain palette using different + // display primaries ("FCC D65"). This resulted in colors that looked off. + // The modification here is to more closely match Bisqwit's own palette + // generator, which uses a more standard RGB-YIQ matrix. + // at hue 0, saturation 1.0, contrast 1.0, brightness 1.0, gamma 2.2 + // https://bisqwit.iki.fi/utils/nespalette.php + + // for some reason the original coefficients of bisqwit's decoding matrix + // has been reduced by at least 10^-6 + double saturationFactor = 1000000; + + // IQ coefficients are derived from the NTSC base matrix of luminance and color-difference + // with color reduction factors and an additional 33 degree rotation of each respective component. + // https://www.nesdev.org/wiki/NTSC_video#Converting_YUV_to_signal_RGB + _ir = (int)(contrast * ( 0.956084 / saturationFactor) * saturation / _iWidth); + _qr = (int)(contrast * ( 0.620888 / saturationFactor) * saturation / _qWidth); + + _ig = (int)(contrast * (-0.272281 / saturationFactor) * saturation / _iWidth); + _qg = (int)(contrast * (-0.646901 / saturationFactor) * saturation / _qWidth); + + _ib = (int)(contrast * (-1.105617 / saturationFactor) * saturation / _iWidth); + _qb = (int)(contrast * ( 1.702501 / saturationFactor) * saturation / _qWidth); } void BisqwitNtscFilter::RecursiveBlend(int iterationCount, uint64_t *output, uint64_t *currentLine, uint64_t *nextLine, int pixelsPerCycle, bool verticalBlend)