UI: Added video options (scale, filters, aspect ratio)

This commit is contained in:
Sour 2019-03-10 11:12:50 -04:00
parent 337416f3a5
commit 60af2e2f64
45 changed files with 2597 additions and 913 deletions

View file

@ -76,6 +76,15 @@ uint32_t* BaseVideoFilter::GetOutputBuffer()
return _outputBuffer;
}
uint32_t BaseVideoFilter::ApplyScanlineEffect(uint32_t argb, uint8_t scanlineIntensity)
{
uint8_t r = ((argb & 0xFF0000) >> 16) * scanlineIntensity / 255;
uint8_t g = ((argb & 0xFF00) >> 8) * scanlineIntensity / 255;
uint8_t b = (argb & 0xFF) * scanlineIntensity / 255;
return 0xFF000000 | (r << 16) | (g << 8) | b;
}
void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream)
{
uint32_t* pngBuffer;

View file

@ -23,6 +23,7 @@ protected:
virtual void ApplyFilter(uint16_t *ppuOutputBuffer) = 0;
virtual void OnBeforeApplyFilter();
bool IsOddFrame();
uint32_t ApplyScanlineEffect(uint32_t argb, uint8_t scanlineIntensity);
public:
BaseVideoFilter(shared_ptr<Console> console);

View file

@ -20,6 +20,7 @@
#include "MessageManager.h"
#include "KeyManager.h"
#include "EventType.h"
#include "EmuSettings.h"
#include "../Utilities/Timer.h"
#include "../Utilities/VirtualFile.h"
#include "../Utilities/PlatformUtilities.h"
@ -31,6 +32,7 @@ Console::~Console()
void Console::Initialize()
{
_settings.reset(new EmuSettings());
_notificationManager.reset(new NotificationManager());
_videoDecoder.reset(new VideoDecoder(shared_from_this()));
_videoRenderer.reset(new VideoRenderer(shared_from_this()));
@ -176,6 +178,11 @@ shared_ptr<NotificationManager> Console::GetNotificationManager()
return _notificationManager;
}
shared_ptr<EmuSettings> Console::GetSettings()
{
return _settings;
}
shared_ptr<DebugHud> Console::GetDebugHud()
{
return _debugHud;

View file

@ -17,6 +17,7 @@ class SoundMixer;
class VideoRenderer;
class VideoDecoder;
class NotificationManager;
class EmuSettings;
enum class MemoryOperationType;
enum class SnesMemoryType;
enum class EventType;
@ -40,6 +41,7 @@ private:
shared_ptr<VideoRenderer> _videoRenderer;
shared_ptr<VideoDecoder> _videoDecoder;
shared_ptr<DebugHud> _debugHud;
shared_ptr<EmuSettings> _settings;
thread::id _emulationThreadId;
@ -62,6 +64,7 @@ public:
shared_ptr<VideoRenderer> GetVideoRenderer();
shared_ptr<VideoDecoder> GetVideoDecoder();
shared_ptr<NotificationManager> GetNotificationManager();
shared_ptr<EmuSettings> GetSettings();
shared_ptr<DebugHud> GetDebugHud();

View file

@ -61,9 +61,11 @@
<ClInclude Include="Cpu.h" />
<ClInclude Include="DebugBreakHelper.h" />
<ClInclude Include="DummyCpu.h" />
<ClInclude Include="EmuSettings.h" />
<ClInclude Include="EventManager.h" />
<ClInclude Include="EventType.h" />
<ClInclude Include="ExpressionEvaluator.h" />
<ClInclude Include="NtscFilter.h" />
<ClInclude Include="PpuTools.h" />
<ClInclude Include="RegisterHandlerB.h" />
<ClInclude Include="CpuTypes.h" />
@ -101,6 +103,7 @@
<ClInclude Include="RamHandler.h" />
<ClInclude Include="RegisterHandlerA.h" />
<ClInclude Include="RomHandler.h" />
<ClInclude Include="ScaleFilter.h" />
<ClInclude Include="SettingTypes.h" />
<ClInclude Include="SnesController.h" />
<ClInclude Include="SNES_SPC.h" />
@ -133,6 +136,7 @@
<ClCompile Include="Disassembler.cpp" />
<ClCompile Include="DisassemblyInfo.cpp" />
<ClCompile Include="DmaController.cpp" />
<ClCompile Include="EmuSettings.cpp" />
<ClCompile Include="EventManager.cpp" />
<ClCompile Include="ExpressionEvaluator.cpp" />
<ClCompile Include="InternalRegisters.cpp" />
@ -141,8 +145,10 @@
<ClCompile Include="MemoryManager.cpp" />
<ClCompile Include="MessageManager.cpp" />
<ClCompile Include="NotificationManager.cpp" />
<ClCompile Include="NtscFilter.cpp" />
<ClCompile Include="Ppu.cpp" />
<ClCompile Include="PpuTools.cpp" />
<ClCompile Include="ScaleFilter.cpp" />
<ClCompile Include="SNES_SPC.cpp" />
<ClCompile Include="SNES_SPC_misc.cpp" />
<ClCompile Include="SNES_SPC_state.cpp" />

View file

@ -209,6 +209,15 @@
<ClInclude Include="DebugBreakHelper.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="EmuSettings.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="ScaleFilter.h">
<Filter>Video</Filter>
</ClInclude>
<ClInclude Include="NtscFilter.h">
<Filter>Video</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
@ -326,6 +335,15 @@
<ClCompile Include="PpuTools.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="EmuSettings.cpp">
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="ScaleFilter.cpp">
<Filter>Video</Filter>
</ClCompile>
<ClCompile Include="NtscFilter.cpp">
<Filter>Video</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="SNES">

View file

@ -5,17 +5,16 @@
#include <algorithm>
#include "DebugHud.h"
#include "Console.h"
#include "EmuSettings.h"
#include "SettingTypes.h"
DefaultVideoFilter::DefaultVideoFilter(shared_ptr<Console> console) : BaseVideoFilter(console)
{
InitConversionMatrix(_pictureSettings.Hue, _pictureSettings.Saturation);
InitLookupTable();
}
void DefaultVideoFilter::InitConversionMatrix(double hueShift, double saturationShift)
{
_pictureSettings.Hue = hueShift;
_pictureSettings.Saturation = saturationShift;
double hue = hueShift * M_PI;
double sat = saturationShift + 1;
@ -34,60 +33,40 @@ void DefaultVideoFilter::InitConversionMatrix(double hueShift, double saturation
}
}
void DefaultVideoFilter::OnBeforeApplyFilter()
void DefaultVideoFilter::InitLookupTable()
{
/*PictureSettings currentSettings = _console->GetSettings()->GetPictureSettings();
if(_pictureSettings.Hue != currentSettings.Hue || _pictureSettings.Saturation != currentSettings.Saturation) {
InitConversionMatrix(currentSettings.Hue, currentSettings.Saturation);
VideoConfig config = _console->GetSettings()->GetVideoConfig();
InitConversionMatrix(config.Hue, config.Saturation);
double y, i, q;
for(int rgb555 = 0; rgb555 < 0x8000; rgb555++) {
double redChannel = To8Bit(rgb555 & 0x1F) / 255.0;
double greenChannel = To8Bit((rgb555 >> 5) & 0x1F) / 255.0;
double blueChannel = To8Bit(rgb555 >> 10) / 255.0;
//Apply brightness, contrast, hue & saturation
RgbToYiq(redChannel, greenChannel, blueChannel, y, i, q);
y *= config.Contrast * 0.5f + 1;
y += config.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[rgb555] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
_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));
}*/
_videoConfig = config;
}
void DefaultVideoFilter::DecodePpuBuffer(uint16_t *ppuOutputBuffer, uint32_t* outputBuffer, bool displayScanlines)
void DefaultVideoFilter::OnBeforeApplyFilter()
{
/*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++;
}
}
}*/
VideoConfig config = _console->GetSettings()->GetVideoConfig();
if(_videoConfig.Hue != config.Hue || _videoConfig.Saturation != config.Saturation || _videoConfig.Contrast != config.Contrast || _videoConfig.Brightness != config.Brightness) {
InitLookupTable();
}
}
uint8_t DefaultVideoFilter::To8Bit(uint8_t color)
@ -107,10 +86,28 @@ uint32_t DefaultVideoFilter::ToArgb(uint16_t rgb555)
void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
{
uint32_t *out = GetOutputBuffer();
uint32_t pixelCount = GetFrameInfo().Width * GetFrameInfo().Height;
for(uint32_t i = 0; i < pixelCount; i++) {
out[i] = ToArgb(ppuOutputBuffer[i]);
FrameInfo frameInfo = GetFrameInfo();
uint8_t scanlineIntensity = (uint8_t)((1.0 - _console->GetSettings()->GetVideoConfig().ScanlineIntensity) * 255);
if(scanlineIntensity < 255) {
for(uint32_t i = 0; i < frameInfo.Height; i++) {
if(i & 0x01) {
for(uint32_t j = 0; j < frameInfo.Width; j++) {
*out = ApplyScanlineEffect(_calculatedPalette[ppuOutputBuffer[i * 512 + j]], scanlineIntensity);
out++;
}
} else {
for(uint32_t j = 0; j < frameInfo.Width; j++) {
*out = _calculatedPalette[ppuOutputBuffer[i * 512 + j]];
out++;
}
}
}
} else {
uint32_t pixelCount = frameInfo.Width * frameInfo.Height;
for(uint32_t i = 0; i < pixelCount; i++) {
out[i] = _calculatedPalette[ppuOutputBuffer[i]];
}
}
}
@ -126,15 +123,4 @@ void DefaultVideoFilter::YiqToRgb(double y, double i, double q, double &r, doubl
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;
}

View file

@ -2,24 +2,24 @@
#include "stdafx.h"
#include "BaseVideoFilter.h"
#include "SettingTypes.h"
class DefaultVideoFilter : public BaseVideoFilter
{
private:
uint32_t _calculatedPalette[0x8000];
double _yiqToRgbMatrix[6];
uint32_t _calculatedPalette[512];
PictureSettings _pictureSettings;
VideoConfig _videoConfig;
bool _needToProcess = false;
void InitConversionMatrix(double hueShift, double saturationShift);
void InitLookupTable();
void RgbToYiq(double r, double g, double b, double &y, double &i, double &q);
void YiqToRgb(double y, double i, double q, double &r, double &g, double &b);
__forceinline static uint8_t To8Bit(uint8_t color);
protected:
void DecodePpuBuffer(uint16_t *ppuOutputBuffer, uint32_t* outputBuffer, bool displayScanlines);
uint32_t ApplyScanlineEffect(uint16_t ppuPixel, uint8_t scanlineIntensity);
void OnBeforeApplyFilter();
public:

32
Core/EmuSettings.cpp Normal file
View file

@ -0,0 +1,32 @@
#include "stdafx.h"
#include "EmuSettings.h"
void EmuSettings::SetVideoConfig(VideoConfig config)
{
_video = config;
}
VideoConfig EmuSettings::GetVideoConfig()
{
return _video;
}
double EmuSettings::GetAspectRatio()
{
switch(_video.AspectRatio) {
case VideoAspectRatio::NoStretching: return 0.0;
case VideoAspectRatio::Auto:
{
bool isPal = false;
return isPal ? (9440000.0 / 6384411.0) : (128.0 / 105.0);
}
case VideoAspectRatio::NTSC: return 128.0 / 105.0;
case VideoAspectRatio::PAL: return 9440000.0 / 6384411.0;
case VideoAspectRatio::Standard: return 4.0 / 3.0;
case VideoAspectRatio::Widescreen: return 16.0 / 9.0;
case VideoAspectRatio::Custom: return _video.CustomAspectRatio;
}
return 0.0;
}

14
Core/EmuSettings.h Normal file
View file

@ -0,0 +1,14 @@
#pragma once
#include "stdafx.h"
#include "SettingTypes.h"
class EmuSettings
{
private:
VideoConfig _video;
public:
void SetVideoConfig(VideoConfig config);
VideoConfig GetVideoConfig();
double GetAspectRatio();
};

72
Core/NtscFilter.cpp Normal file
View file

@ -0,0 +1,72 @@
#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()
{
FrameInfo frameInfo = BaseVideoFilter::GetFrameInfo();
frameInfo.Width = SNES_NTSC_OUT_WIDTH(frameInfo.Width / 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();
snes_ntsc_blit_hires(&_ntscData, ppuOutputBuffer, 512, IsOddFrame() ? 0 : 1, 512, frameInfo.Height, _ntscBuffer, SNES_NTSC_OUT_WIDTH(256)*4);
VideoConfig cfg = _console->GetSettings()->GetVideoConfig();
if(cfg.ScanlineIntensity == 0) {
memcpy(GetOutputBuffer(), _ntscBuffer, frameInfo.Width * frameInfo.Height * 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 + i * frameInfo.Width;
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+i*frameInfo.Width, frameInfo.Width * sizeof(uint32_t));
}
}
}
}
NtscFilter::~NtscFilter()
{
delete[] _ntscBuffer;
}

24
Core/NtscFilter.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include "stdafx.h"
#include "BaseVideoFilter.h"
#include "../Utilities/snes_ntsc.h"
class Console;
class NtscFilter : public BaseVideoFilter
{
private:
snes_ntsc_setup_t _ntscSetup;
snes_ntsc_t _ntscData;
uint32_t* _ntscBuffer;
protected:
void OnBeforeApplyFilter();
public:
NtscFilter(shared_ptr<Console> console);
virtual ~NtscFilter();
virtual void ApplyFilter(uint16_t *ppuOutputBuffer);
virtual FrameInfo GetFrameInfo();
};

141
Core/ScaleFilter.cpp Normal file
View file

@ -0,0 +1,141 @@
#include "stdafx.h"
#include "ScaleFilter.h"
#include "../Utilities/xBRZ/xbrz.h"
#include "../Utilities/HQX/hqx.h"
#include "../Utilities/Scale2x/scalebit.h"
#include "../Utilities/KreedSaiEagle/SaiEagle.h"
bool ScaleFilter::_hqxInitDone = false;
ScaleFilter::ScaleFilter(ScaleFilterType scaleFilterType, uint32_t scale)
{
_scaleFilterType = scaleFilterType;
_filterScale = scale;
if(!_hqxInitDone && _scaleFilterType == ScaleFilterType::HQX) {
hqxInit();
_hqxInitDone = true;
}
}
ScaleFilter::~ScaleFilter()
{
if(_outputBuffer) {
delete[] _outputBuffer;
}
}
uint32_t ScaleFilter::GetScale()
{
return _filterScale;
}
void ScaleFilter::ApplyPrescaleFilter(uint32_t *inputArgbBuffer)
{
uint32_t* outputBuffer = _outputBuffer;
for(uint32_t y = 0; y < _height; y++) {
for(uint32_t x = 0; x < _width; x++) {
for(uint32_t i = 0; i < _filterScale; i++) {
*(outputBuffer++) = *inputArgbBuffer;
}
inputArgbBuffer++;
}
for(uint32_t i = 1; i < _filterScale; i++) {
memcpy(outputBuffer, outputBuffer - _width*_filterScale, _width*_filterScale *4);
outputBuffer += _width*_filterScale;
}
}
}
void ScaleFilter::UpdateOutputBuffer(uint32_t width, uint32_t height)
{
if(!_outputBuffer || width != _width || height != _height) {
if(_outputBuffer) {
delete[] _outputBuffer;
}
_width = width;
_height = height;
_outputBuffer = new uint32_t[_width*_height*_filterScale*_filterScale];
}
}
uint32_t* ScaleFilter::ApplyFilter(uint32_t *inputArgbBuffer, uint32_t width, uint32_t height, double scanlineIntensity)
{
UpdateOutputBuffer(width, height);
if(_scaleFilterType == ScaleFilterType::xBRZ) {
xbrz::scale(_filterScale, inputArgbBuffer, _outputBuffer, width, height, xbrz::ColorFormat::ARGB);
} else if(_scaleFilterType == ScaleFilterType::HQX) {
hqx(_filterScale, inputArgbBuffer, _outputBuffer, width, height);
} else if(_scaleFilterType == ScaleFilterType::Scale2x) {
scale(_filterScale, _outputBuffer, width*sizeof(uint32_t)*_filterScale, inputArgbBuffer, width*sizeof(uint32_t), 4, width, height);
} else if(_scaleFilterType == ScaleFilterType::_2xSai) {
twoxsai_generic_xrgb8888(width, height, inputArgbBuffer, width, _outputBuffer, width * _filterScale);
} else if(_scaleFilterType == ScaleFilterType::Super2xSai) {
supertwoxsai_generic_xrgb8888(width, height, inputArgbBuffer, width, _outputBuffer, width * _filterScale);
} else if(_scaleFilterType == ScaleFilterType::SuperEagle) {
supereagle_generic_xrgb8888(width, height, inputArgbBuffer, width, _outputBuffer, width * _filterScale);
} else if(_scaleFilterType == ScaleFilterType::Prescale) {
ApplyPrescaleFilter(inputArgbBuffer);
}
scanlineIntensity = 1.0 - scanlineIntensity;
if(scanlineIntensity < 1.0) {
for(int y = 1, yMax = height * _filterScale; y < yMax; y += 2) {
for(int x = 0, xMax = width * _filterScale; x < xMax; x++) {
uint32_t &color = _outputBuffer[y*xMax + x];
uint8_t r = (color >> 16) & 0xFF, g = (color >> 8) & 0xFF, b = color & 0xFF;
r = (uint8_t)(r * scanlineIntensity);
g = (uint8_t)(g * scanlineIntensity);
b = (uint8_t)(b * scanlineIntensity);
color = 0xFF000000 | (r << 16) | (g << 8) | b;
}
}
}
return _outputBuffer;
}
shared_ptr<ScaleFilter> ScaleFilter::GetScaleFilter(VideoFilterType filter)
{
shared_ptr<ScaleFilter> scaleFilter;
switch(filter) {
case VideoFilterType::NTSC:
case VideoFilterType::None:
break;
case VideoFilterType::xBRZ2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 2)); break;
case VideoFilterType::xBRZ3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 3)); break;
case VideoFilterType::xBRZ4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 4)); break;
case VideoFilterType::xBRZ5x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 5)); break;
case VideoFilterType::xBRZ6x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 6)); break;
case VideoFilterType::HQ2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 2)); break;
case VideoFilterType::HQ3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 3)); break;
case VideoFilterType::HQ4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 4)); break;
case VideoFilterType::Scale2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 2)); break;
case VideoFilterType::Scale3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 3)); break;
case VideoFilterType::Scale4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 4)); break;
case VideoFilterType::_2xSai: scaleFilter.reset(new ScaleFilter(ScaleFilterType::_2xSai, 2)); break;
case VideoFilterType::Super2xSai: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Super2xSai, 2)); break;
case VideoFilterType::SuperEagle: scaleFilter.reset(new ScaleFilter(ScaleFilterType::SuperEagle, 2)); break;
case VideoFilterType::Prescale2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 2)); break;
case VideoFilterType::Prescale3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 3)); break;
case VideoFilterType::Prescale4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 4)); break;
case VideoFilterType::Prescale6x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 6)); break;
case VideoFilterType::Prescale8x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 8)); break;
case VideoFilterType::Prescale10x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 10)); break;
}
return scaleFilter;
}
FrameInfo ScaleFilter::GetFrameInfo(FrameInfo baseFrameInfo)
{
FrameInfo info = baseFrameInfo;
info.Height *= this->GetScale();
info.Width *= this->GetScale();
return info;
}

