Video: Overscan settings

This commit is contained in:
Sour 2019-03-15 10:15:45 -04:00
parent 61c1b58051
commit 84d1439780
14 changed files with 446 additions and 33 deletions

View file

@ -10,7 +10,7 @@
BaseVideoFilter::BaseVideoFilter(shared_ptr<Console> console)
{
_console = console;
_overscan = {}; //TODO _console->GetSettings()->GetOverscanDimensions();
_overscan = _console->GetSettings()->GetOverscan();
}
BaseVideoFilter::~BaseVideoFilter()
@ -29,7 +29,11 @@ void BaseVideoFilter::SetBaseFrameInfo(FrameInfo frameInfo)
FrameInfo BaseVideoFilter::GetFrameInfo()
{
return _baseFrameInfo;
FrameInfo frameInfo = _baseFrameInfo;
OverscanDimensions overscan = GetOverscan();
frameInfo.Width -= overscan.Left * 2 + overscan.Right * 2;
frameInfo.Height -= overscan.Top * 2 + overscan.Bottom * 2;
return frameInfo;
}
void BaseVideoFilter::UpdateBufferSize()
@ -64,7 +68,7 @@ bool BaseVideoFilter::IsOddFrame()
void BaseVideoFilter::SendFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber)
{
_frameLock.Acquire();
_overscan = {}; //TODO _console->GetSettings()->GetOverscanDimensions();
_overscan = _console->GetSettings()->GetOverscan();
_isOddFrame = frameNumber % 2;
UpdateBufferSize();
OnBeforeApplyFilter();

View file

@ -13,12 +13,12 @@ private:
SimpleLock _frameLock;
OverscanDimensions _overscan;
bool _isOddFrame;
FrameInfo _baseFrameInfo;
void UpdateBufferSize();
protected:
shared_ptr<Console> _console;
FrameInfo _baseFrameInfo;
virtual void ApplyFilter(uint16_t *ppuOutputBuffer) = 0;
virtual void OnBeforeApplyFilter();

View file

@ -87,26 +87,31 @@ void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
{
uint32_t *out = GetOutputBuffer();
FrameInfo frameInfo = GetFrameInfo();
OverscanDimensions overscan = GetOverscan();
uint32_t xOffset = overscan.Left * 2;
uint32_t yOffset = overscan.Top * 2 * 512;
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 = ApplyScanlineEffect(_calculatedPalette[ppuOutputBuffer[i * 512 + j + yOffset + xOffset]], scanlineIntensity);
out++;
}
} else {
for(uint32_t j = 0; j < frameInfo.Width; j++) {
*out = _calculatedPalette[ppuOutputBuffer[i * 512 + j]];
*out = _calculatedPalette[ppuOutputBuffer[i * 512 + j + yOffset + xOffset]];
out++;
}
}
}
} else {
uint32_t pixelCount = frameInfo.Width * frameInfo.Height;
for(uint32_t i = 0; i < pixelCount; i++) {
out[i] = _calculatedPalette[ppuOutputBuffer[i]];
for(uint32_t i = 0; i < frameInfo.Height; i++) {
for(uint32_t j = 0; j < frameInfo.Width; j++) {
out[i*frameInfo.Width+j] = _calculatedPalette[ppuOutputBuffer[i * 512 + j + yOffset + xOffset]];
}
}
}
}

View file

