Mesen-S/Core/NtscFilter.cpp

91 lines
3.5 KiB
C++

#include "stdafx.h"
#include "NtscFilter.h"
#include "EmuSettings.h"
#include "SettingTypes.h"
#include "Console.h"
NtscFilter::NtscFilter(shared_ptr<Console> console) : BaseVideoFilter(console)
{
memset(&_ntscData, 0, sizeof(_ntscData));
_ntscSetup = { };
snes_ntsc_init(&_ntscData, &_ntscSetup);
_ntscBuffer = new uint32_t[SNES_NTSC_OUT_WIDTH(256) * 480];
}
FrameInfo NtscFilter::GetFrameInfo()
{
OverscanDimensions overscan = GetOverscan();
int widthDivider = _baseFrameInfo.Width == 512 ? 2 : 1;
int heightMultiplier = _baseFrameInfo.Width == 512 ? 1 : 2;
FrameInfo frameInfo;
frameInfo.Width = SNES_NTSC_OUT_WIDTH(_baseFrameInfo.Width / widthDivider) - overscan.Left*2 - overscan.Right*2;
frameInfo.Height = _baseFrameInfo.Height * heightMultiplier - overscan.Top*2 - overscan.Bottom*2;
return frameInfo;
}
void NtscFilter::OnBeforeApplyFilter()
{
VideoConfig cfg = _console->GetSettings()->GetVideoConfig();
if(_ntscSetup.hue != cfg.Hue / 100.0 || _ntscSetup.saturation != cfg.Saturation / 100.0 || _ntscSetup.brightness != cfg.Brightness / 100.0 || _ntscSetup.contrast != cfg.Contrast / 100.0 ||
_ntscSetup.artifacts != cfg.NtscArtifacts || _ntscSetup.bleed != cfg.NtscBleed || _ntscSetup.fringing != cfg.NtscFringing || _ntscSetup.gamma != cfg.NtscGamma ||
(_ntscSetup.merge_fields == 1) != cfg.NtscMergeFields || _ntscSetup.resolution != cfg.NtscResolution || _ntscSetup.sharpness != cfg.NtscSharpness) {
_ntscSetup.hue = cfg.Hue;
_ntscSetup.saturation = cfg.Saturation;
_ntscSetup.brightness = cfg.Brightness;
_ntscSetup.contrast = cfg.Contrast;
_ntscSetup.artifacts = cfg.NtscArtifacts;
_ntscSetup.bleed = cfg.NtscBleed;
_ntscSetup.fringing = cfg.NtscFringing;
_ntscSetup.gamma = cfg.NtscGamma;
_ntscSetup.merge_fields = (int)cfg.NtscMergeFields;
_ntscSetup.resolution = cfg.NtscResolution;
_ntscSetup.sharpness = cfg.NtscSharpness;
snes_ntsc_init(&_ntscData, &_ntscSetup);
}
}
void NtscFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
{
FrameInfo frameInfo = GetFrameInfo();
OverscanDimensions overscan = GetOverscan();
bool useHighResOutput = _baseFrameInfo.Width == 512;
uint32_t baseWidth = SNES_NTSC_OUT_WIDTH(256);
uint32_t xOffset = overscan.Left * 2;
uint32_t yOffset = overscan.Top * 2 * baseWidth;
if(useHighResOutput) {
snes_ntsc_blit_hires(&_ntscData, ppuOutputBuffer, 512, IsOddFrame() ? 0 : 1, 512, _baseFrameInfo.Height, _ntscBuffer, SNES_NTSC_OUT_WIDTH(256) * 4);
} else {
snes_ntsc_blit(&_ntscData, ppuOutputBuffer, 256, IsOddFrame() ? 0 : 1, 256, _baseFrameInfo.Height, _ntscBuffer, SNES_NTSC_OUT_WIDTH(256) * 8);
}
VideoConfig cfg = _console->GetSettings()->GetVideoConfig();
if(cfg.ScanlineIntensity == 0) {
for(uint32_t i = 0; i < frameInfo.Height; i+=2) {
memcpy(GetOutputBuffer()+i*frameInfo.Width, _ntscBuffer + yOffset + xOffset + i*baseWidth, frameInfo.Width * sizeof(uint32_t));
memcpy(GetOutputBuffer()+(i+1)*frameInfo.Width, _ntscBuffer + yOffset + xOffset + i*baseWidth, frameInfo.Width * sizeof(uint32_t));
}
} else {
uint8_t intensity = (uint8_t)((1.0 - cfg.ScanlineIntensity) * 255);
for(uint32_t i = 0; i < frameInfo.Height; i++) {
if(i & 0x01) {
uint32_t *in = _ntscBuffer + yOffset + xOffset + (i - 1) * baseWidth;
uint32_t *out = GetOutputBuffer() + i * frameInfo.Width;
for(uint32_t j = 0; j < frameInfo.Width; j++) {
out[j] = ApplyScanlineEffect(in[j], intensity);
}
} else {
memcpy(GetOutputBuffer()+i*frameInfo.Width, _ntscBuffer + yOffset + xOffset + i*baseWidth, frameInfo.Width * sizeof(uint32_t));
}
}
}
}
NtscFilter::~NtscFilter()
{
delete[] _ntscBuffer;
}