28
Core/ScaleFilter.h Normal file
View file

@ -0,0 +1,28 @@
#pragma once
#include "stdafx.h"
#include "DefaultVideoFilter.h"
class ScaleFilter
{
private:
static bool _hqxInitDone;
uint32_t _filterScale;
ScaleFilterType _scaleFilterType;
uint32_t *_outputBuffer = nullptr;
uint32_t _width = 0;
uint32_t _height = 0;
void ApplyPrescaleFilter(uint32_t *inputArgbBuffer);
void UpdateOutputBuffer(uint32_t width, uint32_t height);
public:
ScaleFilter(ScaleFilterType scaleFilterType, uint32_t scale);
~ScaleFilter();
uint32_t GetScale();
uint32_t* ApplyFilter(uint32_t *inputArgbBuffer, uint32_t width, uint32_t height, double scanlineIntensity);
FrameInfo GetFrameInfo(FrameInfo baseFrameInfo);
static shared_ptr<ScaleFilter> GetScaleFilter(VideoFilterType filter);
};

View file

@ -15,32 +15,27 @@ enum class ScaleFilterType
enum class VideoFilterType
{
None = 0,
NTSC = 1,
BisqwitNtscQuarterRes = 2,
BisqwitNtscHalfRes = 3,
BisqwitNtsc = 4,
xBRZ2x = 5,
xBRZ3x = 6,
xBRZ4x = 7,
xBRZ5x = 8,
xBRZ6x = 9,
HQ2x = 10,
HQ3x = 11,
HQ4x = 12,
Scale2x = 13,
Scale3x = 14,
Scale4x = 15,
_2xSai = 16,
Super2xSai = 17,
SuperEagle = 18,
Prescale2x = 19,
Prescale3x = 20,
Prescale4x = 21,
Prescale6x = 22,
Prescale8x = 23,
Prescale10x = 24,
Raw = 25,
HdPack = 999
NTSC,
xBRZ2x,
xBRZ3x,
xBRZ4x,
xBRZ5x,
xBRZ6x,
HQ2x,
HQ3x,
HQ4x,
Scale2x,
Scale3x,
Scale4x,
_2xSai,
Super2xSai,
SuperEagle,
Prescale2x,
Prescale3x,
Prescale4x,
Prescale6x,
Prescale8x,
Prescale10x
};
enum class VideoResizeFilter
@ -60,6 +55,35 @@ enum class VideoAspectRatio
Custom = 6
};
struct VideoConfig
{
double VideoScale = 2;
double CustomAspectRatio = 1.0;
VideoFilterType VideoFilter = VideoFilterType::NTSC;
VideoAspectRatio AspectRatio = VideoAspectRatio::NoStretching;
bool UseBilinearInterpolation = false;
bool VerticalSync = false;
bool IntegerFpsMode = false;
double Brightness = 0;
double Contrast = 0;
double Hue = 0;
double Saturation = 0;
double ScanlineIntensity = 0;
double NtscArtifacts = 0;
double NtscBleed = 0;
double NtscFringing = 0;
double NtscGamma = 0;
double NtscResolution = 0;
double NtscSharpness = 0;
bool NtscMergeFields = false;
bool FullscreenForceIntegerScale = false;
bool UseExclusiveFullscreen = false;
int32_t ExclusiveFullscreenRefreshRate = 60;
};
struct OverscanDimensions
{
uint32_t Left = 0;
@ -68,32 +92,6 @@ struct OverscanDimensions
uint32_t Bottom = 0;
};
struct PictureSettings
{
double Brightness = 0;
double Contrast = 0;
double Saturation = 0;
double Hue = 0;
double ScanlineIntensity = 0;
};
struct NtscFilterSettings
{
double Sharpness = 0;
double Gamma = 0;
double Resolution = 0;
double Artifacts = 0;
double Fringing = 0;
double Bleed = 0;
bool MergeFields = false;
bool VerticalBlend = false;
bool KeepVerticalResolution = false;
double YFilterLength = 0;
double IFilterLength = 0;
double QFilterLength = 0;
};
struct FrameInfo
{
uint32_t Width;

View file

@ -3,7 +3,12 @@
#include "VideoDecoder.h"
#include "VideoRenderer.h"
#include "DefaultVideoFilter.h"
#include "NotificationManager.h"
#include "Console.h"
#include "EmuSettings.h"
#include "SettingTypes.h"
#include "NtscFilter.h"
#include "ScaleFilter.h"
#include "Ppu.h"
#include "DebugHud.h"
@ -25,64 +30,40 @@ FrameInfo VideoDecoder::GetFrameInfo()
return _lastFrameInfo;
}
void VideoDecoder::GetScreenSize(ScreenSize &size, bool ignoreScale)
ScreenSize VideoDecoder::GetScreenSize(bool ignoreScale)
{
ScreenSize size = {};
if(_videoFilter) {
/*OverscanDimensions overscan = ignoreScale ? _videoFilter->GetOverscan() : _console->GetSettings()->GetOverscanDimensions();
FrameInfo frameInfo{ overscan.GetScreenWidth(), overscan.GetScreenHeight(), PPU::ScreenWidth, PPU::ScreenHeight, 4 };
double aspectRatio = _console->GetSettings()->GetAspectRatio(_console);
double scale = (ignoreScale ? 1 : _console->GetSettings()->GetVideoScale());
size.Width = (int32_t)(frameInfo.Width * scale);
size.Height = (int32_t)(frameInfo.Height * scale);
VideoConfig config = _console->GetSettings()->GetVideoConfig();
double aspectRatio = _console->GetSettings()->GetAspectRatio();
double scale = (ignoreScale ? 1 : config.VideoScale);
size.Width = (int32_t)(_baseFrameInfo.Width * scale / 2);
size.Height = (int32_t)(_baseFrameInfo.Height * scale / 2);
size.Scale = scale;
if(aspectRatio != 0.0) {
size.Width = (uint32_t)(frameInfo.OriginalHeight * scale * aspectRatio * ((double)frameInfo.Width / frameInfo.OriginalWidth));
size.Width = (uint32_t)(_baseFrameInfo.Height * scale * aspectRatio / 2);
}
if(_console->GetSettings()->GetScreenRotation() % 180) {
/*if(_console->GetSettings()->GetScreenRotation() % 180) {
std::swap(size.Width, size.Height);
}
size.Scale = scale;*/
size.Scale = 2;
if(ignoreScale) {
size.Width = _baseFrameInfo.Width;
size.Height = _baseFrameInfo.Height;
} else {
if(_baseFrameInfo.Width == 256) {
size.Width = (int32_t)(_baseFrameInfo.Width * size.Scale);
size.Height = (int32_t)(_baseFrameInfo.Height * size.Scale);
} else {
size.Width = (int32_t)_baseFrameInfo.Width;
size.Height = (int32_t)_baseFrameInfo.Height;
if(_baseFrameInfo.Height <= 240) {
size.Height *= 2;
}
}
}
}*/
}
return size;
}
void VideoDecoder::UpdateVideoFilter()
{
VideoFilterType newFilter = VideoFilterType::None;
VideoFilterType newFilter = _console->GetSettings()->GetVideoConfig().VideoFilter;
if(_videoFilterType != newFilter || _videoFilter == nullptr) {
_videoFilterType = newFilter;
_videoFilter.reset(new DefaultVideoFilter(_console));
//_scaleFilter.reset();
_scaleFilter.reset();
switch(_videoFilterType) {
case VideoFilterType::None: break;
//TODO
/*
case VideoFilterType::NTSC: _videoFilter.reset(new NtscFilter(_console)); break;
case VideoFilterType::BisqwitNtsc: _videoFilter.reset(new BisqwitNtscFilter(_console, 1)); break;
case VideoFilterType::BisqwitNtscHalfRes: _videoFilter.reset(new BisqwitNtscFilter(_console, 2)); break;
case VideoFilterType::BisqwitNtscQuarterRes: _videoFilter.reset(new BisqwitNtscFilter(_console, 4)); break;
case VideoFilterType::Raw: _videoFilter.reset(new RawVideoFilter(_console)); break;
default: _scaleFilter = ScaleFilter::GetScaleFilter(_videoFilterType); break;*/
default: _scaleFilter = ScaleFilter::GetScaleFilter(_videoFilterType); break;
}
}
@ -112,23 +93,24 @@ void VideoDecoder::DecodeFrame(bool synchronous)
if(_rotateFilter) {
outputBuffer = _rotateFilter->ApplyFilter(outputBuffer, frameInfo.Width, frameInfo.Height);
frameInfo = _rotateFilter->GetFrameInfo(frameInfo);
}
}*/
if(_scaleFilter) {
outputBuffer = _scaleFilter->ApplyFilter(outputBuffer, frameInfo.Width, frameInfo.Height, _console->GetSettings()->GetPictureSettings().ScanlineIntensity);
outputBuffer = _scaleFilter->ApplyFilter(outputBuffer, frameInfo.Width, frameInfo.Height, _console->GetSettings()->GetVideoConfig().ScanlineIntensity);
frameInfo = _scaleFilter->GetFrameInfo(frameInfo);
}
/*
if(_hud) {
_hud->DrawHud(_console, outputBuffer, frameInfo, _videoFilter->GetOverscan());
}*/
ScreenSize screenSize;
GetScreenSize(screenSize, true);
/*if(_previousScale != _console->GetSettings()->GetVideoScale() || screenSize.Height != _previousScreenSize.Height || screenSize.Width != _previousScreenSize.Width) {
ScreenSize screenSize = GetScreenSize(true);
VideoConfig config = _console->GetSettings()->GetVideoConfig();
if(_previousScale != config.VideoScale || screenSize.Height != _previousScreenSize.Height || screenSize.Width != _previousScreenSize.Width) {
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ResolutionChanged);
}*/
_previousScale = 1; // _console->GetSettings()->GetVideoScale();
}
_previousScale = config.VideoScale;
_previousScreenSize = screenSize;
_lastFrameInfo = frameInfo;

View file

@ -5,7 +5,7 @@
#include "SettingTypes.h"
class BaseVideoFilter;
//class ScaleFilter;
class ScaleFilter;
//class RotateFilter;
class IRenderingDevice;
//class VideoHud;
@ -35,7 +35,7 @@ private:
VideoFilterType _videoFilterType = VideoFilterType::None;
unique_ptr<BaseVideoFilter> _videoFilter;
//shared_ptr<ScaleFilter> _scaleFilter;
shared_ptr<ScaleFilter> _scaleFilter;
//shared_ptr<RotateFilter> _rotateFilter;
void UpdateVideoFilter();
@ -53,7 +53,7 @@ public:
uint32_t GetFrameCount();
FrameInfo GetFrameInfo();
void GetScreenSize(ScreenSize &size, bool ignoreScale);
ScreenSize GetScreenSize(bool ignoreScale);
void UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber);
void UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber);

View file

@ -0,0 +1,13 @@
#include "stdafx.h"
#include "../Core/Console.h"
#include "../Core/EmuSettings.h"
#include "../Core/SettingTypes.h"
extern shared_ptr<Console> _console;
extern "C" {
DllExport void __stdcall SetVideoConfig(VideoConfig config)
{
_console->GetSettings()->SetVideoConfig(config);
}
}