@ -151,6 +151,16 @@ vector<KeyCombination> EmuSettings::GetShortcutSupersets(EmulatorShortcut shortc
return _shortcutSupersets[keySetIndex][(uint32_t)shortcut];
}
OverscanDimensions EmuSettings::GetOverscan()
{
OverscanDimensions overscan;
overscan.Left = _video.OverscanLeft;
overscan.Right = _video.OverscanRight;
overscan.Top = _video.OverscanTop;
overscan.Bottom = _video.OverscanBottom;
return overscan;
}
uint32_t EmuSettings::GetRewindBufferSize()
{
return _preferences.RewindBufferSize;

View file

@ -51,6 +51,7 @@ public:
KeyCombination GetShortcutKey(EmulatorShortcut shortcut, int keySetIndex);
vector<KeyCombination> GetShortcutSupersets(EmulatorShortcut shortcut, int keySetIndex);
OverscanDimensions GetOverscan();
uint32_t GetRewindBufferSize();
uint32_t GetEmulationSpeed();
double GetAspectRatio();

View file

@ -15,7 +15,8 @@ NtscFilter::NtscFilter(shared_ptr<Console> console) : BaseVideoFilter(console)
FrameInfo NtscFilter::GetFrameInfo()
{
FrameInfo frameInfo = BaseVideoFilter::GetFrameInfo();
frameInfo.Width = SNES_NTSC_OUT_WIDTH(frameInfo.Width / 2);
OverscanDimensions overscan = GetOverscan();
frameInfo.Width = SNES_NTSC_OUT_WIDTH(_baseFrameInfo.Width / 2) - overscan.Left * 2 - overscan.Right * 2;
return frameInfo;
}
@ -45,22 +46,29 @@ void NtscFilter::OnBeforeApplyFilter()
void NtscFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
{
FrameInfo frameInfo = GetFrameInfo();
OverscanDimensions overscan = GetOverscan();
uint32_t baseWidth = SNES_NTSC_OUT_WIDTH(256);
uint32_t xOffset = overscan.Left * 2;
uint32_t yOffset = overscan.Top * 2 * baseWidth;
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));
for(uint32_t i = 0; i < frameInfo.Height; i++) {
memcpy(GetOutputBuffer()+i*frameInfo.Width, _ntscBuffer + yOffset + xOffset + i*baseWidth, frameInfo.Width * sizeof(uint32_t));
}
} else {
uint8_t intensity = (uint8_t)((1.0 - cfg.ScanlineIntensity) * 255);
for(uint32_t i = 0; i < frameInfo.Height; i++) {
if(i & 0x01) {
uint32_t *in = _ntscBuffer + i * frameInfo.Width;
uint32_t *in = _ntscBuffer + yOffset + xOffset + i * baseWidth;
uint32_t *out = GetOutputBuffer() + i * frameInfo.Width;
for(uint32_t j = 0; j < frameInfo.Width; j++) {
out[j] = ApplyScanlineEffect(in[j], intensity);
}
} else {
memcpy(GetOutputBuffer()+i*frameInfo.Width, _ntscBuffer+i*frameInfo.Width, frameInfo.Width * sizeof(uint32_t));
memcpy(GetOutputBuffer()+i*frameInfo.Width, _ntscBuffer + yOffset + xOffset + i*baseWidth, frameInfo.Width * sizeof(uint32_t));
}
}
}

View file

@ -86,6 +86,11 @@ struct VideoConfig
double NtscSharpness = 0;
bool NtscMergeFields = false;
uint32_t OverscanLeft = 0;
uint32_t OverscanRight = 0;
uint32_t OverscanTop = 0;
uint32_t OverscanBottom = 0;
bool FullscreenForceIntegerScale = false;
bool UseExclusiveFullscreen = false;
int32_t ExclusiveFullscreenRefreshRate = 60;

View file

