From 0aaf2b4151fb6932479cb3676007139cd6ab4d66 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 28 Mar 2020 14:48:24 -0500 Subject: [PATCH] DS - rethink ScreenArranger, fix side by side options --- BizHawk.Emulation.Common/ScreenArranger.cs | 102 ++++++++++-------- .../Consoles/Nintendo/NDS/MelonDS.cs | 5 +- .../Consoles/Nintendo/NDS/MelonDS_Settable.cs | 2 - .../Nintendo/NDS/MelonDS_VideoProvider.cs | 28 ++--- .../Nintendo/NDS/VIdeoScreenOptions.cs | 71 ++++++------ 5 files changed, 108 insertions(+), 100 deletions(-) diff --git a/BizHawk.Emulation.Common/ScreenArranger.cs b/BizHawk.Emulation.Common/ScreenArranger.cs index 8b7a713851..b6241bdb4a 100644 --- a/BizHawk.Emulation.Common/ScreenArranger.cs +++ b/BizHawk.Emulation.Common/ScreenArranger.cs @@ -1,64 +1,82 @@ -using System; -using System.Drawing; - -namespace BizHawk.Emulation.Common +namespace BizHawk.Emulation.Common { + public unsafe class VideoScreen + { + public VideoScreen(int* buffer, int width, int height) + { + Buffer = buffer; + Width = width; + Height = height; + } + + public int* Buffer { get; } + public int Width { get; } + public int Height { get; } + + public int Length => Width * Height; + } + /// /// Provides a way to arrange displays inside a frame buffer. /// - public class ScreenArranger + public static class ScreenArranger { - private readonly Size[] _sizes; - - public ScreenArranger(Size[] sizes) + // TODO: pad lines + // TOOD: pass in int[] to reuse buffer + public static unsafe int[] Stack(VideoScreen screen1, VideoScreen screen2, int padLines) { - _sizes = sizes; - } - - public ScreenLayoutSettings LayoutSettings { get; set; } - - public unsafe int[] GenerateFramebuffer(int*[] src, int[] srcLength) - { - if (src.Length != LayoutSettings.Locations.Length) + var ret = new int[screen1.Width * (screen1.Height + screen2.Height)]; + for (int i = 0; i < screen1.Length; i++) { - throw new InvalidCastException("Buffer length mismatch"); + ret[i] = screen1.Buffer[i]; } - var ret = new int[LayoutSettings.FinalSize.Width * LayoutSettings.FinalSize.Height]; - for (int iBuf = 0; iBuf < src.Length; iBuf++) + for (int i = 0; i < screen2.Length; i++) { - int screen = LayoutSettings.Order[iBuf]; - Size size = _sizes[screen]; - Point position = LayoutSettings.Locations[screen]; + ret[screen1.Length + i] = screen2.Buffer[i]; + } - int minSrcX = Math.Max(-position.X, 0); - int maxSrcX = Math.Min(LayoutSettings.FinalSize.Width - position.X, size.Width); - int minDstX = Math.Max(position.X, 0); + return ret; + } - int minSrcY = Math.Max(-position.Y, 0); - int maxSrcY = Math.Min(LayoutSettings.FinalSize.Height - position.Y, size.Height); - int minDstY = Math.Max(position.Y, 0); + // Simply populates a buffer with a single screen + public static unsafe int[] Copy(VideoScreen screen1) + { + var ret = new int[screen1.Length]; - if ((maxSrcX - 1) + (maxSrcY - 1) * size.Width > srcLength[iBuf]) - throw new ArgumentException("The given source buffer is smaller than expected."); + for (int i = 0; i < ret.Length; i++) + { + ret[i] = screen1.Buffer[i]; + } - for (int iY = minSrcY; iY < maxSrcY; iY++) + return ret; + } + + // TODO: pass in int[] to reuse buffer + // TODO: there is a simpler algorithm for sure + public static unsafe int[] SideBySide(VideoScreen screen1, VideoScreen screen2) + { + int width = screen1.Width + screen2.Width; + int height = screen2.Height; + var ret = new int[width * height]; + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) { - int dstIndex = minDstX + (minDstY + iY - minSrcY) * LayoutSettings.FinalSize.Width; - int srcIndex = minSrcX + iY * size.Width; - for (int iX = minSrcX; iX < maxSrcX; iX++) - ret[dstIndex++] = src[screen][srcIndex++]; + if (x < screen1.Width) + { + ret[(y * width) + x] = screen1.Buffer[(y * width / 2) + x]; + } + else + { + ret[(y * width) + x] = screen2.Buffer[(y * width / 2) + x]; + } } + } return ret; } } - - public class ScreenLayoutSettings - { - public Point[] Locations { get; set; } - public int[] Order { get; set; } - public Size FinalSize { get; set; } - } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs index 7cb8074c16..d8067d19f1 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs @@ -108,7 +108,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS throw new Exception("Failed to init NDS."); InitMemoryDomains(); - _screenArranger = new ScreenArranger(new[] { new Size(NativeWidth, NativeHeight), new Size(NativeWidth, NativeHeight) }); PutSettings(settings as MelonSettings); PutSyncSettings(syncsettings as MelonSyncSettings); @@ -119,9 +118,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS } } - public Point? TouchScreenStart => _screenArranger.LayoutSettings.Locations.Length > 1 - ? _screenArranger.LayoutSettings.Locations[1] - : (Point?)null; + public Point? TouchScreenStart => _settings.ScreenOptions.TouchScreenStart(); /// /// MelonDS expects bios and firmware files at a specific location. diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_Settable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_Settable.cs index 5caca31245..c6ef75b8c9 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_Settable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_Settable.cs @@ -32,8 +32,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public bool PutSettings(MelonSettings o) { _settings = o ?? new MelonSettings(); - _screenArranger.LayoutSettings = _settings.ScreenOptions.ToLayout(); - return false; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_VideoProvider.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_VideoProvider.cs index eda13f7df1..0045dade0b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_VideoProvider.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_VideoProvider.cs @@ -1,5 +1,4 @@ -using System.Linq; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using BizHawk.Emulation.Common; @@ -17,8 +16,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public int VirtualWidth => BufferWidth; public int VirtualHeight => BufferHeight; - public int BufferWidth => _screenArranger.LayoutSettings.FinalSize.Width; - public int BufferHeight => _screenArranger.LayoutSettings.FinalSize.Height; + public int BufferWidth => _settings.ScreenOptions.Width(); + public int BufferHeight => _settings.ScreenOptions.Height(); public int VsyncNumerator => 60; @@ -26,8 +25,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public int BackgroundColor => 0; - private readonly ScreenArranger _screenArranger; - [DllImport(dllPath)] private static extern int* GetTopScreenBuffer(); [DllImport(dllPath)] @@ -42,18 +39,21 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS { if (_getNewBuffer) { - // Shenanigans - var buffers = _settings.ScreenOptions.NeedsBottomScreen() - ? new[] {GetTopScreenBuffer(), GetBottomScreenBuffer()} - : new[] {GetTopScreenBuffer()}; - _getNewBuffer = false; - - int bufferSize = GetScreenBufferSize(); - _buffer = _screenArranger.GenerateFramebuffer(buffers, new[] { bufferSize, bufferSize }); + _buffer = _settings.ScreenOptions switch + { + VideoScreenOptions.TopOnly => ScreenArranger.Copy(TopScreen), + VideoScreenOptions.SideBySideLR => ScreenArranger.SideBySide(TopScreen, BottomScreen), + VideoScreenOptions.SideBySideRL => ScreenArranger.SideBySide(BottomScreen, TopScreen), + _ => ScreenArranger.Stack(TopScreen, BottomScreen, 0) + }; } + return _buffer; } + + private VideoScreen TopScreen => new VideoScreen(GetTopScreenBuffer(), NativeWidth, NativeHeight); + private VideoScreen BottomScreen => new VideoScreen(GetBottomScreenBuffer(), NativeWidth, NativeHeight); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/VIdeoScreenOptions.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/VIdeoScreenOptions.cs index e8daf6e96e..67a43eefe5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/VIdeoScreenOptions.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/VIdeoScreenOptions.cs @@ -1,5 +1,4 @@ using System.Drawing; -using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS { @@ -10,49 +9,45 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public static class VideoScreenOptionExtensions { - public static bool NeedsBottomScreen(this VideoScreenOptions option) + public static Point? TouchScreenStart(this VideoScreenOptions option) { - return option != VideoScreenOptions.TopOnly; - } - - public static ScreenLayoutSettings ToLayout(this VideoScreenOptions option) - { - return option switch + switch (option) { - VideoScreenOptions.Default => Default, - VideoScreenOptions.TopOnly => TopOnly, - VideoScreenOptions.SideBySideLR => SideBySideLR, - VideoScreenOptions.SideBySideRL => SideBySideRL, - _ => Default - }; + default: + return new Point(0, MelonDS.NativeHeight); + case VideoScreenOptions.TopOnly: + return null; + case VideoScreenOptions.SideBySideLR: + return new Point(MelonDS.NativeWidth, 0); + case VideoScreenOptions.SideBySideRL: + return new Point(0, 0); + } } - private static ScreenLayoutSettings Default => new ScreenLayoutSettings + public static int Width(this VideoScreenOptions option) { - Locations = new[] { new Point(0, 0), new Point(0, MelonDS.NativeHeight) }, - Order = new[] { 0, 1 }, - FinalSize = new Size(MelonDS.NativeWidth, MelonDS.NativeHeight * 2) - }; + switch (option) + { + default: + return MelonDS.NativeWidth; + case VideoScreenOptions.SideBySideLR: + case VideoScreenOptions.SideBySideRL: + return MelonDS.NativeWidth * 2; + } + } - private static ScreenLayoutSettings TopOnly => new ScreenLayoutSettings + // TODO: padding + public static int Height(this VideoScreenOptions option) { - Locations = new[] { new Point(0, 0) }, - Order = new[] { 0 }, - FinalSize = new Size(MelonDS.NativeWidth, MelonDS.NativeHeight) - }; - - private static ScreenLayoutSettings SideBySideLR => new ScreenLayoutSettings - { - Locations = new[] { new Point(0, 0), new Point(MelonDS.NativeWidth, MelonDS.NativeHeight) }, - Order = new[] { 0, 1 }, - FinalSize = new Size(MelonDS.NativeWidth * 2, MelonDS.NativeHeight) - }; - - private static ScreenLayoutSettings SideBySideRL => new ScreenLayoutSettings - { - Locations = new[] {new Point(MelonDS.NativeWidth, MelonDS.NativeHeight), new Point(0, 0) }, - Order = new[] { 0, 1 }, - FinalSize = new Size(MelonDS.NativeWidth * 2, MelonDS.NativeHeight) - }; + switch (option) + { + default: + return MelonDS.NativeHeight * 2; + case VideoScreenOptions.TopOnly: + case VideoScreenOptions.SideBySideLR: + case VideoScreenOptions.SideBySideRL: + return MelonDS.NativeHeight; + } + } } }