View file

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "../Core/Console.h"
#include "../Core/VideoDecoder.h"
#include "../Core/MessageManager.h"
#include "../Core/INotificationListener.h"
#include "../Core/KeyManager.h"
@ -28,182 +29,185 @@ string _logString;
shared_ptr<Console> _console;
InteropNotificationListeners _listeners;
namespace InteropEmu {
extern "C" {
DllExport bool __stdcall TestDll()
{
return true;
}
extern "C" {
DllExport bool __stdcall TestDll()
{
return true;
}
DllExport uint32_t __stdcall GetMesenVersion() { return 0x00000100; }
DllExport uint32_t __stdcall GetMesenVersion() { return 0x00000100; }
DllExport void __stdcall InitDll()
{
_console.reset(new Console());
_console->Initialize();
}
DllExport void __stdcall InitDll()
{
_console.reset(new Console());
_console->Initialize();
}
DllExport void __stdcall InitializeEmu(const char* homeFolder, void *windowHandle, void *viewerHandle, bool noAudio, bool noVideo, bool noInput)
{
FolderUtilities::SetHomeFolder(homeFolder);
//_shortcutKeyHandler.reset(new ShortcutKeyHandler(_console));
DllExport void __stdcall InitializeEmu(const char* homeFolder, void *windowHandle, void *viewerHandle, bool noAudio, bool noVideo, bool noInput)
{
FolderUtilities::SetHomeFolder(homeFolder);
//_shortcutKeyHandler.reset(new ShortcutKeyHandler(_console));
if(windowHandle != nullptr && viewerHandle != nullptr) {
_windowHandle = windowHandle;
_viewerHandle = viewerHandle;
if(windowHandle != nullptr && viewerHandle != nullptr) {
_windowHandle = windowHandle;
_viewerHandle = viewerHandle;
if(!noVideo) {
#ifdef _WIN32
_renderer.reset(new Renderer(_console, (HWND)_viewerHandle, true));
#else
_renderer.reset(new SdlRenderer(_console, _viewerHandle, true));
#endif
}
if(!noAudio) {
#ifdef _WIN32
_soundManager.reset(new SoundManager(_console, (HWND)_windowHandle));
#else
_soundManager.reset(new SdlSoundManager(_console));
#endif
}
if(!noInput) {
#ifdef _WIN32
_keyManager.reset(new WindowsKeyManager(_console, (HWND)_windowHandle));
#else
_keyManager.reset(new LinuxKeyManager(_console));
#endif
KeyManager::RegisterKeyManager(_keyManager.get());
}
}
}
DllExport void __stdcall SetFullscreenMode(bool fullscreen, void *windowHandle, uint32_t monitorWidth, uint32_t monitorHeight)
{
if(_renderer) {
_renderer->SetFullscreenMode(fullscreen, windowHandle, monitorWidth, monitorHeight);
}
}
DllExport void __stdcall LoadRom(char* filename, char* patchFile) { _console->LoadRom((VirtualFile)filename, (VirtualFile)patchFile); }
//DllExport void __stdcall AddKnownGameFolder(char* folder) { FolderUtilities::AddKnownGameFolder(folder); }
//DllExport void __stdcall SetFolderOverrides(char* saveFolder, char* saveStateFolder, char* screenshotFolder) { FolderUtilities::SetFolderOverrides(saveFolder, saveStateFolder, screenshotFolder); }
DllExport const char* __stdcall GetArchiveRomList(char* filename) {
std::ostringstream out;
shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(filename);
if(reader) {
for(string romName : reader->GetFileList({ ".sfc" })) {
out << romName << "[!|!]";
}
}
_returnString = out.str();
return _returnString.c_str();
}
DllExport void __stdcall SetMousePosition(double x, double y) { KeyManager::SetMousePosition(x, y); }
DllExport void __stdcall SetMouseMovement(int16_t x, int16_t y) { KeyManager::SetMouseMovement(x, y); }
DllExport void __stdcall UpdateInputDevices() { if(_keyManager) { _keyManager->UpdateDevices(); } }
DllExport void __stdcall GetPressedKeys(uint32_t *keyBuffer) {
vector<uint32_t> pressedKeys = KeyManager::GetPressedKeys();
for(size_t i = 0; i < pressedKeys.size() && i < 3; i++) {
keyBuffer[i] = pressedKeys[i];
}
}
DllExport void __stdcall DisableAllKeys(bool disabled) {
if(_keyManager) {
_keyManager->SetDisabled(disabled);
}
}
DllExport void __stdcall SetKeyState(int32_t scanCode, bool state) {
if(_keyManager) {
_keyManager->SetKeyState(scanCode, state);
//_shortcutKeyHandler->ProcessKeys();
if(!noVideo) {
#ifdef _WIN32
_renderer.reset(new Renderer(_console, (HWND)_viewerHandle, true));
#else
_renderer.reset(new SdlRenderer(_console, _viewerHandle, true));
#endif
}
}
DllExport void __stdcall ResetKeyState() { if(_keyManager) { _keyManager->ResetKeyState(); } }
DllExport const char* __stdcall GetKeyName(uint32_t keyCode)
{
_returnString = KeyManager::GetKeyName(keyCode);
return _returnString.c_str();
}
DllExport uint32_t __stdcall GetKeyCode(char* keyName) {
if(keyName) {
return KeyManager::GetKeyCode(keyName);
} else {
return 0;
if(!noAudio) {
#ifdef _WIN32
_soundManager.reset(new SoundManager(_console, (HWND)_windowHandle));
#else
_soundManager.reset(new SdlSoundManager(_console));
#endif
}
}
DllExport void __stdcall Run()
{
if(_console) {
_console->Run();
}
}
DllExport void __stdcall Stop()
{
if(_console) {
_console->Stop();
}
}
DllExport void __stdcall Release()
{
_console->Stop();
_renderer.reset();
_soundManager.reset();
_keyManager.reset();
_console->Release();
_console.reset();
//_shortcutKeyHandler.reset();
}
DllExport INotificationListener* __stdcall RegisterNotificationCallback(NotificationListenerCallback callback)
{
return _listeners.RegisterNotificationCallback(callback, _console);
}
DllExport void __stdcall UnregisterNotificationCallback(INotificationListener *listener)
{
_listeners.UnregisterNotificationCallback(listener);
}
DllExport void __stdcall DisplayMessage(char* title, char* message, char* param1) { MessageManager::DisplayMessage(title, message, param1 ? param1 : ""); }
DllExport const char* __stdcall GetLog()
{
_logString = MessageManager::GetLog();
return _logString.c_str();
}
DllExport void __stdcall WriteLogEntry(char* message) { MessageManager::Log(message); }
DllExport void __stdcall PgoRunTest(vector<string> testRoms, bool enableDebugger)
{
FolderUtilities::SetHomeFolder("../PGOMesenHome");
for(size_t i = 0; i < testRoms.size(); i++) {
std::cout << "Running: " << testRoms[i] << std::endl;
_console.reset(new Console());
_console->Initialize();
_console->LoadRom((VirtualFile)testRoms[i], VirtualFile());
thread testThread([=] {
_console->Run();
});
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(5000));
_console->Stop();
testThread.join();
_console->Release();
if(!noInput) {
#ifdef _WIN32
_keyManager.reset(new WindowsKeyManager(_console, (HWND)_windowHandle));
#else
_keyManager.reset(new LinuxKeyManager(_console));
#endif
KeyManager::RegisterKeyManager(_keyManager.get());
}
}
}
DllExport void __stdcall SetFullscreenMode(bool fullscreen, void *windowHandle, uint32_t monitorWidth, uint32_t monitorHeight)
{
if(_renderer) {
_renderer->SetFullscreenMode(fullscreen, windowHandle, monitorWidth, monitorHeight);
}
}
DllExport void __stdcall LoadRom(char* filename, char* patchFile) { _console->LoadRom((VirtualFile)filename, (VirtualFile)patchFile); }
//DllExport void __stdcall AddKnownGameFolder(char* folder) { FolderUtilities::AddKnownGameFolder(folder); }
//DllExport void __stdcall SetFolderOverrides(char* saveFolder, char* saveStateFolder, char* screenshotFolder) { FolderUtilities::SetFolderOverrides(saveFolder, saveStateFolder, screenshotFolder); }
DllExport const char* __stdcall GetArchiveRomList(char* filename) {
std::ostringstream out;
shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(filename);
if(reader) {
for(string romName : reader->GetFileList({ ".sfc" })) {
out << romName << "[!|!]";
}
}
_returnString = out.str();
return _returnString.c_str();
}
DllExport void __stdcall SetMousePosition(double x, double y) { KeyManager::SetMousePosition(x, y); }
DllExport void __stdcall SetMouseMovement(int16_t x, int16_t y) { KeyManager::SetMouseMovement(x, y); }
DllExport void __stdcall UpdateInputDevices() { if(_keyManager) { _keyManager->UpdateDevices(); } }
DllExport void __stdcall GetPressedKeys(uint32_t *keyBuffer) {
vector<uint32_t> pressedKeys = KeyManager::GetPressedKeys();
for(size_t i = 0; i < pressedKeys.size() && i < 3; i++) {
keyBuffer[i] = pressedKeys[i];
}
}
DllExport void __stdcall DisableAllKeys(bool disabled) {
if(_keyManager) {
_keyManager->SetDisabled(disabled);
}
}
DllExport void __stdcall SetKeyState(int32_t scanCode, bool state) {
if(_keyManager) {
_keyManager->SetKeyState(scanCode, state);
//_shortcutKeyHandler->ProcessKeys();
}
}
DllExport void __stdcall ResetKeyState() { if(_keyManager) { _keyManager->ResetKeyState(); } }
DllExport const char* __stdcall GetKeyName(uint32_t keyCode)
{
_returnString = KeyManager::GetKeyName(keyCode);
return _returnString.c_str();
}
DllExport uint32_t __stdcall GetKeyCode(char* keyName) {
if(keyName) {
return KeyManager::GetKeyCode(keyName);
} else {
return 0;
}
}
DllExport void __stdcall Run()
{
if(_console) {
_console->Run();
}
}
DllExport void __stdcall Stop()
{
if(_console) {
_console->Stop();
}
}
DllExport void __stdcall Release()
{
_console->Stop();
_renderer.reset();
_soundManager.reset();
_keyManager.reset();
_console->Release();
_console.reset();
//_shortcutKeyHandler.reset();
}
DllExport INotificationListener* __stdcall RegisterNotificationCallback(NotificationListenerCallback callback)
{
return _listeners.RegisterNotificationCallback(callback, _console);
}
DllExport void __stdcall UnregisterNotificationCallback(INotificationListener *listener)
{
_listeners.UnregisterNotificationCallback(listener);
}
DllExport void __stdcall DisplayMessage(char* title, char* message, char* param1) { MessageManager::DisplayMessage(title, message, param1 ? param1 : ""); }
DllExport const char* __stdcall GetLog()
{
_logString = MessageManager::GetLog();
return _logString.c_str();
}
DllExport ScreenSize __stdcall GetScreenSize(bool ignoreScale)
{
return _console->GetVideoDecoder()->GetScreenSize(ignoreScale);
}
DllExport void __stdcall WriteLogEntry(char* message) { MessageManager::Log(message); }
DllExport void __stdcall PgoRunTest(vector<string> testRoms, bool enableDebugger)
{
FolderUtilities::SetHomeFolder("../PGOMesenHome");
for(size_t i = 0; i < testRoms.size(); i++) {
std::cout << "Running: " << testRoms[i] << std::endl;
_console.reset(new Console());
_console->Initialize();
_console->LoadRom((VirtualFile)testRoms[i], VirtualFile());
thread testThread([=] {
_console->Run();
});
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(5000));
_console->Stop();
testThread.join();
_console->Release();
}
}
}

View file

@ -453,6 +453,7 @@
<ClInclude Include="stdafx.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ConfigApiWrapper.cpp" />
<ClCompile Include="EmuApiWrapper.cpp" />
<ClCompile Include="DebugApiWrapper.cpp" />
<ClCompile Include="stdafx.cpp">

View file

@ -31,5 +31,8 @@
<ClCompile Include="EmuApiWrapper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ConfigApiWrapper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

18
UI/Config/BaseConfig.cs Normal file
View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Config
{
[StructLayout(LayoutKind.Sequential)]
public class BaseConfig<T>
{
public T Clone()
{
return (T)this.MemberwiseClone();
}
}
}

View file

@ -17,6 +17,7 @@ namespace Mesen.GUI.Config
public string Version = "0.1.0";
public List<RecentItem> RecentFiles;
public VideoConfig Video;
public DebugInfo Debug;
public Point? WindowLocation;
public Size? WindowSize;
@ -25,6 +26,7 @@ namespace Mesen.GUI.Config
{
RecentFiles = new List<RecentItem>();
Debug = new DebugInfo();
Video = new VideoConfig();
}
~Configuration()
@ -50,6 +52,7 @@ namespace Mesen.GUI.Config
public void ApplyConfig()
{
Video.ApplyConfig();
}
public void InitializeDefaults()

82
UI/Config/VideoConfig.cs Normal file
View file

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Config
{
[StructLayout(LayoutKind.Sequential)]
public class VideoConfig : BaseConfig<VideoConfig>
{
[MinMax(0.1, 10.0)] public double VideoScale = 2;
[MinMax(0.1, 5.0)] public double CustomAspectRatio = 1.0;
public VideoFilterType VideoFilter = VideoFilterType.None;
public VideoAspectRatio AspectRatio = VideoAspectRatio.NoStretching;
[MarshalAs(UnmanagedType.I1)] public bool UseBilinearInterpolation = false;
[MarshalAs(UnmanagedType.I1)] public bool VerticalSync = false;
[MarshalAs(UnmanagedType.I1)] public bool IntegerFpsMode = false;
[MinMax(-1, 1.0)] public double Brightness = 0;
[MinMax(-1, 1.0)] public double Contrast = 0;
[MinMax(-1, 1.0)] public double Hue = 0;
[MinMax(-1, 1.0)] public double Saturation = 0;
[MinMax(0, 1.0)] public double ScanlineIntensity = 0;
[MinMax(-1, 1.0)] public double NtscArtifacts = 0;
[MinMax(-1, 1.0)] public double NtscBleed = 0;
[MinMax(-1, 1.0)] public double NtscFringing = 0;
[MinMax(-1, 1.0)] public double NtscGamma = 0;
[MinMax(-1, 1.0)] public double NtscResolution = 0;
[MinMax(-1, 1.0)] public double NtscSharpness = 0;
[MarshalAs(UnmanagedType.I1)] public bool NtscMergeFields = false;
[MarshalAs(UnmanagedType.I1)] public bool FullscreenForceIntegerScale = false;
[MarshalAs(UnmanagedType.I1)] public bool UseExclusiveFullscreen = false;
public Int32 ExclusiveFullscreenRefreshRate = 60;
public void ApplyConfig()
{
ConfigApi.SetVideoConfig(this);
}
}
public enum VideoFilterType
{
None = 0,
NTSC,
xBRZ2x,
xBRZ3x,
xBRZ4x,
xBRZ5x,
xBRZ6x,
HQ2x,
HQ3x,
HQ4x,
Scale2x,
Scale3x,
Scale4x,
_2xSai,
Super2xSai,
SuperEagle,
Prescale2x,
Prescale3x,
Prescale4x,
Prescale6x,
Prescale8x,
Prescale10x
}
public enum VideoAspectRatio
{
NoStretching = 0,
Auto = 1,
NTSC = 2,
PAL = 3,
Standard = 4,
Widescreen = 5,
Custom = 6
}
}

View file

@ -74,11 +74,7 @@ namespace Mesen.GUI.Forms
if(this.DialogResult == System.Windows.Forms.DialogResult.OK) {
UpdateObject();
if(ApplyChangesOnOK) {
ConfigManager.ApplyChanges();
}
} else {
if(ApplyChangesOnOK) {
ConfigManager.RejectChanges();
OnApply();
}
}
base.OnFormClosed(e);
@ -89,6 +85,9 @@ namespace Mesen.GUI.Forms
get { return true; }
}
protected virtual void OnApply()
{
}
protected virtual void UpdateConfig()
{

900
UI/Forms/Config/frmVideoConfig.Designer.cs generated Normal file
View file

@ -0,0 +1,900 @@
namespace Mesen.GUI.Forms.Config
{
partial class frmVideoConfig
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.tabMain = new System.Windows.Forms.TabControl();
this.tpgGeneral = new System.Windows.Forms.TabPage();
this.tlpMain = new System.Windows.Forms.TableLayoutPanel();
this.chkUseExclusiveFullscreen = new System.Windows.Forms.CheckBox();
this.lblVideoScale = new System.Windows.Forms.Label();
this.chkVerticalSync = new System.Windows.Forms.CheckBox();
this.lblDisplayRatio = new System.Windows.Forms.Label();
this.nudScale = new Mesen.GUI.Controls.MesenNumericUpDown();
this.flowLayoutPanel6 = new System.Windows.Forms.FlowLayoutPanel();
this.cboAspectRatio = new System.Windows.Forms.ComboBox();
this.lblCustomRatio = new System.Windows.Forms.Label();
this.nudCustomRatio = new Mesen.GUI.Controls.MesenNumericUpDown();
this.chkFullscreenForceIntegerScale = new System.Windows.Forms.CheckBox();
this.chkShowFps = new System.Windows.Forms.CheckBox();
this.chkIntegerFpsMode = new System.Windows.Forms.CheckBox();
this.flpRefreshRate = new System.Windows.Forms.FlowLayoutPanel();
this.lblRequestedRefreshRate = new System.Windows.Forms.Label();
this.cboRefreshRate = new System.Windows.Forms.ComboBox();
this.tpgPicture = new System.Windows.Forms.TabPage();
this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel7 = new System.Windows.Forms.TableLayoutPanel();
this.btnSelectPreset = new System.Windows.Forms.Button();
this.btnResetPictureSettings = new System.Windows.Forms.Button();
this.grpNtscFilter = new System.Windows.Forms.GroupBox();
this.tlpNtscFilter = new System.Windows.Forms.TableLayoutPanel();
this.chkMergeFields = new System.Windows.Forms.CheckBox();
this.trkArtifacts = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkBleed = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkFringing = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkGamma = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkResolution = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkSharpness = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.grpCommon = new System.Windows.Forms.GroupBox();
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
this.chkBilinearInterpolation = new System.Windows.Forms.CheckBox();
this.trkBrightness = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkContrast = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkHue = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkSaturation = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.grpScanlines = new System.Windows.Forms.GroupBox();
this.trkScanlines = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.tableLayoutPanel8 = new System.Windows.Forms.TableLayoutPanel();
this.cboFilter = new System.Windows.Forms.ComboBox();
this.lblVideoFilter = new System.Windows.Forms.Label();
this.ctxPicturePresets = new System.Windows.Forms.ContextMenuStrip(this.components);
this.mnuPresetComposite = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPresetSVideo = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPresetRgb = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPresetMonochrome = new System.Windows.Forms.ToolStripMenuItem();
this.tabMain.SuspendLayout();
this.tpgGeneral.SuspendLayout();
this.tlpMain.SuspendLayout();
this.flowLayoutPanel6.SuspendLayout();
this.flpRefreshRate.SuspendLayout();
this.tpgPicture.SuspendLayout();
this.tableLayoutPanel5.SuspendLayout();
this.tableLayoutPanel7.SuspendLayout();
this.grpNtscFilter.SuspendLayout();
this.tlpNtscFilter.SuspendLayout();
this.grpCommon.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout();
this.grpScanlines.SuspendLayout();
this.tableLayoutPanel8.SuspendLayout();
this.ctxPicturePresets.SuspendLayout();
this.SuspendLayout();
//
// baseConfigPanel
//
this.baseConfigPanel.Location = new System.Drawing.Point(0, 408);
this.baseConfigPanel.Size = new System.Drawing.Size(574, 29);
//
// tabMain
//
this.tabMain.Controls.Add(this.tpgGeneral);
this.tabMain.Controls.Add(this.tpgPicture);
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabMain.Location = new System.Drawing.Point(0, 0);
this.tabMain.Name = "tabMain";
this.tabMain.SelectedIndex = 0;
this.tabMain.Size = new System.Drawing.Size(574, 408);
this.tabMain.TabIndex = 2;
//
// tpgGeneral
//
this.tpgGeneral.Controls.Add(this.tlpMain);
this.tpgGeneral.Location = new System.Drawing.Point(4, 22);
this.tpgGeneral.Name = "tpgGeneral";
this.tpgGeneral.Padding = new System.Windows.Forms.Padding(3);
this.tpgGeneral.Size = new System.Drawing.Size(566, 382);
this.tpgGeneral.TabIndex = 5;
this.tpgGeneral.Text = "General";
this.tpgGeneral.UseVisualStyleBackColor = true;
//
// tlpMain
//
this.tlpMain.ColumnCount = 2;
this.tlpMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tlpMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpMain.Controls.Add(this.chkUseExclusiveFullscreen, 0, 4);
this.tlpMain.Controls.Add(this.lblVideoScale, 0, 0);
this.tlpMain.Controls.Add(this.chkVerticalSync, 0, 3);
this.tlpMain.Controls.Add(this.lblDisplayRatio, 0, 1);
this.tlpMain.Controls.Add(this.nudScale, 1, 0);
this.tlpMain.Controls.Add(this.flowLayoutPanel6, 1, 1);
this.tlpMain.Controls.Add(this.chkFullscreenForceIntegerScale, 0, 6);
this.tlpMain.Controls.Add(this.chkShowFps, 0, 7);
this.tlpMain.Controls.Add(this.chkIntegerFpsMode, 0, 2);
this.tlpMain.Controls.Add(this.flpRefreshRate, 0, 5);
this.tlpMain.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpMain.Location = new System.Drawing.Point(3, 3);
this.tlpMain.Margin = new System.Windows.Forms.Padding(0);
this.tlpMain.Name = "tlpMain";
this.tlpMain.RowCount = 9;
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlpMain.Size = new System.Drawing.Size(560, 376);
this.tlpMain.TabIndex = 1;
//
// chkUseExclusiveFullscreen
//
this.chkUseExclusiveFullscreen.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkUseExclusiveFullscreen.AutoSize = true;
this.tlpMain.SetColumnSpan(this.chkUseExclusiveFullscreen, 2);
this.chkUseExclusiveFullscreen.Location = new System.Drawing.Point(3, 96);
this.chkUseExclusiveFullscreen.Name = "chkUseExclusiveFullscreen";
this.chkUseExclusiveFullscreen.Size = new System.Drawing.Size(169, 17);
this.chkUseExclusiveFullscreen.TabIndex = 24;
this.chkUseExclusiveFullscreen.Text = "Use exclusive fullscreen mode";
this.chkUseExclusiveFullscreen.UseVisualStyleBackColor = true;
this.chkUseExclusiveFullscreen.Visible = false;
//
// lblVideoScale
//
this.lblVideoScale.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblVideoScale.AutoSize = true;
this.lblVideoScale.Location = new System.Drawing.Point(3, 4);
this.lblVideoScale.Name = "lblVideoScale";
this.lblVideoScale.Size = new System.Drawing.Size(37, 13);
this.lblVideoScale.TabIndex = 11;
this.lblVideoScale.Text = "Scale:";
//
// chkVerticalSync
//
this.chkVerticalSync.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkVerticalSync.AutoSize = true;
this.tlpMain.SetColumnSpan(this.chkVerticalSync, 2);
this.chkVerticalSync.Location = new System.Drawing.Point(3, 73);
this.chkVerticalSync.Name = "chkVerticalSync";
this.chkVerticalSync.Size = new System.Drawing.Size(121, 17);
this.chkVerticalSync.TabIndex = 15;
this.chkVerticalSync.Text = "Enable vertical sync";
this.chkVerticalSync.UseVisualStyleBackColor = true;
//
// lblDisplayRatio
//
this.lblDisplayRatio.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblDisplayRatio.AutoSize = true;
this.lblDisplayRatio.Location = new System.Drawing.Point(3, 27);
this.lblDisplayRatio.Name = "lblDisplayRatio";
this.lblDisplayRatio.Size = new System.Drawing.Size(71, 13);
this.lblDisplayRatio.TabIndex = 17;
this.lblDisplayRatio.Text = "Aspect Ratio:";
//
// nudScale
//
this.nudScale.DecimalPlaces = 2;
this.nudScale.Increment = new decimal(new int[] {
1,
0,
0,
0});
this.nudScale.Location = new System.Drawing.Point(77, 0);
this.nudScale.Margin = new System.Windows.Forms.Padding(0);
this.nudScale.Maximum = new decimal(new int[] {
10,
0,
0,
0});
this.nudScale.MaximumSize = new System.Drawing.Size(10000, 20);
this.nudScale.Minimum = new decimal(new int[] {
5,
0,
0,
65536});
this.nudScale.MinimumSize = new System.Drawing.Size(0, 21);
this.nudScale.Name = "nudScale";
this.nudScale.Size = new System.Drawing.Size(48, 21);
this.nudScale.TabIndex = 21;
this.nudScale.Value = new decimal(new int[] {
1,
0,
0,
0});
//
// flowLayoutPanel6
//
this.flowLayoutPanel6.Controls.Add(this.cboAspectRatio);
this.flowLayoutPanel6.Controls.Add(this.lblCustomRatio);
this.flowLayoutPanel6.Controls.Add(this.nudCustomRatio);
this.flowLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel6.Location = new System.Drawing.Point(77, 21);
this.flowLayoutPanel6.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel6.Name = "flowLayoutPanel6";
this.flowLayoutPanel6.Size = new System.Drawing.Size(483, 26);
this.flowLayoutPanel6.TabIndex = 22;
//
// cboAspectRatio
//
this.cboAspectRatio.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboAspectRatio.FormattingEnabled = true;
this.cboAspectRatio.Items.AddRange(new object[] {
"Auto",
"NTSC (8:7)",
"PAL (18:13)",
"Standard (4:3)",
"Widescreen (16:9)"});
this.cboAspectRatio.Location = new System.Drawing.Point(3, 3);
this.cboAspectRatio.Name = "cboAspectRatio";
this.cboAspectRatio.Size = new System.Drawing.Size(197, 21);
this.cboAspectRatio.TabIndex = 16;
//
// lblCustomRatio
//
this.lblCustomRatio.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblCustomRatio.AutoSize = true;
this.lblCustomRatio.Location = new System.Drawing.Point(206, 7);
this.lblCustomRatio.Name = "lblCustomRatio";
this.lblCustomRatio.Size = new System.Drawing.Size(76, 13);
this.lblCustomRatio.TabIndex = 17;
this.lblCustomRatio.Text = "Custom Ratio: ";
this.lblCustomRatio.Visible = false;
//
// nudCustomRatio
//
this.nudCustomRatio.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.nudCustomRatio.DecimalPlaces = 3;
this.nudCustomRatio.Increment = new decimal(new int[] {
1,
0,
0,
65536});
this.nudCustomRatio.Location = new System.Drawing.Point(285, 3);
this.nudCustomRatio.Margin = new System.Windows.Forms.Padding(0);
this.nudCustomRatio.Maximum = new decimal(new int[] {
5,
0,
0,
0});
this.nudCustomRatio.MaximumSize = new System.Drawing.Size(10000, 20);
this.nudCustomRatio.Minimum = new decimal(new int[] {
1,
0,
0,
65536});
this.nudCustomRatio.MinimumSize = new System.Drawing.Size(0, 21);
this.nudCustomRatio.Name = "nudCustomRatio";
this.nudCustomRatio.Size = new System.Drawing.Size(48, 21);
this.nudCustomRatio.TabIndex = 22;
this.nudCustomRatio.Value = new decimal(new int[] {
1,
0,
0,
65536});
this.nudCustomRatio.Visible = false;
//
// chkFullscreenForceIntegerScale
//
this.chkFullscreenForceIntegerScale.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkFullscreenForceIntegerScale.AutoSize = true;
this.tlpMain.SetColumnSpan(this.chkFullscreenForceIntegerScale, 2);
this.chkFullscreenForceIntegerScale.Location = new System.Drawing.Point(3, 146);
this.chkFullscreenForceIntegerScale.Name = "chkFullscreenForceIntegerScale";
this.chkFullscreenForceIntegerScale.Size = new System.Drawing.Size(289, 17);
this.chkFullscreenForceIntegerScale.TabIndex = 23;
this.chkFullscreenForceIntegerScale.Text = "Use integer scale values when entering fullscreen mode";
this.chkFullscreenForceIntegerScale.UseVisualStyleBackColor = true;
this.chkFullscreenForceIntegerScale.Visible = false;
//
// chkShowFps
//
this.chkShowFps.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkShowFps.AutoSize = true;
this.tlpMain.SetColumnSpan(this.chkShowFps, 2);
this.chkShowFps.Location = new System.Drawing.Point(3, 169);
this.chkShowFps.Name = "chkShowFps";
this.chkShowFps.Size = new System.Drawing.Size(76, 17);
this.chkShowFps.TabIndex = 9;
this.chkShowFps.Text = "Show FPS";
this.chkShowFps.UseVisualStyleBackColor = true;
this.chkShowFps.Visible = false;
//
// chkIntegerFpsMode
//
this.chkIntegerFpsMode.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkIntegerFpsMode.AutoSize = true;
this.tlpMain.SetColumnSpan(this.chkIntegerFpsMode, 2);
this.chkIntegerFpsMode.Location = new System.Drawing.Point(3, 50);
this.chkIntegerFpsMode.Name = "chkIntegerFpsMode";
this.chkIntegerFpsMode.Size = new System.Drawing.Size(308, 17);
this.chkIntegerFpsMode.TabIndex = 24;
this.chkIntegerFpsMode.Text = "Enable integer FPS mode (e.g: run at 60 fps instead of 60.1)";
this.chkIntegerFpsMode.UseVisualStyleBackColor = true;
this.chkIntegerFpsMode.Visible = false;
//
// flpRefreshRate
//
this.tlpMain.SetColumnSpan(this.flpRefreshRate, 2);
this.flpRefreshRate.Controls.Add(this.lblRequestedRefreshRate);
this.flpRefreshRate.Controls.Add(this.cboRefreshRate);
this.flpRefreshRate.Dock = System.Windows.Forms.DockStyle.Fill;
this.flpRefreshRate.Location = new System.Drawing.Point(30, 116);
this.flpRefreshRate.Margin = new System.Windows.Forms.Padding(30, 0, 0, 0);
this.flpRefreshRate.Name = "flpRefreshRate";
this.flpRefreshRate.Size = new System.Drawing.Size(530, 27);
this.flpRefreshRate.TabIndex = 26;
this.flpRefreshRate.Visible = false;
//
// lblRequestedRefreshRate
//
this.lblRequestedRefreshRate.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.lblRequestedRefreshRate.AutoSize = true;
this.lblRequestedRefreshRate.Location = new System.Drawing.Point(3, 7);
this.lblRequestedRefreshRate.Name = "lblRequestedRefreshRate";
this.lblRequestedRefreshRate.Size = new System.Drawing.Size(128, 13);
this.lblRequestedRefreshRate.TabIndex = 17;
this.lblRequestedRefreshRate.Text = "Requested Refresh Rate:";
//
// cboRefreshRate
//
this.cboRefreshRate.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboRefreshRate.FormattingEnabled = true;
this.cboRefreshRate.Items.AddRange(new object[] {
"Auto",
"NTSC (8:7)",
"PAL (18:13)",
"Standard (4:3)",
"Widescreen (16:9)"});
this.cboRefreshRate.Location = new System.Drawing.Point(137, 3);
this.cboRefreshRate.Name = "cboRefreshRate";
this.cboRefreshRate.Size = new System.Drawing.Size(68, 21);
this.cboRefreshRate.TabIndex = 25;
//
// tpgPicture
//
this.tpgPicture.Controls.Add(this.tableLayoutPanel5);
this.tpgPicture.Location = new System.Drawing.Point(4, 22);
this.tpgPicture.Name = "tpgPicture";
this.tpgPicture.Padding = new System.Windows.Forms.Padding(3);
this.tpgPicture.Size = new System.Drawing.Size(566, 382);
this.tpgPicture.TabIndex = 4;
this.tpgPicture.Text = "Picture";
this.tpgPicture.UseVisualStyleBackColor = true;
//
// tableLayoutPanel5
//
this.tableLayoutPanel5.ColumnCount = 2;
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel5.Controls.Add(this.tableLayoutPanel7, 0, 3);
this.tableLayoutPanel5.Controls.Add(this.grpNtscFilter, 1, 1);
this.tableLayoutPanel5.Controls.Add(this.grpCommon, 0, 1);
this.tableLayoutPanel5.Controls.Add(this.grpScanlines, 0, 2);
this.tableLayoutPanel5.Controls.Add(this.tableLayoutPanel8, 0, 0);
this.tableLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel5.Location = new System.Drawing.Point(3, 3);
this.tableLayoutPanel5.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel5.Name = "tableLayoutPanel5";
this.tableLayoutPanel5.RowCount = 4;
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel5.Size = new System.Drawing.Size(560, 376);
this.tableLayoutPanel5.TabIndex = 5;
//
// tableLayoutPanel7
//
this.tableLayoutPanel7.ColumnCount = 2;
this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 36.92308F));
this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 63.07692F));
this.tableLayoutPanel7.Controls.Add(this.btnSelectPreset, 1, 0);
this.tableLayoutPanel7.Controls.Add(this.btnResetPictureSettings, 0, 0);
this.tableLayoutPanel7.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel7.Location = new System.Drawing.Point(0, 341);
this.tableLayoutPanel7.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel7.Name = "tableLayoutPanel7";
this.tableLayoutPanel7.RowCount = 1;
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel7.Size = new System.Drawing.Size(280, 35);
this.tableLayoutPanel7.TabIndex = 3;
//
// btnSelectPreset
//
this.btnSelectPreset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnSelectPreset.AutoSize = true;
this.btnSelectPreset.Image = global::Mesen.GUI.Properties.Resources.DownArrow;
this.btnSelectPreset.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
this.btnSelectPreset.Location = new System.Drawing.Point(178, 9);
this.btnSelectPreset.Name = "btnSelectPreset";
this.btnSelectPreset.Padding = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.btnSelectPreset.Size = new System.Drawing.Size(99, 23);
this.btnSelectPreset.TabIndex = 3;
this.btnSelectPreset.Text = "Select Preset...";
this.btnSelectPreset.TextImageRelation = System.Windows.Forms.TextImageRelation.TextBeforeImage;
this.btnSelectPreset.UseVisualStyleBackColor = true;
this.btnSelectPreset.Click += new System.EventHandler(this.btnSelectPreset_Click);
//
// btnResetPictureSettings
//
this.btnResetPictureSettings.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnResetPictureSettings.AutoSize = true;
this.btnResetPictureSettings.Location = new System.Drawing.Point(3, 9);
this.btnResetPictureSettings.Name = "btnResetPictureSettings";
this.btnResetPictureSettings.Size = new System.Drawing.Size(45, 23);
this.btnResetPictureSettings.TabIndex = 3;
this.btnResetPictureSettings.Text = "Reset";
this.btnResetPictureSettings.UseVisualStyleBackColor = true;
this.btnResetPictureSettings.Click += new System.EventHandler(this.btnResetPictureSettings_Click);
//
// grpNtscFilter
//
this.grpNtscFilter.Controls.Add(this.tlpNtscFilter);
this.grpNtscFilter.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpNtscFilter.Location = new System.Drawing.Point(282, 27);
this.grpNtscFilter.Margin = new System.Windows.Forms.Padding(2, 0, 0, 0);
this.grpNtscFilter.Name = "grpNtscFilter";
this.tableLayoutPanel5.SetRowSpan(this.grpNtscFilter, 3);
this.grpNtscFilter.Size = new System.Drawing.Size(278, 349);
this.grpNtscFilter.TabIndex = 4;
this.grpNtscFilter.TabStop = false;
this.grpNtscFilter.Text = "NTSC Filter";
//
// tlpNtscFilter
//
this.tlpNtscFilter.ColumnCount = 1;
this.tlpNtscFilter.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpNtscFilter.Controls.Add(this.chkMergeFields, 0, 6);
this.tlpNtscFilter.Controls.Add(this.trkArtifacts, 0, 0);
this.tlpNtscFilter.Controls.Add(this.trkBleed, 0, 1);
this.tlpNtscFilter.Controls.Add(this.trkFringing, 0, 2);
this.tlpNtscFilter.Controls.Add(this.trkGamma, 0, 3);
this.tlpNtscFilter.Controls.Add(this.trkResolution, 0, 4);
this.tlpNtscFilter.Controls.Add(this.trkSharpness, 0, 5);
this.tlpNtscFilter.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpNtscFilter.Location = new System.Drawing.Point(3, 16);
this.tlpNtscFilter.Margin = new System.Windows.Forms.Padding(0);
this.tlpNtscFilter.Name = "tlpNtscFilter";
this.tlpNtscFilter.RowCount = 7;
this.tlpNtscFilter.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpNtscFilter.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpNtscFilter.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpNtscFilter.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpNtscFilter.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpNtscFilter.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpNtscFilter.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpNtscFilter.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlpNtscFilter.Size = new System.Drawing.Size(272, 330);
this.tlpNtscFilter.TabIndex = 5;
//
// chkMergeFields
//
this.chkMergeFields.AutoSize = true;
this.chkMergeFields.Location = new System.Drawing.Point(3, 303);
this.chkMergeFields.Name = "chkMergeFields";
this.chkMergeFields.Size = new System.Drawing.Size(86, 17);
this.chkMergeFields.TabIndex = 30;
this.chkMergeFields.Text = "Merge Fields";
this.chkMergeFields.UseVisualStyleBackColor = true;
//
// trkArtifacts
//
this.trkArtifacts.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkArtifacts.Location = new System.Drawing.Point(0, 0);
this.trkArtifacts.Margin = new System.Windows.Forms.Padding(0);
this.trkArtifacts.Maximum = 100;
this.trkArtifacts.MaximumSize = new System.Drawing.Size(0, 60);
this.trkArtifacts.Minimum = -100;
this.trkArtifacts.MinimumSize = new System.Drawing.Size(206, 50);
this.trkArtifacts.Name = "trkArtifacts";
this.trkArtifacts.Size = new System.Drawing.Size(272, 50);
this.trkArtifacts.TabIndex = 24;
this.trkArtifacts.Text = "Artifacts";
this.trkArtifacts.Value = 0;
//
// trkBleed
//
this.trkBleed.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkBleed.Location = new System.Drawing.Point(0, 50);
this.trkBleed.Margin = new System.Windows.Forms.Padding(0);
this.trkBleed.Maximum = 100;
this.trkBleed.MaximumSize = new System.Drawing.Size(400, 55);
this.trkBleed.Minimum = -100;
this.trkBleed.MinimumSize = new System.Drawing.Size(206, 50);
this.trkBleed.Name = "trkBleed";
this.trkBleed.Size = new System.Drawing.Size(272, 50);
this.trkBleed.TabIndex = 25;
this.trkBleed.Text = "Bleed";
this.trkBleed.Value = 0;
//
// trkFringing
//
this.trkFringing.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkFringing.Location = new System.Drawing.Point(0, 100);
this.trkFringing.Margin = new System.Windows.Forms.Padding(0);
this.trkFringing.Maximum = 100;
this.trkFringing.MaximumSize = new System.Drawing.Size(0, 41);
this.trkFringing.Minimum = -100;
this.trkFringing.MinimumSize = new System.Drawing.Size(206, 50);
this.trkFringing.Name = "trkFringing";
this.trkFringing.Size = new System.Drawing.Size(272, 50);
this.trkFringing.TabIndex = 26;
this.trkFringing.Text = "Fringing";
this.trkFringing.Value = 0;
//
// trkGamma
//
this.trkGamma.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkGamma.Location = new System.Drawing.Point(0, 150);
this.trkGamma.Margin = new System.Windows.Forms.Padding(0);
this.trkGamma.Maximum = 100;
this.trkGamma.MaximumSize = new System.Drawing.Size(0, 41);
this.trkGamma.Minimum = -100;
this.trkGamma.MinimumSize = new System.Drawing.Size(206, 50);
this.trkGamma.Name = "trkGamma";
this.trkGamma.Size = new System.Drawing.Size(272, 50);
this.trkGamma.TabIndex = 27;
this.trkGamma.Text = "Gamma";
this.trkGamma.Value = 0;
//
// trkResolution
//
this.trkResolution.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkResolution.Location = new System.Drawing.Point(0, 200);
this.trkResolution.Margin = new System.Windows.Forms.Padding(0);
this.trkResolution.Maximum = 100;
this.trkResolution.MaximumSize = new System.Drawing.Size(0, 41);
this.trkResolution.Minimum = -100;
this.trkResolution.MinimumSize = new System.Drawing.Size(206, 50);
this.trkResolution.Name = "trkResolution";
this.trkResolution.Size = new System.Drawing.Size(272, 50);
this.trkResolution.TabIndex = 28;
this.trkResolution.Text = "Resolution";
this.trkResolution.Value = 0;
//
// trkSharpness
//
this.trkSharpness.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkSharpness.Location = new System.Drawing.Point(0, 250);
this.trkSharpness.Margin = new System.Windows.Forms.Padding(0);
this.trkSharpness.Maximum = 100;
this.trkSharpness.MaximumSize = new System.Drawing.Size(0, 41);
this.trkSharpness.Minimum = -100;
this.trkSharpness.MinimumSize = new System.Drawing.Size(206, 50);
this.trkSharpness.Name = "trkSharpness";
this.trkSharpness.Size = new System.Drawing.Size(272, 50);
this.trkSharpness.TabIndex = 29;
this.trkSharpness.Text = "Sharpness";
this.trkSharpness.Value = 0;
//
// grpCommon
//
this.grpCommon.Controls.Add(this.tableLayoutPanel4);
this.grpCommon.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpCommon.Location = new System.Drawing.Point(0, 27);
this.grpCommon.Margin = new System.Windows.Forms.Padding(0, 0, 2, 0);
this.grpCommon.Name = "grpCommon";
this.grpCommon.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.grpCommon.Size = new System.Drawing.Size(278, 242);
this.grpCommon.TabIndex = 3;
this.grpCommon.TabStop = false;
this.grpCommon.Text = "Common Settings";
//
// tableLayoutPanel4
//
this.tableLayoutPanel4.ColumnCount = 1;
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel4.Controls.Add(this.chkBilinearInterpolation, 0, 4);
this.tableLayoutPanel4.Controls.Add(this.trkBrightness, 0, 0);
this.tableLayoutPanel4.Controls.Add(this.trkContrast, 0, 1);
this.tableLayoutPanel4.Controls.Add(this.trkHue, 0, 2);
this.tableLayoutPanel4.Controls.Add(this.trkSaturation, 0, 3);
this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 15);
this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 5;
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel4.Size = new System.Drawing.Size(272, 225);
this.tableLayoutPanel4.TabIndex = 4;
//
// chkBilinearInterpolation
//
this.chkBilinearInterpolation.AutoSize = true;
this.tableLayoutPanel4.SetColumnSpan(this.chkBilinearInterpolation, 2);
this.chkBilinearInterpolation.Location = new System.Drawing.Point(3, 203);
this.chkBilinearInterpolation.Name = "chkBilinearInterpolation";
this.chkBilinearInterpolation.Size = new System.Drawing.Size(206, 17);
this.chkBilinearInterpolation.TabIndex = 28;
this.chkBilinearInterpolation.Text = "Use bilinear interpolation when scaling";
this.chkBilinearInterpolation.UseVisualStyleBackColor = true;
//
// trkBrightness
//
this.trkBrightness.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkBrightness.Location = new System.Drawing.Point(0, 0);
this.trkBrightness.Margin = new System.Windows.Forms.Padding(0);
this.trkBrightness.Maximum = 100;
this.trkBrightness.MaximumSize = new System.Drawing.Size(0, 60);
this.trkBrightness.Minimum = -100;
this.trkBrightness.MinimumSize = new System.Drawing.Size(206, 50);
this.trkBrightness.Name = "trkBrightness";
this.trkBrightness.Size = new System.Drawing.Size(272, 50);
this.trkBrightness.TabIndex = 24;
this.trkBrightness.Text = "Brightness";
this.trkBrightness.Value = 0;
//
// trkContrast
//
this.trkContrast.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkContrast.Location = new System.Drawing.Point(0, 50);
this.trkContrast.Margin = new System.Windows.Forms.Padding(0);
this.trkContrast.Maximum = 100;
this.trkContrast.MaximumSize = new System.Drawing.Size(400, 55);
this.trkContrast.Minimum = -100;
this.trkContrast.MinimumSize = new System.Drawing.Size(206, 50);
this.trkContrast.Name = "trkContrast";
this.trkContrast.Size = new System.Drawing.Size(272, 50);
this.trkContrast.TabIndex = 25;
this.trkContrast.Text = "Contrast";
this.trkContrast.Value = 0;
//
// trkHue
//
this.trkHue.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkHue.Location = new System.Drawing.Point(0, 100);
this.trkHue.Margin = new System.Windows.Forms.Padding(0);
this.trkHue.Maximum = 100;
this.trkHue.MaximumSize = new System.Drawing.Size(0, 41);
this.trkHue.Minimum = -100;
this.trkHue.MinimumSize = new System.Drawing.Size(206, 50);
this.trkHue.Name = "trkHue";
this.trkHue.Size = new System.Drawing.Size(272, 50);
this.trkHue.TabIndex = 26;
this.trkHue.Text = "Hue";
this.trkHue.Value = 0;
//
// trkSaturation
//
this.trkSaturation.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkSaturation.Location = new System.Drawing.Point(0, 150);
this.trkSaturation.Margin = new System.Windows.Forms.Padding(0);
this.trkSaturation.Maximum = 100;
this.trkSaturation.MaximumSize = new System.Drawing.Size(0, 41);
this.trkSaturation.Minimum = -100;
this.trkSaturation.MinimumSize = new System.Drawing.Size(206, 50);
this.trkSaturation.Name = "trkSaturation";
this.trkSaturation.Size = new System.Drawing.Size(272, 50);
this.trkSaturation.TabIndex = 27;
this.trkSaturation.Text = "Saturation";
this.trkSaturation.Value = 0;
//
// grpScanlines
//
this.grpScanlines.Controls.Add(this.trkScanlines);
this.grpScanlines.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpScanlines.Location = new System.Drawing.Point(0, 269);
this.grpScanlines.Margin = new System.Windows.Forms.Padding(0, 0, 2, 0);
this.grpScanlines.Name = "grpScanlines";
this.grpScanlines.Size = new System.Drawing.Size(278, 72);
this.grpScanlines.TabIndex = 5;
this.grpScanlines.TabStop = false;
this.grpScanlines.Text = "Scanlines";
//
// trkScanlines
//
this.trkScanlines.Dock = System.Windows.Forms.DockStyle.Fill;
this.trkScanlines.Location = new System.Drawing.Point(3, 16);
this.trkScanlines.Margin = new System.Windows.Forms.Padding(0);
this.trkScanlines.Maximum = 100;
this.trkScanlines.MaximumSize = new System.Drawing.Size(0, 41);
this.trkScanlines.Minimum = 0;
this.trkScanlines.MinimumSize = new System.Drawing.Size(206, 50);
this.trkScanlines.Name = "trkScanlines";
this.trkScanlines.Size = new System.Drawing.Size(272, 50);
this.trkScanlines.TabIndex = 28;
this.trkScanlines.Text = "Scanlines";
this.trkScanlines.Value = 0;
//
// tableLayoutPanel8
//
this.tableLayoutPanel8.ColumnCount = 2;
this.tableLayoutPanel5.SetColumnSpan(this.tableLayoutPanel8, 2);
this.tableLayoutPanel8.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel8.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel8.Controls.Add(this.cboFilter, 1, 0);
this.tableLayoutPanel8.Controls.Add(this.lblVideoFilter, 0, 0);
this.tableLayoutPanel8.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel8.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel8.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel8.Name = "tableLayoutPanel8";
this.tableLayoutPanel8.RowCount = 1;
this.tableLayoutPanel8.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel8.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 27F));
this.tableLayoutPanel8.Size = new System.Drawing.Size(560, 27);
this.tableLayoutPanel8.TabIndex = 6;
//
// cboFilter
//
this.cboFilter.Dock = System.Windows.Forms.DockStyle.Fill;
this.cboFilter.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboFilter.FormattingEnabled = true;
this.cboFilter.Items.AddRange(new object[] {
"None",
"NTSC"});
this.cboFilter.Location = new System.Drawing.Point(41, 3);
this.cboFilter.Name = "cboFilter";
this.cboFilter.Size = new System.Drawing.Size(516, 21);
this.cboFilter.TabIndex = 15;
//
// lblVideoFilter
//
this.lblVideoFilter.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblVideoFilter.AutoSize = true;
this.lblVideoFilter.Location = new System.Drawing.Point(3, 7);
this.lblVideoFilter.Name = "lblVideoFilter";
this.lblVideoFilter.Size = new System.Drawing.Size(32, 13);
this.lblVideoFilter.TabIndex = 13;
this.lblVideoFilter.Text = "Filter:";
//
// ctxPicturePresets
//
this.ctxPicturePresets.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuPresetComposite,
this.mnuPresetSVideo,
this.mnuPresetRgb,
this.mnuPresetMonochrome});
this.ctxPicturePresets.Name = "contextPicturePresets";
this.ctxPicturePresets.Size = new System.Drawing.Size(148, 92);
//
// mnuPresetComposite
//
this.mnuPresetComposite.Name = "mnuPresetComposite";
this.mnuPresetComposite.Size = new System.Drawing.Size(147, 22);
this.mnuPresetComposite.Text = "Composite";
this.mnuPresetComposite.Click += new System.EventHandler(this.mnuPresetComposite_Click);
//
// mnuPresetSVideo
//
this.mnuPresetSVideo.Name = "mnuPresetSVideo";
this.mnuPresetSVideo.Size = new System.Drawing.Size(147, 22);
this.mnuPresetSVideo.Text = "S-Video";
this.mnuPresetSVideo.Click += new System.EventHandler(this.mnuPresetSVideo_Click);
//
// mnuPresetRgb
//
this.mnuPresetRgb.Name = "mnuPresetRgb";
this.mnuPresetRgb.Size = new System.Drawing.Size(147, 22);
this.mnuPresetRgb.Text = "RGB";
this.mnuPresetRgb.Click += new System.EventHandler(this.mnuPresetRgb_Click);
//
// mnuPresetMonochrome
//
this.mnuPresetMonochrome.Name = "mnuPresetMonochrome";
this.mnuPresetMonochrome.Size = new System.Drawing.Size(147, 22);
this.mnuPresetMonochrome.Text = "Monochrome";
this.mnuPresetMonochrome.Click += new System.EventHandler(this.mnuPresetMonochrome_Click);
//
// frmVideoConfig
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(574, 437);
this.Controls.Add(this.tabMain);
this.Name = "frmVideoConfig";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "frmVideoConfig";
this.Controls.SetChildIndex(this.baseConfigPanel, 0);
this.Controls.SetChildIndex(this.tabMain, 0);
this.tabMain.ResumeLayout(false);
this.tpgGeneral.ResumeLayout(false);
this.tlpMain.ResumeLayout(false);
this.tlpMain.PerformLayout();
this.flowLayoutPanel6.ResumeLayout(false);
this.flowLayoutPanel6.PerformLayout();
this.flpRefreshRate.ResumeLayout(false);
this.flpRefreshRate.PerformLayout();
this.tpgPicture.ResumeLayout(false);
this.tableLayoutPanel5.ResumeLayout(false);
this.tableLayoutPanel7.ResumeLayout(false);
this.tableLayoutPanel7.PerformLayout();
this.grpNtscFilter.ResumeLayout(false);
this.tlpNtscFilter.ResumeLayout(false);
this.tlpNtscFilter.PerformLayout();
this.grpCommon.ResumeLayout(false);
this.tableLayoutPanel4.ResumeLayout(false);
this.tableLayoutPanel4.PerformLayout();
this.grpScanlines.ResumeLayout(false);
this.tableLayoutPanel8.ResumeLayout(false);
this.tableLayoutPanel8.PerformLayout();
this.ctxPicturePresets.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TabControl tabMain;
private System.Windows.Forms.TabPage tpgGeneral;
private System.Windows.Forms.TableLayoutPanel tlpMain;
private System.Windows.Forms.CheckBox chkUseExclusiveFullscreen;
private System.Windows.Forms.Label lblVideoScale;
private System.Windows.Forms.CheckBox chkVerticalSync;
private System.Windows.Forms.Label lblDisplayRatio;
private Controls.MesenNumericUpDown nudScale;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel6;
private System.Windows.Forms.ComboBox cboAspectRatio;
private System.Windows.Forms.Label lblCustomRatio;
private Controls.MesenNumericUpDown nudCustomRatio;
private System.Windows.Forms.CheckBox chkFullscreenForceIntegerScale;
private System.Windows.Forms.CheckBox chkShowFps;
private System.Windows.Forms.CheckBox chkIntegerFpsMode;
private System.Windows.Forms.FlowLayoutPanel flpRefreshRate;
private System.Windows.Forms.Label lblRequestedRefreshRate;
private System.Windows.Forms.ComboBox cboRefreshRate;
private System.Windows.Forms.TabPage tpgPicture;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel7;
private System.Windows.Forms.Button btnSelectPreset;
private System.Windows.Forms.Button btnResetPictureSettings;
private System.Windows.Forms.GroupBox grpNtscFilter;
private System.Windows.Forms.TableLayoutPanel tlpNtscFilter;
private System.Windows.Forms.CheckBox chkMergeFields;
private Controls.ctrlHorizontalTrackbar trkArtifacts;
private Controls.ctrlHorizontalTrackbar trkBleed;
private Controls.ctrlHorizontalTrackbar trkFringing;
private Controls.ctrlHorizontalTrackbar trkGamma;
private Controls.ctrlHorizontalTrackbar trkResolution;
private Controls.ctrlHorizontalTrackbar trkSharpness;
private System.Windows.Forms.GroupBox grpCommon;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4;
private System.Windows.Forms.CheckBox chkBilinearInterpolation;
private Controls.ctrlHorizontalTrackbar trkBrightness;
private Controls.ctrlHorizontalTrackbar trkContrast;
private Controls.ctrlHorizontalTrackbar trkHue;
private Controls.ctrlHorizontalTrackbar trkSaturation;
private System.Windows.Forms.GroupBox grpScanlines;
private Controls.ctrlHorizontalTrackbar trkScanlines;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel8;
private System.Windows.Forms.ComboBox cboFilter;
private System.Windows.Forms.Label lblVideoFilter;
private System.Windows.Forms.ContextMenuStrip ctxPicturePresets;
private System.Windows.Forms.ToolStripMenuItem mnuPresetComposite;
private System.Windows.Forms.ToolStripMenuItem mnuPresetSVideo;
private System.Windows.Forms.ToolStripMenuItem mnuPresetRgb;
private System.Windows.Forms.ToolStripMenuItem mnuPresetMonochrome;
}
}