@ -18,7 +18,10 @@ VideoDecoder::VideoDecoder(shared_ptr<Console> console)
_console = console;
_frameChanged = false;
_stopFlag = false;
_baseFrameInfo = { 512, 478 };
_lastFrameInfo = _baseFrameInfo;
UpdateVideoFilter();
_videoFilter->SetBaseFrameInfo(_baseFrameInfo);
}
VideoDecoder::~VideoDecoder()
@ -33,22 +36,25 @@ FrameInfo VideoDecoder::GetFrameInfo()
ScreenSize VideoDecoder::GetScreenSize(bool ignoreScale)
{
ScreenSize size = {};
if(_videoFilter) {
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)(_baseFrameInfo.Height * scale * aspectRatio / 2);
}
/*if(_console->GetSettings()->GetScreenRotation() % 180) {
std::swap(size.Width, size.Height);
}*/
ScreenSize size;
OverscanDimensions overscan = ignoreScale ? _videoFilter->GetOverscan() : _console->GetSettings()->GetOverscan();
FrameInfo frameInfo = _videoFilter->GetFrameInfo();
double aspectRatio = _console->GetSettings()->GetAspectRatio();
double scale = (ignoreScale ? 1 : _console->GetSettings()->GetVideoConfig().VideoScale);
size.Width = (int32_t)(frameInfo.Width * scale / 2);
size.Height = (int32_t)(frameInfo.Height * scale / 2);
if(aspectRatio != 0.0) {
uint32_t originalHeight = frameInfo.Height + (overscan.Top + overscan.Bottom) * 2;
uint32_t originalWidth = frameInfo.Width + (overscan.Left + overscan.Right) * 2;
size.Width = (uint32_t)(originalHeight * scale * aspectRatio * ((double)frameInfo.Width / originalWidth)) / 2;
}
/*
if(_console->GetSettings()->GetScreenRotation() % 180) {
std::swap(size.Width, size.Height);
}*/
size.Scale = scale;
return size;
}

View file

@ -28,9 +28,9 @@ private:
atomic<bool> _stopFlag;
uint32_t _frameCount = 0;
FrameInfo _baseFrameInfo = { 512, 478 };
ScreenSize _previousScreenSize = {};
double _previousScale = 0;
FrameInfo _baseFrameInfo;
FrameInfo _lastFrameInfo;
VideoFilterType _videoFilterType = VideoFilterType::None;

View file

@ -33,6 +33,11 @@ namespace Mesen.GUI.Config
[MinMax(-1, 1.0)] public double NtscSharpness = 0;
[MarshalAs(UnmanagedType.I1)] public bool NtscMergeFields = false;
[MinMax(0, 100)] public UInt32 OverscanLeft = 0;
[MinMax(0, 100)] public UInt32 OverscanRight = 0;
[MinMax(0, 100)] public UInt32 OverscanTop = 0;
[MinMax(0, 100)] public UInt32 OverscanBottom = 0;
[MarshalAs(UnmanagedType.I1)] public bool FullscreenForceIntegerScale = false;
[MarshalAs(UnmanagedType.I1)] public bool UseExclusiveFullscreen = false;
public Int32 ExclusiveFullscreenRefreshRate = 60;

View file

