mirror of
https://github.com/SourMesen/Mesen.git
synced 2024-06-02 11:28:17 -04:00
130 lines
4.6 KiB
C++
130 lines
4.6 KiB
C++
#include "stdafx.h"
|
|
#include "DefaultVideoFilter.h"
|
|
#include "EmulationSettings.h"
|
|
#include <math.h>
|
|
#include <algorithm>
|
|
#include "PPU.h"
|
|
#include "DebugHud.h"
|
|
#include "Console.h"
|
|
|
|
|
|
DefaultVideoFilter::DefaultVideoFilter(shared_ptr<Console> console) : BaseVideoFilter(console)
|
|
{
|
|
InitConversionMatrix(_pictureSettings.Hue, _pictureSettings.Saturation);
|
|
}
|
|
|
|
void DefaultVideoFilter::InitConversionMatrix(double hueShift, double saturationShift)
|
|
{
|
|
_pictureSettings.Hue = hueShift;
|
|
_pictureSettings.Saturation = saturationShift;
|
|
|
|
double hue = hueShift * 3.14159265358979323846264f;
|
|
double sat = saturationShift + 1;
|
|
|
|
double baseValues[6] = { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
|
|
|
double s = sin(hue) * sat;
|
|
double c = cos(hue) * sat;
|
|
|
|
double *output = _yiqToRgbMatrix;
|
|
double *input = baseValues;
|
|
for(int n = 0; n < 3; n++) {
|
|
double i = *input++;
|
|
double q = *input++;
|
|
*output++ = i * c - q * s;
|
|
*output++ = i * s + q * c;
|
|
}
|
|
}
|
|
|
|
FrameInfo DefaultVideoFilter::GetFrameInfo()
|
|
{
|
|
OverscanDimensions overscan = GetOverscan();
|
|
return { overscan.GetScreenWidth(), overscan.GetScreenHeight(), PPU::ScreenWidth, PPU::ScreenHeight, 4 };
|
|
}
|
|
|
|
void DefaultVideoFilter::OnBeforeApplyFilter()
|
|
{
|
|
PictureSettings currentSettings = _console->GetSettings()->GetPictureSettings();
|
|
if(_pictureSettings.Hue != currentSettings.Hue || _pictureSettings.Saturation != currentSettings.Saturation) {
|
|
InitConversionMatrix(currentSettings.Hue, currentSettings.Saturation);
|
|
}
|
|
_pictureSettings = currentSettings;
|
|
_needToProcess = _pictureSettings.Hue != 0 || _pictureSettings.Saturation != 0 || _pictureSettings.Brightness || _pictureSettings.Contrast;
|
|
|
|
if(_needToProcess) {
|
|
double y, i, q;
|
|
uint32_t* originalPalette = _console->GetSettings()->GetRgbPalette();
|
|
|
|
for(int pal = 0; pal < 512; pal++) {
|
|
uint32_t pixelOutput = originalPalette[pal];
|
|
double redChannel = ((pixelOutput & 0xFF0000) >> 16) / 255.0;
|
|
double greenChannel = ((pixelOutput & 0xFF00) >> 8) / 255.0;
|
|
double blueChannel = (pixelOutput & 0xFF) / 255.0;
|
|
|
|
//Apply brightness, contrast, hue & saturation
|
|
RgbToYiq(redChannel, greenChannel, blueChannel, y, i, q);
|
|
y *= _pictureSettings.Contrast * 0.5f + 1;
|
|
y += _pictureSettings.Brightness * 0.5f;
|
|
YiqToRgb(y, i, q, redChannel, greenChannel, blueChannel);
|
|
|
|
int r = std::min(255, (int)(redChannel * 255));
|
|
int g = std::min(255, (int)(greenChannel * 255));
|
|
int b = std::min(255, (int)(blueChannel * 255));
|
|
|
|
_calculatedPalette[pal] = 0xFF000000 | (r << 16) | (g << 8) | b;
|
|
}
|
|
} else {
|
|
memcpy(_calculatedPalette, _console->GetSettings()->GetRgbPalette(), sizeof(_calculatedPalette));
|
|
}
|
|
}
|
|
|
|
void DefaultVideoFilter::DecodePpuBuffer(uint16_t *ppuOutputBuffer, uint32_t* outputBuffer, bool displayScanlines)
|
|
{
|
|
uint32_t* out = outputBuffer;
|
|
OverscanDimensions overscan = GetOverscan();
|
|
uint8_t scanlineIntensity = (uint8_t)((1.0 - _console->GetSettings()->GetPictureSettings().ScanlineIntensity) * 255);
|
|
for(uint32_t i = overscan.Top, iMax = 240 - overscan.Bottom; i < iMax; i++) {
|
|
if(displayScanlines && (i + overscan.Top) % 2 == 0) {
|
|
for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) {
|
|
*out = ApplyScanlineEffect(ppuOutputBuffer[i * 256 + j], scanlineIntensity);
|
|
out++;
|
|
}
|
|
} else {
|
|
for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) {
|
|
*out = _calculatedPalette[ppuOutputBuffer[i * 256 + j]];
|
|
out++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
|
|
{
|
|
DecodePpuBuffer(ppuOutputBuffer, GetOutputBuffer(), _console->GetSettings()->GetVideoFilterType() <= VideoFilterType::BisqwitNtsc);
|
|
}
|
|
|
|
void DefaultVideoFilter::RgbToYiq(double r, double g, double b, double &y, double &i, double &q)
|
|
{
|
|
y = r * 0.299f + g * 0.587f + b * 0.114f;
|
|
i = r * 0.596f - g * 0.275f - b * 0.321f;
|
|
q = r * 0.212f - g * 0.523f + b * 0.311f;
|
|
}
|
|
|
|
void DefaultVideoFilter::YiqToRgb(double y, double i, double q, double &r, double &g, double &b)
|
|
{
|
|
r = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[0] * i + _yiqToRgbMatrix[1] * q)));
|
|
g = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[2] * i + _yiqToRgbMatrix[3] * q)));
|
|
b = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[4] * i + _yiqToRgbMatrix[5] * q)));
|
|
}
|
|
|
|
uint32_t DefaultVideoFilter::ApplyScanlineEffect(uint16_t ppuPixel, uint8_t scanlineIntensity)
|
|
{
|
|
uint32_t pixelOutput = _calculatedPalette[ppuPixel];
|
|
|
|
uint8_t r = ((pixelOutput & 0xFF0000) >> 16) * scanlineIntensity / 255;
|
|
uint8_t g = ((pixelOutput & 0xFF00) >> 8) * scanlineIntensity / 255;
|
|
uint8_t b = (pixelOutput & 0xFF) * scanlineIntensity / 255;
|
|
|
|
return 0xFF000000 | (r << 16) | (g << 8) | b;
|
|
}
|