View file

@ -0,0 +1,128 @@
using Mesen.GUI.Config;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Forms.Config
{
public partial class frmVideoConfig : BaseConfigForm
{
public frmVideoConfig()
{
InitializeComponent();
if(DesignMode) {
return;
}
Entity = ConfigManager.Config.Video.Clone();
//AddBinding(nameof(VideoConfig.ShowFPS), chkShowFps);
AddBinding(nameof(VideoConfig.UseBilinearInterpolation), chkBilinearInterpolation);
AddBinding(nameof(VideoConfig.VerticalSync), chkVerticalSync);
AddBinding(nameof(VideoConfig.IntegerFpsMode), chkIntegerFpsMode);
AddBinding(nameof(VideoConfig.FullscreenForceIntegerScale), chkFullscreenForceIntegerScale);
AddBinding(nameof(VideoConfig.UseExclusiveFullscreen), chkUseExclusiveFullscreen);
AddBinding(nameof(VideoConfig.ExclusiveFullscreenRefreshRate), cboRefreshRate);
AddBinding(nameof(VideoConfig.VideoScale), nudScale);
AddBinding(nameof(VideoConfig.AspectRatio), cboAspectRatio);
AddBinding(nameof(VideoConfig.CustomAspectRatio), nudCustomRatio);
AddBinding(nameof(VideoConfig.VideoFilter), cboFilter);
AddBinding(nameof(VideoConfig.Brightness), trkBrightness);
AddBinding(nameof(VideoConfig.Contrast), trkContrast);
AddBinding(nameof(VideoConfig.Hue), trkHue);
AddBinding(nameof(VideoConfig.Saturation), trkSaturation);
AddBinding(nameof(VideoConfig.ScanlineIntensity), trkScanlines);
AddBinding(nameof(VideoConfig.NtscArtifacts), trkArtifacts);
AddBinding(nameof(VideoConfig.NtscBleed), trkBleed);
AddBinding(nameof(VideoConfig.NtscFringing), trkFringing);
AddBinding(nameof(VideoConfig.NtscGamma), trkGamma);
AddBinding(nameof(VideoConfig.NtscResolution), trkResolution);
AddBinding(nameof(VideoConfig.NtscSharpness), trkSharpness);
AddBinding(nameof(VideoConfig.NtscMergeFields), chkMergeFields);
}
protected override bool ValidateInput()
{
UpdateObject();
UpdateCustomRatioVisibility();
VideoFilterType filter = ((VideoConfig)Entity).VideoFilter;
grpNtscFilter.Visible = (filter == VideoFilterType.NTSC);
((VideoConfig)this.Entity).ApplyConfig();
return true;
}
protected override void OnApply()
{
ConfigManager.Config.Video = (VideoConfig)this.Entity;
ConfigManager.ApplyChanges();
}
private void UpdateCustomRatioVisibility()
{
VideoAspectRatio ratio = cboAspectRatio.GetEnumValue<VideoAspectRatio>();
lblCustomRatio.Visible = ratio == VideoAspectRatio.Custom;
nudCustomRatio.Visible = ratio == VideoAspectRatio.Custom;
}
private void btnResetPictureSettings_Click(object sender, EventArgs e)
{
SetNtscPreset(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false);
cboFilter.SetEnumValue(VideoFilterType.None);
}
private void btnSelectPreset_Click(object sender, EventArgs e)
{
ctxPicturePresets.Show(btnSelectPreset.PointToScreen(new Point(0, btnSelectPreset.Height - 1)));
}
private void SetNtscPreset(int hue, int saturation, int contrast, int brightness, int sharpness, int gamma, int resolution, int artifacts, int fringing, int bleed, int scanlines, bool mergeFields)
{
cboFilter.SetEnumValue(VideoFilterType.NTSC);
trkHue.Value = hue;
trkSaturation.Value = saturation;
trkContrast.Value = contrast;
trkBrightness.Value = brightness;
trkSharpness.Value = sharpness;
trkGamma.Value = gamma;
trkResolution.Value = resolution;
trkArtifacts.Value = artifacts;
trkFringing.Value = fringing;
trkBleed.Value = bleed;
chkMergeFields.Checked = mergeFields;
trkScanlines.Value = scanlines;
}
private void mnuPresetComposite_Click(object sender, EventArgs e)
{
SetNtscPreset(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, false);
}
private void mnuPresetSVideo_Click(object sender, EventArgs e)
{
SetNtscPreset(0, 0, 0, 0, 20, 0, 20, -100, -100, 0, 15, false);
}
private void mnuPresetRgb_Click(object sender, EventArgs e)
{
SetNtscPreset(0, 0, 0, 0, 20, 0, 70, -100, -100, -100, 15, false);
}
private void mnuPresetMonochrome_Click(object sender, EventArgs e)
{
SetNtscPreset(0, -100, 0, 0, 20, 0, 70, -20, -20, -10, 15, false);
}
}
}