@ -16,6 +16,7 @@ namespace Mesen.GUI.Emulation
private frmMain _frm;
private ctrlRenderer _renderer;
private Panel _panel;
private bool _resizeForm;
public DisplayManager(frmMain frm, ctrlRenderer renderer, Panel panel)
{
@ -30,11 +31,11 @@ namespace Mesen.GUI.Emulation
SetScaleBasedOnWindowSize();
}
public void UpdateViewerSize(bool resizeForm)
public void UpdateViewerSize()
{
ScreenSize screenSize = EmuApi.GetScreenSize(false);
if(resizeForm && _frm.WindowState != FormWindowState.Maximized) {
if(_resizeForm && _frm.WindowState != FormWindowState.Maximized) {
_frm.Resize -= frmMain_Resize;
Size newSize = new Size(screenSize.Width, screenSize.Height);
_frm.ClientSize = new Size(newSize.Width, newSize.Height + _panel.Top);
@ -72,11 +73,12 @@ namespace Mesen.GUI.Emulation
public void SetScale(double scale, bool resizeForm)
{
_resizeForm = resizeForm;
ConfigManager.Config.Video.VideoScale = scale;
ConfigManager.Config.Video.ApplyConfig();
ConfigManager.ApplyChanges();
UpdateViewerSize(resizeForm);
UpdateViewerSize();
}
public void ToggleFullscreen()

View file

@ -76,6 +76,21 @@
this.mnuPresetSVideo = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPresetRgb = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPresetMonochrome = new System.Windows.Forms.ToolStripMenuItem();
this.tpgOverscan = new System.Windows.Forms.TabPage();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.picOverscan = new System.Windows.Forms.PictureBox();
this.tableLayoutPanel11 = new System.Windows.Forms.TableLayoutPanel();
this.nudOverscanTop = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblTop = new System.Windows.Forms.Label();
this.tableLayoutPanel12 = new System.Windows.Forms.TableLayoutPanel();
this.nudOverscanBottom = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblBottom = new System.Windows.Forms.Label();
this.tableLayoutPanel13 = new System.Windows.Forms.TableLayoutPanel();
this.nudOverscanRight = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblRight = new System.Windows.Forms.Label();
this.tableLayoutPanel14 = new System.Windows.Forms.TableLayoutPanel();
this.nudOverscanLeft = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblLeft = new System.Windows.Forms.Label();
this.tabMain.SuspendLayout();
this.tpgGeneral.SuspendLayout();
this.tlpMain.SuspendLayout();
@ -91,6 +106,13 @@
this.grpScanlines.SuspendLayout();
this.tableLayoutPanel8.SuspendLayout();
this.ctxPicturePresets.SuspendLayout();
this.tpgOverscan.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picOverscan)).BeginInit();
this.tableLayoutPanel11.SuspendLayout();
this.tableLayoutPanel12.SuspendLayout();
this.tableLayoutPanel13.SuspendLayout();
this.tableLayoutPanel14.SuspendLayout();
this.SuspendLayout();
//
// baseConfigPanel
@ -102,6 +124,7 @@
//
this.tabMain.Controls.Add(this.tpgGeneral);
this.tabMain.Controls.Add(this.tpgPicture);
this.tabMain.Controls.Add(this.tpgOverscan);
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabMain.Location = new System.Drawing.Point(0, 0);
this.tabMain.Name = "tabMain";
@ -791,6 +814,294 @@
this.mnuPresetMonochrome.Text = "Monochrome";
this.mnuPresetMonochrome.Click += new System.EventHandler(this.mnuPresetMonochrome_Click);
//
// tpgOverscan
//
this.tpgOverscan.Controls.Add(this.tableLayoutPanel1);
this.tpgOverscan.Location = new System.Drawing.Point(4, 22);
this.tpgOverscan.Name = "tpgOverscan";
this.tpgOverscan.Padding = new System.Windows.Forms.Padding(3);
this.tpgOverscan.Size = new System.Drawing.Size(566, 382);
this.tpgOverscan.TabIndex = 6;
this.tpgOverscan.Text = "Overscan";
this.tpgOverscan.UseVisualStyleBackColor = true;
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 262F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.Controls.Add(this.picOverscan, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel11, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel12, 1, 2);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel13, 2, 1);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel14, 0, 1);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 246F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(560, 376);
this.tableLayoutPanel1.TabIndex = 1;
//
// picOverscan
//
this.picOverscan.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.picOverscan.Dock = System.Windows.Forms.DockStyle.Fill;
this.picOverscan.Location = new System.Drawing.Point(152, 68);
this.picOverscan.Name = "picOverscan";
this.picOverscan.Size = new System.Drawing.Size(256, 240);
this.picOverscan.TabIndex = 1;
this.picOverscan.TabStop = false;
//
// tableLayoutPanel11
//
this.tableLayoutPanel11.ColumnCount = 1;
this.tableLayoutPanel11.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel11.Controls.Add(this.nudOverscanTop, 0, 1);
this.tableLayoutPanel11.Controls.Add(this.lblTop, 0, 0);
this.tableLayoutPanel11.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel11.Location = new System.Drawing.Point(149, 0);
this.tableLayoutPanel11.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel11.Name = "tableLayoutPanel11";
this.tableLayoutPanel11.RowCount = 2;
this.tableLayoutPanel11.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel11.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel11.Size = new System.Drawing.Size(262, 65);
this.tableLayoutPanel11.TabIndex = 4;
//
// nudOverscanTop
//
this.nudOverscanTop.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.nudOverscanTop.DecimalPlaces = 0;
this.nudOverscanTop.Increment = new decimal(new int[] {
1,
0,
0,
0});
this.nudOverscanTop.Location = new System.Drawing.Point(110, 44);
this.nudOverscanTop.Margin = new System.Windows.Forms.Padding(0);
this.nudOverscanTop.Maximum = new decimal(new int[] {
100,
0,
0,
0});
this.nudOverscanTop.MaximumSize = new System.Drawing.Size(10000, 20);
this.nudOverscanTop.Minimum = new decimal(new int[] {
0,
0,
0,
0});
this.nudOverscanTop.MinimumSize = new System.Drawing.Size(0, 21);
this.nudOverscanTop.Name = "nudOverscanTop";
this.nudOverscanTop.Size = new System.Drawing.Size(41, 21);
this.nudOverscanTop.TabIndex = 2;
this.nudOverscanTop.Value = new decimal(new int[] {
0,
0,
0,
0});
this.nudOverscanTop.ValueChanged += new System.EventHandler(this.nudOverscan_ValueChanged);
//
// lblTop
//
this.lblTop.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.lblTop.AutoSize = true;
this.lblTop.Location = new System.Drawing.Point(118, 31);
this.lblTop.Name = "lblTop";
this.lblTop.Size = new System.Drawing.Size(26, 13);
this.lblTop.TabIndex = 0;
this.lblTop.Text = "Top";
this.lblTop.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// tableLayoutPanel12
//
this.tableLayoutPanel12.ColumnCount = 1;
this.tableLayoutPanel12.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel12.Controls.Add(this.nudOverscanBottom, 0, 1);
this.tableLayoutPanel12.Controls.Add(this.lblBottom, 0, 0);
this.tableLayoutPanel12.Location = new System.Drawing.Point(149, 311);
this.tableLayoutPanel12.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel12.Name = "tableLayoutPanel12";
this.tableLayoutPanel12.RowCount = 2;
this.tableLayoutPanel12.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel12.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel12.Size = new System.Drawing.Size(262, 58);
this.tableLayoutPanel12.TabIndex = 5;
//
// nudOverscanBottom
//
this.nudOverscanBottom.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.nudOverscanBottom.DecimalPlaces = 0;
this.nudOverscanBottom.Increment = new decimal(new int[] {
1,
0,
0,
0});
this.nudOverscanBottom.Location = new System.Drawing.Point(110, 13);
this.nudOverscanBottom.Margin = new System.Windows.Forms.Padding(0);
this.nudOverscanBottom.Maximum = new decimal(new int[] {
100,
0,
0,
0});
this.nudOverscanBottom.MaximumSize = new System.Drawing.Size(10000, 20);
this.nudOverscanBottom.Minimum = new decimal(new int[] {
0,
0,
0,
0});
this.nudOverscanBottom.MinimumSize = new System.Drawing.Size(0, 21);
this.nudOverscanBottom.Name = "nudOverscanBottom";
this.nudOverscanBottom.Size = new System.Drawing.Size(41, 21);
this.nudOverscanBottom.TabIndex = 2;
this.nudOverscanBottom.Value = new decimal(new int[] {
0,
0,
0,
0});
this.nudOverscanBottom.ValueChanged += new System.EventHandler(this.nudOverscan_ValueChanged);
//
// lblBottom
//
this.lblBottom.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.lblBottom.AutoSize = true;
this.lblBottom.Location = new System.Drawing.Point(111, 0);
this.lblBottom.Name = "lblBottom";
this.lblBottom.Size = new System.Drawing.Size(40, 13);
this.lblBottom.TabIndex = 0;
this.lblBottom.Text = "Bottom";
this.lblBottom.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// tableLayoutPanel13
//
this.tableLayoutPanel13.ColumnCount = 2;
this.tableLayoutPanel13.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel13.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel13.Controls.Add(this.nudOverscanRight, 0, 2);
this.tableLayoutPanel13.Controls.Add(this.lblRight, 0, 1);
this.tableLayoutPanel13.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel13.Location = new System.Drawing.Point(411, 65);
this.tableLayoutPanel13.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel13.Name = "tableLayoutPanel13";
this.tableLayoutPanel13.RowCount = 4;
this.tableLayoutPanel13.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel13.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel13.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel13.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel13.Size = new System.Drawing.Size(149, 246);
this.tableLayoutPanel13.TabIndex = 6;
//
// nudOverscanRight
//
this.nudOverscanRight.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.nudOverscanRight.DecimalPlaces = 0;
this.nudOverscanRight.Increment = new decimal(new int[] {
1,
0,
0,
0});
this.nudOverscanRight.Location = new System.Drawing.Point(0, 119);
this.nudOverscanRight.Margin = new System.Windows.Forms.Padding(0);
this.nudOverscanRight.Maximum = new decimal(new int[] {
100,
0,
0,
0});
this.nudOverscanRight.MaximumSize = new System.Drawing.Size(10000, 20);
this.nudOverscanRight.Minimum = new decimal(new int[] {
0,
0,
0,
0});
this.nudOverscanRight.MinimumSize = new System.Drawing.Size(0, 21);
this.nudOverscanRight.Name = "nudOverscanRight";
this.nudOverscanRight.Size = new System.Drawing.Size(41, 21);
this.nudOverscanRight.TabIndex = 1;
this.nudOverscanRight.Value = new decimal(new int[] {
0,
0,
0,
0});
this.nudOverscanRight.ValueChanged += new System.EventHandler(this.nudOverscan_ValueChanged);
//
// lblRight
//
this.lblRight.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.lblRight.AutoSize = true;
this.lblRight.Location = new System.Drawing.Point(4, 106);
this.lblRight.Name = "lblRight";
this.lblRight.Size = new System.Drawing.Size(32, 13);
this.lblRight.TabIndex = 0;
this.lblRight.Text = "Right";
this.lblRight.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// tableLayoutPanel14
//
this.tableLayoutPanel14.ColumnCount = 2;
this.tableLayoutPanel14.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel14.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel14.Controls.Add(this.nudOverscanLeft, 1, 2);
this.tableLayoutPanel14.Controls.Add(this.lblLeft, 1, 1);
this.tableLayoutPanel14.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel14.Location = new System.Drawing.Point(0, 65);
this.tableLayoutPanel14.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel14.Name = "tableLayoutPanel14";
this.tableLayoutPanel14.RowCount = 4;
this.tableLayoutPanel14.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel14.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel14.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel14.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel14.Size = new System.Drawing.Size(149, 246);
this.tableLayoutPanel14.TabIndex = 7;
//
// nudOverscanLeft
//
this.nudOverscanLeft.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.nudOverscanLeft.DecimalPlaces = 0;
this.nudOverscanLeft.Increment = new decimal(new int[] {
1,
0,
0,
0});
this.nudOverscanLeft.Location = new System.Drawing.Point(108, 119);
this.nudOverscanLeft.Margin = new System.Windows.Forms.Padding(0);
this.nudOverscanLeft.Maximum = new decimal(new int[] {
100,
0,
0,
0});
this.nudOverscanLeft.MaximumSize = new System.Drawing.Size(10000, 20);
this.nudOverscanLeft.Minimum = new decimal(new int[] {
0,
0,
0,
0});
this.nudOverscanLeft.MinimumSize = new System.Drawing.Size(0, 21);
this.nudOverscanLeft.Name = "nudOverscanLeft";
this.nudOverscanLeft.Size = new System.Drawing.Size(41, 21);
this.nudOverscanLeft.TabIndex = 2;
this.nudOverscanLeft.Value = new decimal(new int[] {
0,
0,
0,
0});
this.nudOverscanLeft.ValueChanged += new System.EventHandler(this.nudOverscan_ValueChanged);
//
// lblLeft
//
this.lblLeft.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.lblLeft.AutoSize = true;
this.lblLeft.Location = new System.Drawing.Point(116, 106);
this.lblLeft.Name = "lblLeft";
this.lblLeft.Size = new System.Drawing.Size(25, 13);
this.lblLeft.TabIndex = 0;
this.lblLeft.Text = "Left";
this.lblLeft.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// frmVideoConfig
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -827,6 +1138,17 @@
this.tableLayoutPanel8.ResumeLayout(false);
this.tableLayoutPanel8.PerformLayout();
this.ctxPicturePresets.ResumeLayout(false);
this.tpgOverscan.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.picOverscan)).EndInit();
this.tableLayoutPanel11.ResumeLayout(false);
this.tableLayoutPanel11.PerformLayout();
this.tableLayoutPanel12.ResumeLayout(false);
this.tableLayoutPanel12.PerformLayout();
this.tableLayoutPanel13.ResumeLayout(false);
this.tableLayoutPanel13.PerformLayout();
this.tableLayoutPanel14.ResumeLayout(false);
this.tableLayoutPanel14.PerformLayout();
this.ResumeLayout(false);
}
@ -881,5 +1203,20 @@
private System.Windows.Forms.ToolStripMenuItem mnuPresetSVideo;
private System.Windows.Forms.ToolStripMenuItem mnuPresetRgb;
private System.Windows.Forms.ToolStripMenuItem mnuPresetMonochrome;
private System.Windows.Forms.TabPage tpgOverscan;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.PictureBox picOverscan;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel11;
private Controls.MesenNumericUpDown nudOverscanTop;
private System.Windows.Forms.Label lblTop;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel12;
private Controls.MesenNumericUpDown nudOverscanBottom;
private System.Windows.Forms.Label lblBottom;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel13;
private Controls.MesenNumericUpDown nudOverscanRight;
private System.Windows.Forms.Label lblRight;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel14;
private Controls.MesenNumericUpDown nudOverscanLeft;
private System.Windows.Forms.Label lblLeft;
}
}

