diff --git a/Core/BaseVideoFilter.cpp b/Core/BaseVideoFilter.cpp index 8ca1b24d..4e69bf6e 100644 --- a/Core/BaseVideoFilter.cpp +++ b/Core/BaseVideoFilter.cpp @@ -6,6 +6,7 @@ #include "Console.h" #include "StandardController.h" #include "ScaleFilter.h" +#include "RotateFilter.h" BaseVideoFilter::BaseVideoFilter() { @@ -52,7 +53,6 @@ void BaseVideoFilter::SendFrame(uint16_t *ppuOutputBuffer) UpdateBufferSize(); OnBeforeApplyFilter(); ApplyFilter(ppuOutputBuffer); - _videoHud.DrawHud(GetOutputBuffer(), GetFrameInfo(), GetOverscan()); _frameLock.Release(); } @@ -77,14 +77,25 @@ void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename frameInfo = GetFrameInfo(); } + pngBuffer = frameBuffer; + + uint32_t rotationAngle = EmulationSettings::GetScreenRotation(); + shared_ptr rotateFilter; + if(rotationAngle > 0) { + rotateFilter.reset(new RotateFilter(rotationAngle)); + pngBuffer = rotateFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height); + frameInfo = rotateFilter->GetFrameInfo(frameInfo); + } + shared_ptr scaleFilter = ScaleFilter::GetScaleFilter(filterType); if(scaleFilter) { - pngBuffer = scaleFilter->ApplyFilter(frameBuffer, frameInfo.Width, frameInfo.Height); + pngBuffer = scaleFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height); frameInfo = scaleFilter->GetFrameInfo(frameInfo); - } else { - pngBuffer = frameBuffer; } + VideoHud hud; + hud.DrawHud((uint8_t*)pngBuffer, frameInfo, EmulationSettings::GetOverscanDimensions()); + if(!filename.empty()) { PNGHelper::WritePNG(filename, pngBuffer, frameInfo.Width, frameInfo.Height); } else { diff --git a/Core/BaseVideoFilter.h b/Core/BaseVideoFilter.h index eb930132..8ee8a23b 100644 --- a/Core/BaseVideoFilter.h +++ b/Core/BaseVideoFilter.h @@ -8,7 +8,6 @@ class BaseVideoFilter { private: - VideoHud _videoHud; uint8_t* _outputBuffer = nullptr; uint32_t _bufferSize = 0; SimpleLock _frameLock; diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 39bafc12..c708d660 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -423,6 +423,7 @@ + @@ -845,6 +846,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 5d27322f..33112965 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1243,6 +1243,9 @@ Nes\RomLoader + + VideoDecoder + @@ -1509,5 +1512,8 @@ Misc + + VideoDecoder + \ No newline at end of file diff --git a/Core/EmulationSettings.cpp b/Core/EmulationSettings.cpp index 990f31bc..077077b2 100644 --- a/Core/EmulationSettings.cpp +++ b/Core/EmulationSettings.cpp @@ -74,6 +74,7 @@ PictureSettings EmulationSettings::_pictureSettings; NtscFilterSettings EmulationSettings::_ntscFilterSettings; bool EmulationSettings::_backgroundEnabled = true; bool EmulationSettings::_spritesEnabled = true; +uint32_t EmulationSettings::_screenRotation = 0; ConsoleType EmulationSettings::_consoleType = ConsoleType::Nes; ExpansionPortDevice EmulationSettings::_expansionDevice = ExpansionPortDevice::None; diff --git a/Core/EmulationSettings.h b/Core/EmulationSettings.h index dcc752ac..09c7ad61 100644 --- a/Core/EmulationSettings.h +++ b/Core/EmulationSettings.h @@ -513,6 +513,7 @@ private: static NtscFilterSettings _ntscFilterSettings; static bool _backgroundEnabled; static bool _spritesEnabled; + static uint32_t _screenRotation; static ConsoleType _consoleType; static ExpansionPortDevice _expansionDevice; @@ -1033,6 +1034,16 @@ public: return _videoScale; } + static void SetScreenRotation(uint32_t angle) + { + _screenRotation = angle; + } + + static uint32_t GetScreenRotation() + { + return _screenRotation; + } + static uint32_t* GetRgbPalette() { return _currentPalette; diff --git a/Core/RotateFilter.cpp b/Core/RotateFilter.cpp new file mode 100644 index 00000000..3caa781b --- /dev/null +++ b/Core/RotateFilter.cpp @@ -0,0 +1,75 @@ +#include "RotateFilter.h" +#pragma once + +RotateFilter::RotateFilter(uint32_t angle) +{ + _angle = angle; +} + +RotateFilter::~RotateFilter() +{ + if(_outputBuffer) { + delete[] _outputBuffer; + } +} + +void RotateFilter::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]; + } +} + +uint32_t RotateFilter::GetAngle() +{ + return _angle; +} + +uint32_t * RotateFilter::ApplyFilter(uint32_t * inputArgbBuffer, uint32_t width, uint32_t height) +{ + UpdateOutputBuffer(width, height); + + uint32_t *input = inputArgbBuffer; + if(_angle == 90) { + for(int i = (int)height - 1; i >= 0; i--) { + for(uint32_t j = 0; j < width; j++) { + _outputBuffer[j*height + i] = *input; + input++; + } + } + } else if(_angle == 180) { + for(int i = (int)height - 1; i >= 0; i--) { + for(int j = (int)width - 1; j >= 0; j--) { + _outputBuffer[i * width + j] = *input; + input++; + } + } + } else if(_angle == 270) { + for(uint32_t i = 0; i < height; i++) { + for(uint32_t j = 0; j < width; j++) { + _outputBuffer[j*height + i] = *input; + input++; + } + } + } + + return _outputBuffer; +} + +FrameInfo RotateFilter::GetFrameInfo(FrameInfo baseFrameInfo) +{ + FrameInfo info = baseFrameInfo; + if(_angle % 180) { + info.Height = baseFrameInfo.Width; + info.Width = baseFrameInfo.Height; + info.OriginalHeight = baseFrameInfo.OriginalWidth; + info.OriginalWidth = baseFrameInfo.OriginalHeight; + } + return info; +} diff --git a/Core/RotateFilter.h b/Core/RotateFilter.h new file mode 100644 index 00000000..de9d448c --- /dev/null +++ b/Core/RotateFilter.h @@ -0,0 +1,22 @@ +#pragma once +#include "stdafx.h" +#include "DefaultVideoFilter.h" + +class RotateFilter +{ +private: + uint32_t *_outputBuffer = nullptr; + uint32_t _angle = 0; + uint32_t _width = 0; + uint32_t _height = 0; + + void UpdateOutputBuffer(uint32_t width, uint32_t height); + +public: + RotateFilter(uint32_t angle); + ~RotateFilter(); + + uint32_t GetAngle(); + uint32_t* ApplyFilter(uint32_t *inputArgbBuffer, uint32_t width, uint32_t height); + FrameInfo GetFrameInfo(FrameInfo baseFrameInfo); +}; \ No newline at end of file diff --git a/Core/VideoDecoder.cpp b/Core/VideoDecoder.cpp index 181ee7f2..53fbeb73 100644 --- a/Core/VideoDecoder.cpp +++ b/Core/VideoDecoder.cpp @@ -11,6 +11,7 @@ #include "RewindManager.h" #include "PPU.h" #include "HdNesPack.h" +#include "RotateFilter.h" unique_ptr VideoDecoder::Instance; @@ -43,7 +44,7 @@ VideoDecoder::~VideoDecoder() FrameInfo VideoDecoder::GetFrameInfo() { - return _videoFilter->GetFrameInfo(); + return _lastFrameInfo; } void VideoDecoder::GetScreenSize(ScreenSize &size, bool ignoreScale) @@ -58,6 +59,11 @@ void VideoDecoder::GetScreenSize(ScreenSize &size, bool ignoreScale) if(aspectRatio != 0.0) { size.Width = (uint32_t)(frameInfo.OriginalHeight * scale * aspectRatio * ((double)frameInfo.Width / frameInfo.OriginalWidth)); } + + if(EmulationSettings::GetScreenRotation() % 180) { + std::swap(size.Width, size.Height); + } + size.Scale = scale; } } @@ -86,6 +92,14 @@ void VideoDecoder::UpdateVideoFilter() _hdFilterEnabled = true; } } + + if(EmulationSettings::GetScreenRotation() == 0 && _rotateFilter) { + _rotateFilter.reset(); + } else if(EmulationSettings::GetScreenRotation() > 0) { + if(!_rotateFilter || _rotateFilter->GetAngle() != EmulationSettings::GetScreenRotation()) { + _rotateFilter.reset(new RotateFilter(EmulationSettings::GetScreenRotation())); + } + } } void VideoDecoder::DecodeFrame() @@ -98,10 +112,21 @@ void VideoDecoder::DecodeFrame() _videoFilter->SendFrame(_ppuOutputBuffer); uint32_t* outputBuffer = (uint32_t*)_videoFilter->GetOutputBuffer(); - if(_scaleFilter) { - outputBuffer = _scaleFilter->ApplyFilter(outputBuffer, _videoFilter->GetFrameInfo().Width, _videoFilter->GetFrameInfo().Height); + FrameInfo frameInfo = _videoFilter->GetFrameInfo(); + + if(_rotateFilter) { + outputBuffer = _rotateFilter->ApplyFilter(outputBuffer, frameInfo.Width, frameInfo.Height); + frameInfo = _rotateFilter->GetFrameInfo(frameInfo); } + if(_scaleFilter) { + outputBuffer = _scaleFilter->ApplyFilter(outputBuffer, frameInfo.Width, frameInfo.Height); + frameInfo = _scaleFilter->GetFrameInfo(frameInfo); + } + + VideoHud hud; + hud.DrawHud((uint8_t*)outputBuffer, frameInfo, _videoFilter->GetOverscan()); + ScreenSize screenSize; GetScreenSize(screenSize, true); if(_previousScale != EmulationSettings::GetVideoScale() || screenSize.Height != _previousScreenSize.Height || screenSize.Width != _previousScreenSize.Width) { @@ -110,10 +135,7 @@ void VideoDecoder::DecodeFrame() _previousScale = EmulationSettings::GetVideoScale(); _previousScreenSize = screenSize; - FrameInfo frameInfo = _videoFilter->GetFrameInfo(); - if(_scaleFilter) { - frameInfo = _scaleFilter->GetFrameInfo(frameInfo); - } + _lastFrameInfo = frameInfo; _frameChanged = false; diff --git a/Core/VideoDecoder.h b/Core/VideoDecoder.h index 6de23e2b..7322bd6d 100644 --- a/Core/VideoDecoder.h +++ b/Core/VideoDecoder.h @@ -10,6 +10,7 @@ using std::thread; class BaseVideoFilter; class ScaleFilter; +class RotateFilter; class IRenderingDevice; struct HdPpuPixelInfo; @@ -39,10 +40,12 @@ private: ScreenSize _previousScreenSize = {}; double _previousScale = 0; + FrameInfo _lastFrameInfo; VideoFilterType _videoFilterType = VideoFilterType::None; unique_ptr _videoFilter; shared_ptr _scaleFilter; + shared_ptr _rotateFilter; void UpdateVideoFilter(); diff --git a/Core/VideoHud.cpp b/Core/VideoHud.cpp index a9c69aa7..93c6b4aa 100644 --- a/Core/VideoHud.cpp +++ b/Core/VideoHud.cpp @@ -21,7 +21,8 @@ void VideoHud::DrawHud(uint8_t *outputBuffer, FrameInfo frameInfo, OverscanDimen bool VideoHud::DisplayControllerInput(int inputPort, uint8_t *outputBuffer, FrameInfo &frameInfo, OverscanDimensions &overscan, uint32_t displayIndex) { - int scale = frameInfo.Width / overscan.GetScreenWidth(); + bool axisInverted = (EmulationSettings::GetScreenRotation() % 180) != 0; + int scale = frameInfo.Width / (axisInverted ? overscan.GetScreenHeight() : overscan.GetScreenWidth()); uint32_t* rgbaBuffer = (uint32_t*)outputBuffer; InputDisplaySettings settings = EmulationSettings::GetInputDisplaySettings(); diff --git a/GUI.NET/Config/VideoInfo.cs b/GUI.NET/Config/VideoInfo.cs index c8027519..d1951c6d 100644 --- a/GUI.NET/Config/VideoInfo.cs +++ b/GUI.NET/Config/VideoInfo.cs @@ -20,6 +20,7 @@ namespace Mesen.GUI.Config public VideoFilterType VideoFilter = VideoFilterType.None; public bool UseBilinearInterpolation = false; public VideoAspectRatio AspectRatio = VideoAspectRatio.NoStretching; + public ScreenRotation ScreenRotation = ScreenRotation.None; [MinMax(0.1, 5.0)] public double CustomAspectRatio = 1.0; public bool VerticalSync = false; public bool UseHdPacks = false; @@ -78,6 +79,8 @@ namespace Mesen.GUI.Config InteropEmu.SetOverscanDimensions(videoInfo.OverscanLeft, videoInfo.OverscanRight, videoInfo.OverscanTop, videoInfo.OverscanBottom); + InteropEmu.SetScreenRotation((UInt32)videoInfo.ScreenRotation); + InteropEmu.SetVideoFilter(videoInfo.VideoFilter); InteropEmu.SetVideoResizeFilter(videoInfo.UseBilinearInterpolation ? VideoResizeFilter.Bilinear : VideoResizeFilter.NearestNeighbor); InteropEmu.SetVideoScale(videoInfo.VideoScale <= 10 ? videoInfo.VideoScale : 2); diff --git a/GUI.NET/Dependencies/resources.ca.xml b/GUI.NET/Dependencies/resources.ca.xml index 293c1872..1a41ce23 100644 --- a/GUI.NET/Dependencies/resources.ca.xml +++ b/GUI.NET/Dependencies/resources.ca.xml @@ -292,6 +292,7 @@ Monocrom Avançat + Screen Rotation: Desactiva el fons Desactiva els sprites Força l'aparició del fons a la primera columna @@ -765,6 +766,12 @@ Pantalla panoràmica (16:9) Personalitzat + + None + 90° + 180° + 270° + Cap NTSC diff --git a/GUI.NET/Dependencies/resources.en.xml b/GUI.NET/Dependencies/resources.en.xml index d3fb3dfc..222dbe94 100644 --- a/GUI.NET/Dependencies/resources.en.xml +++ b/GUI.NET/Dependencies/resources.en.xml @@ -170,6 +170,12 @@ Widescreen (16:9) Custom + + None + 90° + 180° + 270° + None NTSC diff --git a/GUI.NET/Dependencies/resources.es.xml b/GUI.NET/Dependencies/resources.es.xml index 9d1d16f0..c5e986fb 100644 --- a/GUI.NET/Dependencies/resources.es.xml +++ b/GUI.NET/Dependencies/resources.es.xml @@ -292,6 +292,7 @@ Monocromo Avanzado + Screen Rotation: Deshabilitar fondo Deshabilitar sprites Forzar ver fondo en primera columna @@ -784,6 +785,12 @@ Pantalla panorámica (16:9) Personalizado + + None + 90° + 180° + 270° + Ninguno NTSC diff --git a/GUI.NET/Dependencies/resources.fr.xml b/GUI.NET/Dependencies/resources.fr.xml index 98093da9..5d312c8d 100644 --- a/GUI.NET/Dependencies/resources.fr.xml +++ b/GUI.NET/Dependencies/resources.fr.xml @@ -294,6 +294,7 @@ Monochrome Avancé + Rotation de l'écran : Désactiver l'arrière-plan Désactiver les sprites Forcer l'affichage de l'arrière-plan dans la première colonne @@ -797,6 +798,12 @@ Écran large (16:9) Personalisé + + Aucune + 90° + 180° + 270° + Aucun NTSC diff --git a/GUI.NET/Dependencies/resources.ja.xml b/GUI.NET/Dependencies/resources.ja.xml index 2c1c0a6f..fb855c46 100644 --- a/GUI.NET/Dependencies/resources.ja.xml +++ b/GUI.NET/Dependencies/resources.ja.xml @@ -296,6 +296,7 @@ モノクロ 詳細設定 + 画面の回転: バックグラウンドを隠す スプライトを隠す ゲームの設定を無視して、画面の一番左側にバックグラウンドを表す @@ -782,6 +783,12 @@ ワイド (16:9) カスタム + + なし + 90度 + 180度 + 270度 + なし NTSC diff --git a/GUI.NET/Dependencies/resources.pt.xml b/GUI.NET/Dependencies/resources.pt.xml index a29fa684..798a9f42 100644 --- a/GUI.NET/Dependencies/resources.pt.xml +++ b/GUI.NET/Dependencies/resources.pt.xml @@ -292,6 +292,7 @@ Monocromo Avançado + Screen Rotation: Desabilitar fundo Desabilitar sprites Forçar ver fundo em primeira coluna @@ -782,6 +783,12 @@ Widescreen (16:9) Personalizado + + None + 90° + 180° + 270° + Nenhum NTSC diff --git a/GUI.NET/Dependencies/resources.ru.xml b/GUI.NET/Dependencies/resources.ru.xml index 6ff44b18..4587b9cc 100644 --- a/GUI.NET/Dependencies/resources.ru.xml +++ b/GUI.NET/Dependencies/resources.ru.xml @@ -294,6 +294,7 @@ Monochrome Advanced + Screen Rotation: Disable background Disable sprites Force background display in first column @@ -787,6 +788,12 @@ Широкий экран (16:9) Custom + + None + 90° + 180° + 270° + Отсутствует NTSC diff --git a/GUI.NET/Dependencies/resources.uk.xml b/GUI.NET/Dependencies/resources.uk.xml index 993b5420..46bd1d3c 100644 --- a/GUI.NET/Dependencies/resources.uk.xml +++ b/GUI.NET/Dependencies/resources.uk.xml @@ -294,6 +294,7 @@ Монохромний Розширенi + Screen Rotation: Відключити фон Відключити спрайти Примусово показувати фон у першому стовпці @@ -787,6 +788,12 @@ Широкий екран (16:9) Custom + + None + 90° + 180° + 270° + Відсутнє NTSC diff --git a/GUI.NET/Forms/Config/frmVideoConfig.Designer.cs b/GUI.NET/Forms/Config/frmVideoConfig.Designer.cs index efede390..18dcc87e 100644 --- a/GUI.NET/Forms/Config/frmVideoConfig.Designer.cs +++ b/GUI.NET/Forms/Config/frmVideoConfig.Designer.cs @@ -44,6 +44,7 @@ namespace Mesen.GUI.Forms.Config 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.tabMain = new System.Windows.Forms.TabControl(); this.tpgGeneral = new System.Windows.Forms.TabPage(); this.tpgPicture = new System.Windows.Forms.TabPage(); @@ -124,7 +125,8 @@ namespace Mesen.GUI.Forms.Config this.mnuPaletteSonyCxa2025As = new System.Windows.Forms.ToolStripMenuItem(); this.mnuPaletteUnsaturated = new System.Windows.Forms.ToolStripMenuItem(); this.mnuPaletteYuv = new System.Windows.Forms.ToolStripMenuItem(); - this.chkIntegerFpsMode = new System.Windows.Forms.CheckBox(); + this.lblScreenRotation = new System.Windows.Forms.Label(); + this.cboScreenRotation = new System.Windows.Forms.ComboBox(); this.tlpMain.SuspendLayout(); this.flowLayoutPanel7.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.picHdNesTooltip)).BeginInit(); @@ -386,6 +388,18 @@ namespace Mesen.GUI.Forms.Config this.chkShowFps.Text = "Show FPS"; this.chkShowFps.UseVisualStyleBackColor = true; // + // 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, 49); + 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; + // // tabMain // this.tabMain.Controls.Add(this.tpgGeneral); @@ -1274,16 +1288,20 @@ namespace Mesen.GUI.Forms.Config // // tableLayoutPanel9 // - this.tableLayoutPanel9.ColumnCount = 1; + this.tableLayoutPanel9.ColumnCount = 2; + this.tableLayoutPanel9.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.tableLayoutPanel9.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel9.Controls.Add(this.chkDisableBackground, 0, 0); - this.tableLayoutPanel9.Controls.Add(this.chkDisableSprites, 0, 1); - this.tableLayoutPanel9.Controls.Add(this.chkForceBackgroundFirstColumn, 0, 2); - this.tableLayoutPanel9.Controls.Add(this.chkForceSpritesFirstColumn, 0, 3); + this.tableLayoutPanel9.Controls.Add(this.chkDisableBackground, 0, 1); + this.tableLayoutPanel9.Controls.Add(this.chkDisableSprites, 0, 2); + this.tableLayoutPanel9.Controls.Add(this.chkForceBackgroundFirstColumn, 0, 3); + this.tableLayoutPanel9.Controls.Add(this.chkForceSpritesFirstColumn, 0, 4); + this.tableLayoutPanel9.Controls.Add(this.lblScreenRotation, 0, 0); + this.tableLayoutPanel9.Controls.Add(this.cboScreenRotation, 1, 0); this.tableLayoutPanel9.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel9.Location = new System.Drawing.Point(3, 3); this.tableLayoutPanel9.Name = "tableLayoutPanel9"; - this.tableLayoutPanel9.RowCount = 5; + this.tableLayoutPanel9.RowCount = 6; + this.tableLayoutPanel9.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel9.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel9.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel9.RowStyles.Add(new System.Windows.Forms.RowStyle()); @@ -1295,8 +1313,9 @@ namespace Mesen.GUI.Forms.Config // chkDisableBackground // this.chkDisableBackground.Checked = false; + this.tableLayoutPanel9.SetColumnSpan(this.chkDisableBackground, 2); this.chkDisableBackground.Dock = System.Windows.Forms.DockStyle.Fill; - this.chkDisableBackground.Location = new System.Drawing.Point(0, 0); + this.chkDisableBackground.Location = new System.Drawing.Point(0, 27); this.chkDisableBackground.MinimumSize = new System.Drawing.Size(0, 21); this.chkDisableBackground.Name = "chkDisableBackground"; this.chkDisableBackground.Size = new System.Drawing.Size(521, 23); @@ -1306,8 +1325,9 @@ namespace Mesen.GUI.Forms.Config // chkDisableSprites // this.chkDisableSprites.Checked = false; + this.tableLayoutPanel9.SetColumnSpan(this.chkDisableSprites, 2); this.chkDisableSprites.Dock = System.Windows.Forms.DockStyle.Fill; - this.chkDisableSprites.Location = new System.Drawing.Point(0, 23); + this.chkDisableSprites.Location = new System.Drawing.Point(0, 50); this.chkDisableSprites.MinimumSize = new System.Drawing.Size(0, 21); this.chkDisableSprites.Name = "chkDisableSprites"; this.chkDisableSprites.Size = new System.Drawing.Size(521, 23); @@ -1317,8 +1337,9 @@ namespace Mesen.GUI.Forms.Config // chkForceBackgroundFirstColumn // this.chkForceBackgroundFirstColumn.Checked = false; + this.tableLayoutPanel9.SetColumnSpan(this.chkForceBackgroundFirstColumn, 2); this.chkForceBackgroundFirstColumn.Dock = System.Windows.Forms.DockStyle.Fill; - this.chkForceBackgroundFirstColumn.Location = new System.Drawing.Point(0, 46); + this.chkForceBackgroundFirstColumn.Location = new System.Drawing.Point(0, 73); this.chkForceBackgroundFirstColumn.MinimumSize = new System.Drawing.Size(0, 21); this.chkForceBackgroundFirstColumn.Name = "chkForceBackgroundFirstColumn"; this.chkForceBackgroundFirstColumn.Size = new System.Drawing.Size(521, 23); @@ -1328,8 +1349,9 @@ namespace Mesen.GUI.Forms.Config // chkForceSpritesFirstColumn // this.chkForceSpritesFirstColumn.Checked = false; + this.tableLayoutPanel9.SetColumnSpan(this.chkForceSpritesFirstColumn, 2); this.chkForceSpritesFirstColumn.Dock = System.Windows.Forms.DockStyle.Fill; - this.chkForceSpritesFirstColumn.Location = new System.Drawing.Point(0, 69); + this.chkForceSpritesFirstColumn.Location = new System.Drawing.Point(0, 96); this.chkForceSpritesFirstColumn.MinimumSize = new System.Drawing.Size(0, 21); this.chkForceSpritesFirstColumn.Name = "chkForceSpritesFirstColumn"; this.chkForceSpritesFirstColumn.Size = new System.Drawing.Size(521, 23); @@ -1459,17 +1481,24 @@ namespace Mesen.GUI.Forms.Config this.mnuPaletteYuv.Text = "YUV v3 (by FirebrandX)"; this.mnuPaletteYuv.Click += new System.EventHandler(this.mnuPaletteYuv_Click); // - // chkIntegerFpsMode + // lblScreenRotation // - 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, 49); - this.chkIntegerFpsMode.Name = "chkIntegerFpsMode"; - this.chkIntegerFpsMode.Size = new System.Drawing.Size(295, 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.lblScreenRotation.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblScreenRotation.AutoSize = true; + this.lblScreenRotation.Location = new System.Drawing.Point(3, 7); + this.lblScreenRotation.Name = "lblScreenRotation"; + this.lblScreenRotation.Size = new System.Drawing.Size(87, 13); + this.lblScreenRotation.TabIndex = 4; + this.lblScreenRotation.Text = "Screen Rotation:"; + // + // cboScreenRotation + // + this.cboScreenRotation.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cboScreenRotation.FormattingEnabled = true; + this.cboScreenRotation.Location = new System.Drawing.Point(96, 3); + this.cboScreenRotation.Name = "cboScreenRotation"; + this.cboScreenRotation.Size = new System.Drawing.Size(77, 21); + this.cboScreenRotation.TabIndex = 5; // // frmVideoConfig // @@ -1528,6 +1557,7 @@ namespace Mesen.GUI.Forms.Config this.tableLayoutPanel2.PerformLayout(); this.tpgAdvanced.ResumeLayout(false); this.tableLayoutPanel9.ResumeLayout(false); + this.tableLayoutPanel9.PerformLayout(); this.contextPicturePresets.ResumeLayout(false); this.contextPaletteList.ResumeLayout(false); this.ResumeLayout(false); @@ -1631,5 +1661,7 @@ namespace Mesen.GUI.Forms.Config private System.Windows.Forms.CheckBox chkShowColorIndexes; private Debugger.ctrlPaletteDisplay ctrlPaletteDisplay; private System.Windows.Forms.CheckBox chkIntegerFpsMode; + private System.Windows.Forms.Label lblScreenRotation; + private System.Windows.Forms.ComboBox cboScreenRotation; } } \ No newline at end of file diff --git a/GUI.NET/Forms/Config/frmVideoConfig.cs b/GUI.NET/Forms/Config/frmVideoConfig.cs index 5eb2935d..ddbdadcb 100644 --- a/GUI.NET/Forms/Config/frmVideoConfig.cs +++ b/GUI.NET/Forms/Config/frmVideoConfig.cs @@ -36,6 +36,8 @@ namespace Mesen.GUI.Forms.Config AddBinding("CustomAspectRatio", nudCustomRatio); AddBinding("VideoFilter", cboFilter); + AddBinding("ScreenRotation", cboScreenRotation); + AddBinding("OverscanLeft", nudOverscanLeft); AddBinding("OverscanRight", nudOverscanRight); AddBinding("OverscanTop", nudOverscanTop); diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 8df87f4b..62d24055 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -166,6 +166,7 @@ namespace Mesen.GUI [DllImport(DLLPath)] public static extern void SetPpuNmiConfig(UInt32 extraScanlinesBeforeNmi, UInt32 extraScanlineAfterNmi); [DllImport(DLLPath)] public static extern void SetOverscanDimensions(UInt32 left, UInt32 right, UInt32 top, UInt32 bottom); [DllImport(DLLPath)] public static extern void SetVideoScale(double scale); + [DllImport(DLLPath)] public static extern void SetScreenRotation(UInt32 angle); [DllImport(DLLPath)] public static extern void SetVideoAspectRatio(VideoAspectRatio aspectRatio, double customRatio); [DllImport(DLLPath)] public static extern void SetVideoFilter(VideoFilterType filter); [DllImport(DLLPath)] public static extern void SetVideoResizeFilter(VideoResizeFilter filter); @@ -1777,6 +1778,14 @@ namespace Mesen.GUI Custom = 6 } + public enum ScreenRotation + { + None = 0, + _90Degrees = 90, + _180Degrees = 180, + _270Degrees = 270 + } + public enum DebugMemoryType { CpuMemory = 0, diff --git a/InteropDLL/ConsoleWrapper.cpp b/InteropDLL/ConsoleWrapper.cpp index 1e337260..8fe7319d 100644 --- a/InteropDLL/ConsoleWrapper.cpp +++ b/InteropDLL/ConsoleWrapper.cpp @@ -431,6 +431,7 @@ namespace InteropEmu { DllExport void __stdcall SetOverclockRate(uint32_t overclockRate, bool adjustApu) { EmulationSettings::SetOverclockRate(overclockRate, adjustApu); } DllExport void __stdcall SetPpuNmiConfig(uint32_t extraScanlinesBeforeNmi, uint32_t extraScanlinesAfterNmi) { EmulationSettings::SetPpuNmiConfig(extraScanlinesBeforeNmi, extraScanlinesAfterNmi); } DllExport void __stdcall SetVideoScale(double scale) { EmulationSettings::SetVideoScale(scale); } + DllExport void __stdcall SetScreenRotation(uint32_t angle) { EmulationSettings::SetScreenRotation(angle); } DllExport void __stdcall SetVideoAspectRatio(VideoAspectRatio aspectRatio, double customRatio) { EmulationSettings::SetVideoAspectRatio(aspectRatio, customRatio); } DllExport void __stdcall SetVideoFilter(VideoFilterType filter) { EmulationSettings::SetVideoFilterType(filter); } DllExport void __stdcall SetVideoResizeFilter(VideoResizeFilter filter) { EmulationSettings::SetVideoResizeFilter(filter); }