View file

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="ctxPicturePresets.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>107, 17</value>
</metadata>
</root>

View file

@ -102,7 +102,11 @@ namespace Mesen.GUI.Forms
((ctrlTrackbar)kvp.Value).Value = (int)(uint)value;
}
} else if(kvp.Value is ctrlHorizontalTrackbar) {
((ctrlHorizontalTrackbar)kvp.Value).Value = (int)value;
if(field.FieldType == typeof(double)) {
((ctrlHorizontalTrackbar)kvp.Value).Value = (int)((double)value * 100);
} else {
((ctrlHorizontalTrackbar)kvp.Value).Value = (int)value;
}
} else if(kvp.Value is TrackBar) {
if(field.FieldType == typeof(Int32)) {
((TrackBar)kvp.Value).Value = (int)value;
@ -236,7 +240,11 @@ namespace Mesen.GUI.Forms
field.SetValue(Entity, (UInt32)((ctrlTrackbar)kvp.Value).Value);
}
} else if(kvp.Value is ctrlHorizontalTrackbar) {
field.SetValue(Entity, (Int32)((ctrlHorizontalTrackbar)kvp.Value).Value);
if(field.FieldType == typeof(double)) {
field.SetValue(Entity, ((ctrlHorizontalTrackbar)kvp.Value).Value / 100.0);
} else {
field.SetValue(Entity, (Int32)((ctrlHorizontalTrackbar)kvp.Value).Value);
}
} else if(kvp.Value is TrackBar) {
if(field.FieldType == typeof(Int32)) {
field.SetValue(Entity, ((TrackBar)kvp.Value).Value);

View file

@ -31,6 +31,8 @@
this.mnuMain = new Mesen.GUI.Controls.ctrlMesenMenuStrip();
this.mnuFile = new System.Windows.Forms.ToolStripMenuItem();
this.mnuOpen = new System.Windows.Forms.ToolStripMenuItem();
this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuVideoConfig = new System.Windows.Forms.ToolStripMenuItem();
this.debugToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRun = new System.Windows.Forms.ToolStripMenuItem();
this.mnuStep = new System.Windows.Forms.ToolStripMenuItem();
@ -41,12 +43,14 @@
this.mnuTraceLogger = new System.Windows.Forms.ToolStripMenuItem();
this.mnuTilemapViewer = new System.Windows.Forms.ToolStripMenuItem();
this.mnuEventViewer = new System.Windows.Forms.ToolStripMenuItem();
this.pnlRenderer = new System.Windows.Forms.Panel();
this.mnuMain.SuspendLayout();
this.pnlRenderer.SuspendLayout();
this.SuspendLayout();
//
// ctrlRenderer
//
this.ctrlRenderer.Location = new System.Drawing.Point(0, 27);
this.ctrlRenderer.Location = new System.Drawing.Point(0, 0);
this.ctrlRenderer.Name = "ctrlRenderer";
this.ctrlRenderer.Size = new System.Drawing.Size(512, 448);
this.ctrlRenderer.TabIndex = 0;
@ -55,6 +59,7 @@
//
this.mnuMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuFile,
this.optionsToolStripMenuItem,
this.debugToolStripMenuItem});
this.mnuMain.Location = new System.Drawing.Point(0, 0);
this.mnuMain.Name = "mnuMain";
@ -79,6 +84,22 @@
this.mnuOpen.Text = "Open";
this.mnuOpen.Click += new System.EventHandler(this.mnuOpen_Click);
//
// optionsToolStripMenuItem
//
this.optionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuVideoConfig});
this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem";
this.optionsToolStripMenuItem.Size = new System.Drawing.Size(61, 20);
this.optionsToolStripMenuItem.Text = "Options";
//
// mnuVideoConfig
//
this.mnuVideoConfig.Image = global::Mesen.GUI.Properties.Resources.VideoOptions;
this.mnuVideoConfig.Name = "mnuVideoConfig";
this.mnuVideoConfig.Size = new System.Drawing.Size(104, 22);
this.mnuVideoConfig.Text = "Video";
this.mnuVideoConfig.Click += new System.EventHandler(this.mnuVideoConfig_Click);
//
// debugToolStripMenuItem
//
this.debugToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@ -164,19 +185,30 @@
this.mnuEventViewer.Text = "Event Viewer";
this.mnuEventViewer.Click += new System.EventHandler(this.mnuEventViewer_Click);
//
// pnlRenderer
//
this.pnlRenderer.BackColor = System.Drawing.Color.Black;
this.pnlRenderer.Controls.Add(this.ctrlRenderer);
this.pnlRenderer.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlRenderer.Location = new System.Drawing.Point(0, 24);
this.pnlRenderer.Name = "pnlRenderer";
this.pnlRenderer.Size = new System.Drawing.Size(512, 448);
this.pnlRenderer.TabIndex = 2;
//
// frmMain
//
this.AllowDrop = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(512, 475);
this.Controls.Add(this.ctrlRenderer);
this.ClientSize = new System.Drawing.Size(512, 472);
this.Controls.Add(this.pnlRenderer);
this.Controls.Add(this.mnuMain);
this.MainMenuStrip = this.mnuMain;
this.Name = "frmMain";
this.Text = "frmMain";
this.mnuMain.ResumeLayout(false);
this.mnuMain.PerformLayout();
this.pnlRenderer.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
@ -198,5 +230,8 @@
private System.Windows.Forms.ToolStripMenuItem mnuMemoryTools;
private System.Windows.Forms.ToolStripMenuItem mnuTilemapViewer;
private System.Windows.Forms.ToolStripMenuItem mnuEventViewer;
private System.Windows.Forms.ToolStripMenuItem optionsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem mnuVideoConfig;
private System.Windows.Forms.Panel pnlRenderer;
}
}