View file

@ -47,6 +47,11 @@ namespace Mesen.GUI.Forms.Config
AddBinding(nameof(VideoConfig.NtscResolution), trkResolution);
AddBinding(nameof(VideoConfig.NtscSharpness), trkSharpness);
AddBinding(nameof(VideoConfig.NtscMergeFields), chkMergeFields);
AddBinding(nameof(VideoConfig.OverscanLeft), nudOverscanLeft);
AddBinding(nameof(VideoConfig.OverscanRight), nudOverscanRight);
AddBinding(nameof(VideoConfig.OverscanTop), nudOverscanTop);
AddBinding(nameof(VideoConfig.OverscanBottom), nudOverscanBottom);
}
protected override bool ValidateInput()
@ -123,5 +128,24 @@ namespace Mesen.GUI.Forms.Config
{
SetNtscPreset(0, -100, 0, 0, 20, 0, 70, -20, -20, -10, 15, false);
}
private void UpdateOverscanImage(PictureBox picture, int top, int bottom, int left, int right)
{
Bitmap overscan = new Bitmap(picture.Width - 2, picture.Height - 2);
using(Graphics g = Graphics.FromImage(overscan)) {
g.Clear(Color.DarkGray);
Rectangle fg = new Rectangle(left, top, 256 - left - right, 240 - top - bottom);
g.ScaleTransform((float)overscan.Width / 256, (float)overscan.Height / 240);
g.FillRectangle(Brushes.LightCyan, fg);
}
picture.Image = overscan;
}
private void nudOverscan_ValueChanged(object sender, EventArgs e)
{
UpdateOverscanImage(picOverscan, (int)nudOverscanTop.Value, (int)nudOverscanBottom.Value, (int)nudOverscanLeft.Value, (int)nudOverscanRight.Value);
}
}
}

View file

@ -57,7 +57,7 @@ namespace Mesen.GUI.Forms
ConfigManager.Config.ApplyConfig();
_displayManager = new DisplayManager(this, ctrlRenderer, pnlRenderer);
_displayManager.UpdateViewerSize(false);
_displayManager.UpdateViewerSize();
_shortcuts = new ShortcutHandler(_displayManager);
_notifListener = new NotificationListener();
@ -112,6 +112,12 @@ namespace Mesen.GUI.Forms
}));
break;
case ConsoleNotificationType.ResolutionChanged:
this.BeginInvoke((Action)(() => {
_displayManager.UpdateViewerSize();
}));
break;
case ConsoleNotificationType.ExecuteShortcut:
this.BeginInvoke((Action)(() => {
_shortcuts.ExecuteShortcut((EmulatorShortcut)e.Parameter);