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;
+ }
+ }
}
}