View file

@ -1,5 +1,6 @@
using Mesen.GUI.Config;
using Mesen.GUI.Debugger;
using Mesen.GUI.Forms.Config;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@ -30,6 +31,8 @@ namespace Mesen.GUI.Forms
EmuApi.InitDll();
EmuApi.InitializeEmu(ConfigManager.HomeFolder, Handle, ctrlRenderer.Handle, false, false, false);
ConfigManager.Config.ApplyConfig();
_notifListener = new NotificationListener();
_notifListener.OnNotification += OnNotificationReceived;
@ -45,6 +48,8 @@ namespace Mesen.GUI.Forms
_notifListener = null;
}
ConfigManager.ApplyChanges();
DebugApi.ResumeExecution();
EmuApi.Stop();
EmuApi.Release();
@ -53,10 +58,40 @@ namespace Mesen.GUI.Forms
private void OnNotificationReceived(NotificationEventArgs e)
{
switch(e.NotificationType) {
case ConsoleNotificationType.CodeBreak:
case ConsoleNotificationType.ResolutionChanged:
ScreenSize size = EmuApi.GetScreenSize(false);
this.BeginInvoke((Action)(() => {
UpdateViewerSize(size);
}));
break;
}
}
private void UpdateViewerSize(ScreenSize screenSize)
{
//this.Resize -= frmMain_Resize;
//if(forceUpdate || (!_customSize && this.WindowState != FormWindowState.Maximized)) {
Size newSize = new Size(screenSize.Width, screenSize.Height);
//UpdateScaleMenu(size.Scale);
this.ClientSize = new Size(newSize.Width, newSize.Height + pnlRenderer.Top);
//}
ctrlRenderer.Size = new Size(screenSize.Width, screenSize.Height);
ctrlRenderer.Top = (pnlRenderer.Height - ctrlRenderer.Height) / 2;
ctrlRenderer.Left = (pnlRenderer.Width - ctrlRenderer.Width) / 2;
//this.Resize += frmMain_Resize;
}
private void mnuVideoConfig_Click(object sender, EventArgs e)
{
using(frmVideoConfig frm = new frmVideoConfig()) {
frm.ShowDialog(sender, this);
}
ConfigManager.Config.Video.ApplyConfig();
}
private void mnuDebugger_Click(object sender, EventArgs e)
{

21
UI/Interop/ConfigApi.cs Normal file
View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
using Mesen.GUI.Forms;
namespace Mesen.GUI
{
public class ConfigApi
{
private const string DllPath = "MesenSCore.dll";
[DllImport(DllPath)] public static extern void SetVideoConfig(VideoConfig config);
}
}

View file

@ -40,7 +40,16 @@ namespace Mesen.GUI
[DllImport(DllPath)] public static extern void SetDisplayLanguage(Language lang);
[DllImport(DllPath)] public static extern ScreenSize GetScreenSize([MarshalAs(UnmanagedType.I1)]bool ignoreScale);
[DllImport(DllPath, EntryPoint = "GetLog")] private static extern IntPtr GetLogWrapper();
public static string GetLog() { return Utf8Marshaler.PtrToStringUtf8(EmuApi.GetLogWrapper()).Replace("\n", Environment.NewLine); }
}
public struct ScreenSize
{
public Int32 Width;
public Int32 Height;
public double Scale;
}
}

View file

@ -209,9 +209,11 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CommandLineHelper.cs" />
<Compile Include="Config\BaseConfig.cs" />
<Compile Include="Config\ConfigAttributes.cs" />
<Compile Include="Config\Configuration.cs" />
<Compile Include="Config\ConfigManager.cs" />
<Compile Include="Config\VideoConfig.cs" />
<Compile Include="Debugger\Breakpoints\Breakpoint.cs" />
<Compile Include="Debugger\Breakpoints\BreakpointManager.cs" />
<Compile Include="Debugger\Breakpoints\ctrlBreakpoints.cs">
@ -462,6 +464,12 @@
<Compile Include="Forms\BaseInputForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Config\frmVideoConfig.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Config\frmVideoConfig.Designer.cs">
<DependentUpon>frmVideoConfig.cs</DependentUpon>
</Compile>
<Compile Include="Forms\EntityBinder.cs" />
<Compile Include="Forms\frmLogWindow.cs">
<SubType>Form</SubType>
@ -480,6 +488,7 @@
<Compile Include="Forms\ResourceHelper.cs" />
<Compile Include="Forms\ResourcePath.cs" />
<Compile Include="Interop\DebugApi.cs" />
<Compile Include="Interop\ConfigApi.cs" />
<Compile Include="Interop\EmuApi.cs" />
<Compile Include="Interop\NotificationListener.cs" />
<Compile Include="Interop\Utf8Marshaler.cs" />
@ -585,6 +594,9 @@
<EmbeddedResource Include="Forms\BaseInputForm.resx">
<DependentUpon>BaseInputForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Config\frmVideoConfig.resx">
<DependentUpon>frmVideoConfig.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\frmLogWindow.resx">
<DependentUpon>frmLogWindow.cs</DependentUpon>
</EmbeddedResource>

View file

@ -417,9 +417,6 @@
<ClInclude Include="md5.h" />
<ClInclude Include="miniz.h" />
<ClInclude Include="AutoResetEvent.h" />
<ClInclude Include="nes_ntsc.h" />
<ClInclude Include="nes_ntsc_config.h" />
<ClInclude Include="nes_ntsc_impl.h" />
<ClInclude Include="BaseCodec.h" />
<ClInclude Include="orfanidis_eq.h" />
<ClInclude Include="PlatformUtilities.h" />
@ -429,6 +426,9 @@
<ClInclude Include="Scale2x\scale3x.h" />
<ClInclude Include="Scale2x\scalebit.h" />
<ClInclude Include="sha1.h" />
<ClInclude Include="snes_ntsc.h" />
<ClInclude Include="snes_ntsc_config.h" />
<ClInclude Include="snes_ntsc_impl.h" />
<ClInclude Include="stb_vorbis.h" />
<ClInclude Include="StringUtilities.h" />
<ClInclude Include="SZReader.h" />
@ -543,7 +543,6 @@
</ClCompile>
<ClCompile Include="md5.cpp" />
<ClCompile Include="miniz.cpp" />
<ClCompile Include="nes_ntsc.cpp" />
<ClCompile Include="PlatformUtilities.cpp" />
<ClCompile Include="PNGHelper.cpp" />
<ClCompile Include="AutoResetEvent.cpp" />
@ -585,6 +584,7 @@
</ClCompile>
<ClCompile Include="sha1.cpp" />
<ClCompile Include="SimpleLock.cpp" />
<ClCompile Include="snes_ntsc.cpp" />
<ClCompile Include="Socket.cpp" />
<ClCompile Include="stb_vorbis.cpp" />
<ClCompile Include="stdafx.cpp">

View file

@ -80,15 +80,6 @@
<ClInclude Include="blip_buf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nes_ntsc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nes_ntsc_config.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nes_ntsc_impl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="xBRZ\config.h">
<Filter>xBRZ</Filter>
</ClInclude>
@ -170,6 +161,15 @@
<ClInclude Include="FastString.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="snes_ntsc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="snes_ntsc_config.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="snes_ntsc_impl.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -217,9 +217,6 @@
<ClCompile Include="blip_buf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="nes_ntsc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="xBRZ\xbrz.cpp">
<Filter>xBRZ</Filter>
</ClCompile>
@ -292,5 +289,8 @@
<ClCompile Include="VirtualFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="snes_ntsc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -1,291 +0,0 @@
#include "stdafx.h"
/* nes_ntsc 0.2.2. http://www.slack.net/~ant/ */
#include "nes_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 */
nes_ntsc_setup_t const nes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0, 0, 0 };
nes_ntsc_setup_t const nes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 };
nes_ntsc_setup_t const nes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0, 0, 0 };
nes_ntsc_setup_t const nes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0, 0, 0 };
#define alignment_count 3
#define burst_count 3
#define rescale_in 8
#define rescale_out 7
#define artifacts_mid 1.0f
#define fringing_mid 1.0f
#define std_decoder_hue -15
#define STD_HUE_CONDITION( setup ) !(setup->base_palette || setup->palette)
#include "nes_ntsc_impl.h"
/* 3 input pixels -> 8 composite samples */
pixel_info_t const nes_ntsc_pixels [alignment_count] = {
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
};
static void merge_kernel_fields( nes_ntsc_rgb_t* io )
{
int n;
for ( n = burst_size; n; --n )
{
nes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias;
nes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias;
nes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias;
/* merge colors without losing precision */
io [burst_size * 0] =
((p0 + p1 - ((p0 ^ p1) & nes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 1] =
((p1 + p2 - ((p1 ^ p2) & nes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 2] =
((p2 + p0 - ((p2 ^ p0) & nes_ntsc_rgb_builder)) >> 1) - rgb_bias;
++io;
}
}
static void correct_errors( nes_ntsc_rgb_t color, nes_ntsc_rgb_t* out )
{
int n;
for ( n = burst_count; n; --n )
{
unsigned i;
for ( i = 0; i < rgb_kernel_size / 2; i++ )
{
nes_ntsc_rgb_t error = color -
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 );
}
out += alignment_count * rgb_kernel_size;
}
}
void nes_ntsc_init( nes_ntsc_t* ntsc, nes_ntsc_setup_t const* setup )
{
int merge_fields;
int entry;
init_t impl;
float gamma_factor;
if ( !setup )
setup = &nes_ntsc_composite;
init( &impl, setup );
/* setup fast gamma */
{
float gamma = (float) setup->gamma * -0.5f;
if ( STD_HUE_CONDITION( setup ) )
gamma += 0.1333f;
gamma_factor = (float) pow( (float) fabs( gamma ), 0.73f );
if ( gamma < 0 )
gamma_factor = -gamma_factor;
}
merge_fields = setup->merge_fields;
if ( setup->artifacts <= -1 && setup->fringing <= -1 )
merge_fields = 1;
for ( entry = 0; entry < nes_ntsc_palette_size; entry++ )
{
/* Base 64-color generation */
static float const lo_levels [4] = { -0.12f, 0.00f, 0.31f, 0.72f };
static float const hi_levels [4] = { 0.40f, 0.68f, 1.00f, 1.00f };
int level = entry >> 4 & 0x03;
float lo = lo_levels [level];
float hi = hi_levels [level];
int color = entry & 0x0F;
if ( color == 0 )
lo = hi;
if ( color == 0x0D )
hi = lo;
if ( color > 0x0D )
hi = lo = 0.0f;
{
/* phases [i] = cos( i * PI / 6 ) */
static float const phases [0x10 + 3] = {
-1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f,
1.0f, 0.866025f, 0.5f, 0.0f, -0.5f, -0.866025f,
-1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f,
1.0f
};
#define TO_ANGLE_SIN( color ) phases [color]
#define TO_ANGLE_COS( color ) phases [(color) + 3]
/* Convert raw waveform to YIQ */
float sat = (hi - lo) * 0.5f;
float i = TO_ANGLE_SIN( color ) * sat;
float q = TO_ANGLE_COS( color ) * sat;
float y = (hi + lo) * 0.5f;
/* Optionally use base palette instead */
if ( setup->base_palette )
{
unsigned char const* in = &setup->base_palette [(entry & 0x3F) * 3];
static float const to_float = 1.0f / 0xFF;
float r = to_float * in [0];
float g = to_float * in [1];
float b = to_float * in [2];
q = RGB_TO_YIQ( r, g, b, y, i );
}
/* Apply color emphasis */
#ifdef NES_NTSC_EMPHASIS
{
int tint = entry >> 6 & 7;
if ( tint && color <= 0x0D )
{
static float const atten_mul = 0.79399f;
static float const atten_sub = 0.0782838f;
if ( tint == 7 )
{
y = y * (atten_mul * 1.13f) - (atten_sub * 1.13f);
}
else
{
static unsigned char const tints [8] = { 0, 6, 10, 8, 2, 4, 0, 0 };
int const tint_color = tints [tint];
float sat = hi * (0.5f - atten_mul * 0.5f) + atten_sub * 0.5f;
y -= sat * 0.5f;
if ( tint >= 3 && tint != 4 )
{
/* combined tint bits */
sat *= 0.6f;
y -= sat;
}
i += TO_ANGLE_SIN( tint_color ) * sat;
q += TO_ANGLE_COS( tint_color ) * sat;
}
}
}
#endif
/* Optionally use palette instead */
if ( setup->palette )
{
unsigned char const* in = &setup->palette [entry * 3];
static float const to_float = 1.0f / 0xFF;
float r = to_float * in [0];
float g = to_float * in [1];
float b = to_float * in [2];
q = RGB_TO_YIQ( r, g, b, y, i );
}
/* Apply brightness, contrast, and gamma */
y *= (float) setup->contrast * 0.5f + 1;
/* adjustment reduces error when using input palette */
y += (float) setup->brightness * 0.5f - 0.5f / 256;
{
float r, g, b = YIQ_TO_RGB( y, i, q, default_decoder, float, r, g );
/* fast approximation of n = pow( n, gamma ) */
r = (r * gamma_factor - gamma_factor) * r + r;
g = (g * gamma_factor - gamma_factor) * g + g;
b = (b * gamma_factor - gamma_factor) * b + 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 */
nes_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 )
{
nes_ntsc_rgb_t* kernel = ntsc->table [entry];
gen_kernel( &impl, y, i, q, kernel );
if ( merge_fields )
merge_kernel_fields( kernel );
correct_errors( rgb, kernel );
}
}
}
}
}
#ifndef NES_NTSC_NO_BLITTERS
void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / nes_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
NES_NTSC_IN_T const* line_in = input;
NES_NTSC_BEGIN_ROW( ntsc, burst_phase,
nes_ntsc_black, nes_ntsc_black, NES_NTSC_ADJ_IN( *line_in ) );
nes_ntsc_out_t* restrict line_out = (nes_ntsc_out_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
NES_NTSC_COLOR_IN( 0, NES_NTSC_ADJ_IN( line_in [0] ) );
NES_NTSC_RGB_OUT( 0, line_out [0], NES_NTSC_OUT_DEPTH );
NES_NTSC_RGB_OUT( 1, line_out [1], NES_NTSC_OUT_DEPTH );
NES_NTSC_COLOR_IN( 1, NES_NTSC_ADJ_IN( line_in [1] ) );
NES_NTSC_RGB_OUT( 2, line_out [2], NES_NTSC_OUT_DEPTH );
NES_NTSC_RGB_OUT( 3, line_out [3], NES_NTSC_OUT_DEPTH );
NES_NTSC_COLOR_IN( 2, NES_NTSC_ADJ_IN( line_in [2] ) );
NES_NTSC_RGB_OUT( 4, line_out [4], NES_NTSC_OUT_DEPTH );
NES_NTSC_RGB_OUT( 5, line_out [5], NES_NTSC_OUT_DEPTH );
NES_NTSC_RGB_OUT( 6, line_out [6], NES_NTSC_OUT_DEPTH );
line_in += 3;
line_out += 7;
}
/* finish final pixels */
NES_NTSC_COLOR_IN( 0, nes_ntsc_black );
NES_NTSC_RGB_OUT( 0, line_out [0], NES_NTSC_OUT_DEPTH );
NES_NTSC_RGB_OUT( 1, line_out [1], NES_NTSC_OUT_DEPTH );
NES_NTSC_COLOR_IN( 1, nes_ntsc_black );
NES_NTSC_RGB_OUT( 2, line_out [2], NES_NTSC_OUT_DEPTH );
NES_NTSC_RGB_OUT( 3, line_out [3], NES_NTSC_OUT_DEPTH );
NES_NTSC_COLOR_IN( 2, nes_ntsc_black );
NES_NTSC_RGB_OUT( 4, line_out [4], NES_NTSC_OUT_DEPTH );
NES_NTSC_RGB_OUT( 5, line_out [5], NES_NTSC_OUT_DEPTH );
NES_NTSC_RGB_OUT( 6, line_out [6], NES_NTSC_OUT_DEPTH );
burst_phase = (burst_phase + 1) % nes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
#endif

View file

@ -1,199 +0,0 @@
#pragma once
/* NES NTSC video filter */
/* nes_ntsc 0.2.2 */
#ifndef NES_NTSC_H
#define NES_NTSC_H
#if defined(_MSC_VER)
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
#include "nes_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 nes_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) */
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
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 512-entry RGB palette in, 3 bytes per color */
unsigned char const* base_palette;/* optional 64-entry RGB palette in, 3 bytes per color */
} nes_ntsc_setup_t;
/* Video format presets */
extern nes_ntsc_setup_t const nes_ntsc_composite; /* color bleeding + artifacts */
extern nes_ntsc_setup_t const nes_ntsc_svideo; /* color bleeding only */
extern nes_ntsc_setup_t const nes_ntsc_rgb; /* crisp image */
extern nes_ntsc_setup_t const nes_ntsc_monochrome;/* desaturated + artifacts */
#ifdef NES_NTSC_EMPHASIS
enum { nes_ntsc_palette_size = 64 * 8 };
#else
enum { nes_ntsc_palette_size = 64 };
#endif
/* Initializes and adjusts parameters. Can be called multiple times on the same
nes_ntsc_t object. Can pass NULL for either parameter. */
typedef struct nes_ntsc_t nes_ntsc_t;
EXPORT void nes_ntsc_init( nes_ntsc_t* ntsc, nes_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 NES_NTSC_OUT_DEPTH (defaults to 16-bit RGB). */
EXPORT void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* nes_in,
long in_row_width, int burst_phase, 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 NES_NTSC_IN_WIDTH() on result to find rounded
value. Guaranteed not to round 256 down at all. */
#define NES_NTSC_OUT_WIDTH( in_width ) \
((((in_width) - 1) / nes_ntsc_in_chunk + 1) * nes_ntsc_out_chunk)
/* Number of input pixels that will fit within given output width. Might be
rounded down slightly; use NES_NTSC_OUT_WIDTH() on result to find rounded
value. */
#define NES_NTSC_IN_WIDTH( out_width ) \
(((out_width) / nes_ntsc_out_chunk - 1) * nes_ntsc_in_chunk + 1)
/* Interface for user-defined custom blitters */
enum { nes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
enum { nes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
enum { nes_ntsc_black = 15 }; /* palette index for black */
enum { nes_ntsc_burst_count = 3 }; /* 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++). */
#define NES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \
char const* const ktable = \
(char const*) (ntsc)->table [0] + burst * (nes_ntsc_burst_size * sizeof (nes_ntsc_rgb_t));\
NES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, NES_NTSC_ENTRY_, ktable )
/* Begins input pixel */
#define NES_NTSC_COLOR_IN( in_index, color_in ) \
NES_NTSC_COLOR_IN_( in_index, color_in, NES_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 NES_NTSC_RGB_OUT( index, rgb_out, bits ) \
NES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 0 )
/* private */
enum { nes_ntsc_entry_size = 128 };
typedef unsigned long nes_ntsc_rgb_t;
struct nes_ntsc_t {
nes_ntsc_rgb_t table [nes_ntsc_palette_size] [nes_ntsc_entry_size];
};
enum { nes_ntsc_burst_size = nes_ntsc_entry_size / nes_ntsc_burst_count };
#define NES_NTSC_ENTRY_( ktable, n ) \
(nes_ntsc_rgb_t const*) (ktable + (n) * (nes_ntsc_entry_size * sizeof (nes_ntsc_rgb_t)))
/* deprecated */
#define NES_NTSC_RGB24_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 24 )
#define NES_NTSC_RGB16_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 16 )
#define NES_NTSC_RGB15_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 15 )
#define NES_NTSC_RAW_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 0 )
enum { nes_ntsc_min_in_width = 256 };
enum { nes_ntsc_min_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_min_in_width ) };
enum { nes_ntsc_640_in_width = 271 };
enum { nes_ntsc_640_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_640_in_width ) };
enum { nes_ntsc_640_overscan_left = 8 };
enum { nes_ntsc_640_overscan_right = nes_ntsc_640_in_width - 256 - nes_ntsc_640_overscan_left };
enum { nes_ntsc_full_in_width = 283 };
enum { nes_ntsc_full_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_full_in_width ) };
enum { nes_ntsc_full_overscan_left = 16 };
enum { nes_ntsc_full_overscan_right = nes_ntsc_full_in_width - 256 - nes_ntsc_full_overscan_left };
/* common 3->7 ntsc macros */
#define NES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
unsigned const nes_ntsc_pixel0_ = (pixel0);\
nes_ntsc_rgb_t const* kernel0 = ENTRY( table, nes_ntsc_pixel0_ );\
unsigned const nes_ntsc_pixel1_ = (pixel1);\
nes_ntsc_rgb_t const* kernel1 = ENTRY( table, nes_ntsc_pixel1_ );\
unsigned const nes_ntsc_pixel2_ = (pixel2);\
nes_ntsc_rgb_t const* kernel2 = ENTRY( table, nes_ntsc_pixel2_ );\
nes_ntsc_rgb_t const* kernelx0;\
nes_ntsc_rgb_t const* kernelx1 = kernel0;\
nes_ntsc_rgb_t const* kernelx2 = kernel0
#define NES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
nes_ntsc_rgb_t raw_ =\
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
NES_NTSC_CLAMP_( raw_, shift );\
NES_NTSC_RGB_OUT_( rgb_out, bits, shift );\
}
/* common ntsc macros */
#define nes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
#define nes_ntsc_clamp_mask (nes_ntsc_rgb_builder * 3 / 2)
#define nes_ntsc_clamp_add (nes_ntsc_rgb_builder * 0x101)
#define NES_NTSC_CLAMP_( io, shift ) {\
nes_ntsc_rgb_t sub = (io) >> (9-(shift)) & nes_ntsc_clamp_mask;\
nes_ntsc_rgb_t clamp = nes_ntsc_clamp_add - sub;\
io |= clamp;\
clamp -= sub;\
io &= clamp;\
}
#define NES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
unsigned color_;\
kernelx##index = kernel##index;\
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
}
/* x is always zero except in snes_ntsc library */
#define NES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == 16 )\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 32 || bits == 24 )\
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
if ( bits == 15 )\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 0 )\
rgb_out = raw_ << x;\
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,27 +0,0 @@
/* Configure library by modifying this file */
#ifndef NES_NTSC_CONFIG_H
#define NES_NTSC_CONFIG_H
/* Uncomment to enable emphasis support and use a 512 color palette instead
of the base 64 color palette. */
#define NES_NTSC_EMPHASIS 1
/* 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 NES_NTSC_OUT_DEPTH 32
/* Type of input pixel values. You'll probably use unsigned short
if you enable emphasis above. */
#define NES_NTSC_IN_T unsigned short
/* 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 NES_NTSC_ADJ_IN( in ) in
/* For each pixel, this is the basic operation:
output_color = color_palette [NES_NTSC_ADJ_IN( NES_NTSC_IN_T )] */
#endif

252
Utilities/snes_ntsc.cpp Normal file
View file

@ -0,0 +1,252 @@
#include "stdafx.h"
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
#include "snes_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 */
snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 };
#define alignment_count 3
#define burst_count 3
#define rescale_in 8
#define rescale_out 7
#define artifacts_mid 1.0f
#define fringing_mid 1.0f
#define std_decoder_hue 0
#define rgb_bits 7 /* half normal range to allow for doubled hires pixels */
#define gamma_size 32
#include "snes_ntsc_impl.h"
/* 3 input pixels -> 8 composite samples */
pixel_info_t const snes_ntsc_pixels [alignment_count] = {
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
};
static void merge_kernel_fields( snes_ntsc_rgb_t* io )
{
int n;
for ( n = burst_size; n; --n )
{
snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias;
snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias;
snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias;
/* merge colors without losing precision */
io [burst_size * 0] =
((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 1] =
((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 2] =
((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
++io;
}
}
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out )
{
int n;
for ( n = burst_count; n; --n )
{
unsigned i;
for ( i = 0; i < rgb_kernel_size / 2; i++ )
{
snes_ntsc_rgb_t error = color -
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 );
}
out += alignment_count * rgb_kernel_size;
}
}
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup )
{
int merge_fields;
int entry;
init_t impl;
if ( !setup )
setup = &snes_ntsc_composite;
init( &impl, setup );
merge_fields = setup->merge_fields;
if ( setup->artifacts <= -1 && setup->fringing <= -1 )
merge_fields = 1;
for ( entry = 0; entry < snes_ntsc_palette_size; entry++ )
{
/* Reduce number of significant bits of source color. Clearing the
low bits of R and B were least notictable. Modifying green was too
noticeable. */
int ir = entry >> 8 & 0x1E;
int ig = entry >> 4 & 0x1F;
int ib = entry << 1 & 0x1E;
#if SNES_NTSC_BSNES_COLORTBL
if ( setup->bsnes_colortbl )
{
int bgr15 = (ib << 10) | (ig << 5) | ir;
unsigned long rgb16 = setup->bsnes_colortbl [bgr15];
ir = rgb16 >> 11 & 0x1E;
ig = rgb16 >> 6 & 0x1F;
ib = rgb16 & 0x1E;
}
#endif
{
float rr = impl.to_float [ir];
float gg = impl.to_float [ig];
float bb = impl.to_float [ib];
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
snes_ntsc_rgb_t* out = ntsc->table [entry];
gen_kernel( &impl, y, i, q, out );
if ( merge_fields )
merge_kernel_fields( out );
correct_errors( rgb, out );
}
}
}
#ifndef SNES_NTSC_NO_BLITTERS
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / snes_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
SNES_NTSC_IN_T const* line_in = input;
SNES_NTSC_BEGIN_ROW( ntsc, burst_phase,
snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) );
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
line_in += 3;
line_out += 7;
}
/* finish final pixels */
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2);
for ( ; in_height; --in_height )
{
SNES_NTSC_IN_T const* line_in = input;
SNES_NTSC_HIRES_ROW( ntsc, burst_phase,
snes_ntsc_black, snes_ntsc_black, snes_ntsc_black,
SNES_NTSC_ADJ_IN( line_in [0] ),
SNES_NTSC_ADJ_IN( line_in [1] ) );
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
int n;
line_in += 2;
for ( n = chunk_count; n; --n )
{
/* twice as many input pixels per chunk */
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) );
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) );
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) );
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
line_in += 6;
line_out += 7;
}
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 3, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 4, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 5, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
#endif

206
Utilities/snes_ntsc.h Normal file
View file

@ -0,0 +1,206 @@
/* SNES NTSC video filter */
/* snes_ntsc 0.2.2 */
#ifndef SNES_NTSC_H
#define SNES_NTSC_H
#include "snes_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 snes_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) */
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */
} snes_ntsc_setup_t;
/* Video format presets */
extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */
extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */
extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */
extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */
/* Initializes and adjusts parameters. Can be called multiple times on the same
snes_ntsc_t object. Can pass NULL for either parameter. */
typedef struct snes_ntsc_t snes_ntsc_t;
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup );
/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT
and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
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. */
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
long in_row_width, int burst_phase, int in_width, int in_height,
void* rgb_out, long out_pitch );
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
long in_row_width, int burst_phase, int in_width, int in_height,
void* rgb_out, long out_pitch );
/* Number of output pixels written by low-res blitter for given input width. Width
might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded
value. Guaranteed not to round 256 down at all. */
#define SNES_NTSC_OUT_WIDTH( in_width ) \
((((in_width) - 1) / snes_ntsc_in_chunk + 1) * snes_ntsc_out_chunk)
/* Number of low-res input pixels that will fit within given output width. Might be
rounded down slightly; use SNES_NTSC_OUT_WIDTH() on result to find rounded
value. */
#define SNES_NTSC_IN_WIDTH( out_width ) \
(((out_width) / snes_ntsc_out_chunk - 1) * snes_ntsc_in_chunk + 1)
/* Interface for user-defined custom blitters */
enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
enum { snes_ntsc_black = 0 }; /* palette index for black */
enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
Use snes_ntsc_black for unused pixels. Declares variables, so must be before first
statement in a block (unless you're using C++). */
#define SNES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \
char const* ktable = \
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SNES_NTSC_IN_FORMAT, ktable )
/* Begins input pixel */
#define SNES_NTSC_COLOR_IN( index, color ) \
SNES_NTSC_COLOR_IN_( index, color, SNES_NTSC_IN_FORMAT, ktable )
/* Generates output pixel. Bits can be 24, 16, 15, 14, 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)
14: BBBBBGG GGGRRRRR (5-5-5 BGR, native SNES format)
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
#define SNES_NTSC_RGB_OUT( index, rgb_out, bits ) \
SNES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 1 )
/* Hires equivalents */
#define SNES_NTSC_HIRES_ROW( ntsc, burst, pixel1, pixel2, pixel3, pixel4, pixel5 ) \
char const* ktable = \
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
unsigned const snes_ntsc_pixel1_ = (pixel1);\
snes_ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel1_ );\
unsigned const snes_ntsc_pixel2_ = (pixel2);\
snes_ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel2_ );\
unsigned const snes_ntsc_pixel3_ = (pixel3);\
snes_ntsc_rgb_t const* kernel3 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel3_ );\
unsigned const snes_ntsc_pixel4_ = (pixel4);\
snes_ntsc_rgb_t const* kernel4 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel4_ );\
unsigned const snes_ntsc_pixel5_ = (pixel5);\
snes_ntsc_rgb_t const* kernel5 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel5_ );\
snes_ntsc_rgb_t const* kernel0 = kernel1;\
snes_ntsc_rgb_t const* kernelx0;\
snes_ntsc_rgb_t const* kernelx1 = kernel1;\
snes_ntsc_rgb_t const* kernelx2 = kernel1;\
snes_ntsc_rgb_t const* kernelx3 = kernel1;\
snes_ntsc_rgb_t const* kernelx4 = kernel1;\
snes_ntsc_rgb_t const* kernelx5 = kernel1
#define SNES_NTSC_HIRES_OUT( x, rgb_out, bits ) {\
snes_ntsc_rgb_t raw_ =\
kernel0 [ x ] + kernel2 [(x+5)%7+14] + kernel4 [(x+3)%7+28] +\
kernelx0 [(x+7)%7+7] + kernelx2 [(x+5)%7+21] + kernelx4 [(x+3)%7+35] +\
kernel1 [(x+6)%7 ] + kernel3 [(x+4)%7+14] + kernel5 [(x+2)%7+28] +\
kernelx1 [(x+6)%7+7] + kernelx3 [(x+4)%7+21] + kernelx5 [(x+2)%7+35];\
SNES_NTSC_CLAMP_( raw_, 0 );\
SNES_NTSC_RGB_OUT_( rgb_out, (bits), 0 );\
}
/* private */
enum { snes_ntsc_entry_size = 128 };
enum { snes_ntsc_palette_size = 0x2000 };
typedef unsigned long snes_ntsc_rgb_t;
struct snes_ntsc_t {
snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size];
};
enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count };
#define SNES_NTSC_RGB16( ktable, n ) \
(snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 1 & 0x03E0) | (n >> 2 & 0x3C00)) * \
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
#define SNES_NTSC_BGR15( ktable, n ) \
(snes_ntsc_rgb_t const*) (ktable + ((n << 9 & 0x3C00) | (n & 0x03E0) | (n >> 10 & 0x001E)) * \
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
/* common 3->7 ntsc macros */
#define SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
unsigned const snes_ntsc_pixel0_ = (pixel0);\
snes_ntsc_rgb_t const* kernel0 = ENTRY( table, snes_ntsc_pixel0_ );\
unsigned const snes_ntsc_pixel1_ = (pixel1);\
snes_ntsc_rgb_t const* kernel1 = ENTRY( table, snes_ntsc_pixel1_ );\
unsigned const snes_ntsc_pixel2_ = (pixel2);\
snes_ntsc_rgb_t const* kernel2 = ENTRY( table, snes_ntsc_pixel2_ );\
snes_ntsc_rgb_t const* kernelx0;\
snes_ntsc_rgb_t const* kernelx1 = kernel0;\
snes_ntsc_rgb_t const* kernelx2 = kernel0
#define SNES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
snes_ntsc_rgb_t raw_ =\
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
SNES_NTSC_CLAMP_( raw_, shift );\
SNES_NTSC_RGB_OUT_( rgb_out, bits, shift );\
}
/* common ntsc macros */
#define snes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
#define snes_ntsc_clamp_mask (snes_ntsc_rgb_builder * 3 / 2)
#define snes_ntsc_clamp_add (snes_ntsc_rgb_builder * 0x101)
#define SNES_NTSC_CLAMP_( io, shift ) {\
snes_ntsc_rgb_t sub = (io) >> (9-(shift)) & snes_ntsc_clamp_mask;\
snes_ntsc_rgb_t clamp = snes_ntsc_clamp_add - sub;\
io |= clamp;\
clamp -= sub;\
io &= clamp;\
}
#define SNES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
unsigned color_;\
kernelx##index = kernel##index;\
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
}
/* x is always zero except in snes_ntsc library */
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == 16 )\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 24 || bits == 32 )\
rgb_out = 0xFF000000|(raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
if ( bits == 15 )\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 14 )\
rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(9-x)&0x03E0)|(raw_<<(6+x)&0x7C00);\
if ( bits == 0 )\
rgb_out = raw_ << x;\
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,26 @@
/* Configure library by modifying this file */
#ifndef SNES_NTSC_CONFIG_H
#define SNES_NTSC_CONFIG_H
/* Format of source pixels */
/* #define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 */
#define SNES_NTSC_IN_FORMAT SNES_NTSC_BGR15
/* 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 SNES_NTSC_OUT_DEPTH 32
/* Type of input pixel values */
#define SNES_NTSC_IN_T unsigned short
/* 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 SNES_NTSC_ADJ_IN( in ) in
/* For each pixel, this is the basic operation:
output_color = SNES_NTSC_ADJ_IN( SNES_NTSC_IN_T ) */
#endif

View file

@ -1,4 +1,4 @@
/* nes_ntsc 0.2.2. http://www.slack.net/~ant/ */
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
/* Common implementation of NTSC filters */
@ -44,7 +44,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#define rgb_unit (1 << rgb_bits)
#define rgb_offset (rgb_unit * 2 + 0.5f)
enum { burst_size = nes_ntsc_entry_size / burst_count };
enum { burst_size = snes_ntsc_entry_size / burst_count };
enum { kernel_half = 16 };
enum { kernel_size = kernel_half * 2 + 1 };
@ -66,7 +66,7 @@ typedef struct init_t
i = t;\
}
static void init_filters( init_t* impl, nes_ntsc_setup_t const* setup )
static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
{
#if rescale_out > 1
float kernels [kernel_size * 2];
@ -195,7 +195,7 @@ static void init_filters( init_t* impl, nes_ntsc_setup_t const* setup )
static float const default_decoder [6] =
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
static void init( init_t* impl, nes_ntsc_setup_t const* setup )
static void init( init_t* impl, snes_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;
@ -285,7 +285,7 @@ static void init( init_t* impl, nes_ntsc_setup_t const* setup )
#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 * nes_ntsc_rgb_builder };
enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder };
typedef struct pixel_info_t
{
@ -309,10 +309,10 @@ typedef struct pixel_info_t
(1.0f - (((ntsc) + 100) & 2))
#endif
extern pixel_info_t const nes_ntsc_pixels [alignment_count];
extern pixel_info_t const snes_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, nes_ntsc_rgb_t* out )
static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out )
{
/* generate for each scanline burst phase */
float const* to_rgb = impl->to_rgb;
@ -324,7 +324,7 @@ static void gen_kernel( init_t* impl, float y, float i, float q, nes_ntsc_rgb_t*
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 = nes_ntsc_pixels;
pixel_info_t const* pixel = snes_ntsc_pixels;
int alignment_remain = alignment_count;
do
{
@ -377,7 +377,7 @@ static void gen_kernel( init_t* impl, float y, float i, float q, nes_ntsc_rgb_t*
while ( --burst_remain );
}
static void correct_errors( nes_ntsc_rgb_t color, nes_ntsc_rgb_t* out );
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out );
#if DISABLE_CORRECTION
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
@ -385,8 +385,8 @@ static void correct_errors( nes_ntsc_rgb_t color, nes_ntsc_rgb_t* out );
#else
#define CORRECT_ERROR( a ) { out [a] += error; }
#define DISTRIBUTE_ERROR( a, b, c ) {\
nes_ntsc_rgb_t fourth = (error + 2 * nes_ntsc_rgb_builder) >> 2;\
fourth &= (rgb_bias >> 1) - nes_ntsc_rgb_builder;\
snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\
fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\
fourth -= rgb_bias >> 2;\
out [a] += fourth;\
out [b] += fourth;\
@ -398,8 +398,8 @@ static void correct_errors( nes_ntsc_rgb_t color, nes_ntsc_rgb_t* out );
#define RGB_PALETTE_OUT( rgb, out_ )\
{\
unsigned char* out = (out_);\
nes_ntsc_rgb_t clamped = (rgb);\
NES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
snes_ntsc_rgb_t clamped = (rgb);\
SNES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
out [0] = (unsigned char) (clamped >> 21);\
out [1] = (unsigned char) (clamped >> 11);\
out [2] = (unsigned char) (clamped >> 1);\
@ -420,18 +420,18 @@ static void correct_errors( nes_ntsc_rgb_t color, nes_ntsc_rgb_t* out );
#include <limits.h>
#if NES_NTSC_OUT_DEPTH <= 16
#if SNES_NTSC_OUT_DEPTH <= 16
#if USHRT_MAX == 0xFFFF
typedef unsigned short nes_ntsc_out_t;
typedef unsigned short snes_ntsc_out_t;
#else
#error "Need 16-bit int type"
#endif
#else
#if UINT_MAX == 0xFFFFFFFF
typedef unsigned int nes_ntsc_out_t;
typedef unsigned int snes_ntsc_out_t;
#elif ULONG_MAX == 0xFFFFFFFF
typedef unsigned long nes_ntsc_out_t;
typedef unsigned long snes_ntsc_out_t;
#else
#error "Need 32-bit int type"
#endif

View file

@ -8,6 +8,7 @@
#include "../Core/Debugger.h"
#include "../Core/MessageManager.h"
#include "../Core/SettingTypes.h"
#include "../Core/EmuSettings.h"
#include "../Utilities/UTF8Util.h"
using namespace DirectX;
@ -40,20 +41,18 @@ void Renderer::SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t m
void Renderer::SetScreenSize(uint32_t width, uint32_t height)
{
ScreenSize screenSize;
_console->GetVideoDecoder()->GetScreenSize(screenSize, false);
//TODO _resizeFilter != _console->GetSettings()->GetVideoResizeFilter()
if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _newFullscreen != _fullscreen) {
ScreenSize screenSize = _console->GetVideoDecoder()->GetScreenSize(false);
VideoConfig cfg = _console->GetSettings()->GetVideoConfig();
if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _newFullscreen != _fullscreen || _useBilinearInterpolation != cfg.UseBilinearInterpolation) {
auto frameLock = _frameLock.AcquireSafe();
auto textureLock = _textureLock.AcquireSafe();
_console->GetVideoDecoder()->GetScreenSize(screenSize, false);
if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _newFullscreen != _fullscreen) {
screenSize = _console->GetVideoDecoder()->GetScreenSize(false);
if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _newFullscreen != _fullscreen || _useBilinearInterpolation != cfg.UseBilinearInterpolation) {
_nesFrameHeight = height;
_nesFrameWidth = width;
_newFrameBufferSize = width*height;
bool needReset = _fullscreen != _newFullscreen;//TODO || _resizeFilter != _console->GetSettings()->GetVideoResizeFilter();
bool needReset = _fullscreen != _newFullscreen || _useBilinearInterpolation != cfg.UseBilinearInterpolation;
bool fullscreenResizeMode = _fullscreen && _newFullscreen;
if(_pSwapChain && _fullscreen && !_newFullscreen) {
@ -278,7 +277,7 @@ HRESULT Renderer::InitDevice()
sd.BufferDesc.Width = _realScreenWidth;
sd.BufferDesc.Height = _realScreenHeight;
sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60; //TODO _console->GetSettings()->GetExclusiveRefreshRate();
sd.BufferDesc.RefreshRate.Numerator = _console->GetSettings()->GetVideoConfig().ExclusiveFullscreenRefreshRate;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.Flags = _fullscreen ? DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH : 0;
@ -401,12 +400,12 @@ HRESULT Renderer::InitDevice()
HRESULT Renderer::CreateSamplerState()
{
_resizeFilter = VideoResizeFilter::NearestNeighbor; //TODO _console->GetSettings()->GetVideoResizeFilter();
_useBilinearInterpolation = _console->GetSettings()->GetVideoConfig().UseBilinearInterpolation;
//Sample state
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(samplerDesc));
samplerDesc.Filter = _resizeFilter == VideoResizeFilter::Bilinear ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.Filter = _useBilinearInterpolation ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
@ -637,7 +636,7 @@ void Renderer::Render()
// Present the information rendered to the back buffer to the front buffer (the screen)
bool waitVSync = false; //TODO _console->GetSettings()->CheckFlag(EmulationFlags::VerticalSync)
bool waitVSync = _console->GetSettings()->GetVideoConfig().VerticalSync;
HRESULT hr = _pSwapChain->Present(waitVSync ? 1 : 0, 0);
if(FAILED(hr)) {
MessageManager::Log("SwapChain::Present() failed - Error:" + std::to_string(hr));

View file

@ -42,7 +42,7 @@ private:
SimpleLock _frameLock;
SimpleLock _textureLock;
VideoResizeFilter _resizeFilter = VideoResizeFilter::NearestNeighbor;
bool _useBilinearInterpolation = false;
unique_ptr<SpriteFont> _font;
unique_ptr<SpriteFont> _largeFont;