diff --git a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs
index 3f8b69b826..cac10512d7 100644
--- a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs
+++ b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs
@@ -14,6 +14,7 @@ using BizHawk.Client.EmuHawk.FilterManager;
using BizHawk.Common.PathExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Sony.PSX;
+using BizHawk.Emulation.Cores.Consoles.Nintendo.NDS;
using OpenTK;
@@ -395,7 +396,12 @@ namespace BizHawk.Client.EmuHawk
Vector2 v = new Vector2(p.X, p.Y);
v = _currentFilterProgram.UntransformPoint("default", v);
if (Global.Emulator.SystemId == "NDS")
- v.Y = 2 * v.Y - (Global.Emulator as IVideoProvider).BufferHeight;
+ {
+ MelonDS core = Global.Emulator as MelonDS;
+ Point touchLocation = core.GetSettings().screenOptions.locations[1];
+ v.Y = (int)((double)core.BufferHeight / MelonDS.NATIVE_HEIGHT * (v.Y - touchLocation.Y));
+ v.X = (int)((double)core.BufferWidth / MelonDS.NATIVE_WIDTH * (v.X - touchLocation.X));
+ }
return new Point((int)v.X, (int)v.Y);
}
diff --git a/BizHawk.Emulation.Common/ScreenArranger.cs b/BizHawk.Emulation.Common/ScreenArranger.cs
new file mode 100644
index 0000000000..e05c0bd13c
--- /dev/null
+++ b/BizHawk.Emulation.Common/ScreenArranger.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+///
+/// Provides a way to arrange displays inside a frame buffer.
+///
+namespace BizHawk.Emulation.Common
+{
+ public class ScreenArranger
+ {
+ public ScreenLayoutSettings layoutSettings;
+ private Size[] sizes;
+
+ public ScreenArranger(Size[] sizes)
+ {
+ this.sizes = sizes;
+ }
+
+ public unsafe int[] GenerateFramebuffer(int*[] src, int[] srcLength)
+ {
+ if (src.Length != layoutSettings.locations.Length)
+ return null;
+
+ int[] ret = new int[layoutSettings.finalSize.Width * layoutSettings.finalSize.Height];
+ for (int iBuf = 0; iBuf < src.Length; iBuf++)
+ {
+ int screen = layoutSettings.order[iBuf];
+ Size size = sizes[screen];
+ Point position = layoutSettings.locations[screen];
+
+ 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);
+
+ 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);
+
+ if ((maxSrcX - 1) + (maxSrcY - 1) * size.Width > srcLength[iBuf])
+ throw new ArgumentException("The given source buffer is smaller than expected.");
+
+ for (int iY = minSrcY; iY < maxSrcY; iY++)
+ {
+ 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++];
+ }
+ }
+
+ return ret;
+ }
+
+ public unsafe int[] GenerateFramebuffer(int[][] src)
+ {
+ GCHandle[] handles = new GCHandle[src.Length];
+ try
+ {
+ for (int i = 0; i < src.Length; i++)
+ handles[i] = GCHandle.Alloc(src[i], GCHandleType.Pinned);
+
+ int*[] srcBuffers = new int*[src.Length];
+ int[] lengths = new int[src.Length];
+ for (int i = 0; i < src.Length; i++)
+ {
+ srcBuffers[i] = (int*)handles[i].AddrOfPinnedObject();
+ lengths[i] = src[i].Length;
+ }
+
+ return GenerateFramebuffer(srcBuffers, lengths);
+ }
+ finally
+ { // unpin the memory
+ foreach (var h in handles)
+ if (h.IsAllocated) h.Free();
+ }
+ }
+ }
+
+ public class ScreenLayoutSettings
+ {
+ public Point[] locations;
+ public int[] order;
+ public Size finalSize;
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs
index 4d2af81548..924e0cbcef 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.cs
@@ -1,18 +1,23 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
+using System.Drawing;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
{
- [Core("MelonDS", "Arisotura", isPorted: true, isReleased: false, "0.8.4-bizhawk-cbd9adac3", "https://github.com/TASVideos/melonDS", singleInstance: true)]
- public unsafe partial class MelonDS : IEmulator
+ [Core("MelonDS", "Arisotura", false, false, null, null, true)]
+ unsafe public partial class MelonDS : IEmulator
{
- private readonly BasicServiceProvider _serviceProvider;
+ private BasicServiceProvider _serviceProvider;
public IEmulatorServiceProvider ServiceProvider => _serviceProvider;
- public ControllerDefinition ControllerDefinition { get; }
+ public ControllerDefinition ControllerDefinition { get; private set; }
public int Frame => GetFrameCount();
@@ -20,7 +25,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
public bool DeterministicEmulation => true;
- internal CoreComm CoreComm { get; }
+ public CoreComm CoreComm { get; private set; }
public void Dispose()
{
@@ -68,18 +73,19 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
private static extern void FrameAdvance(short buttons, byte touchX, byte touchY);
[CoreConstructor("NDS")]
- public MelonDS(byte[] file, CoreComm comm, object settings, object syncSettings)
+ public MelonDS(byte[] file, CoreComm comm, object settings, object syncsettings)
{
_serviceProvider = new BasicServiceProvider(this);
- ControllerDefinition = new ControllerDefinition { Name = "NDS Controller" };
+ ControllerDefinition = new ControllerDefinition();
+ ControllerDefinition.Name = "NDS Controller";
+ ControllerDefinition.BoolButtons.Add("Left");
+ ControllerDefinition.BoolButtons.Add("Right");
ControllerDefinition.BoolButtons.Add("Up");
ControllerDefinition.BoolButtons.Add("Down");
- ControllerDefinition.BoolButtons.Add("Right");
- ControllerDefinition.BoolButtons.Add("Left");
- ControllerDefinition.BoolButtons.Add("Y");
+ ControllerDefinition.BoolButtons.Add("A");
ControllerDefinition.BoolButtons.Add("B");
ControllerDefinition.BoolButtons.Add("X");
- ControllerDefinition.BoolButtons.Add("A");
+ ControllerDefinition.BoolButtons.Add("Y");
ControllerDefinition.BoolButtons.Add("L");
ControllerDefinition.BoolButtons.Add("R");
ControllerDefinition.BoolButtons.Add("Start");
@@ -95,14 +101,16 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
CoreComm = comm;
+ SetUpFiles();
if (!Init())
throw new Exception("Failed to init NDS.");
-
- SetUpFiles();
- PutSyncSettings(syncSettings as MelonSyncSettings);
-
InitMemoryDomains();
+ screenArranger = new ScreenArranger(new Size[] { new Size(NATIVE_WIDTH, NATIVE_HEIGHT), new Size(NATIVE_WIDTH, NATIVE_HEIGHT) });
+ PutSettings(settings as MelonSettings);
+ PutSyncSettings(syncsettings as MelonSyncSettings);
+
+
fixed (byte* f = file)
{
LoadROM(f, file.Length);
@@ -160,7 +168,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
byte[] bytes = File.ReadAllBytes(firmwarePath);
// There are two regions for user settings
- int settingsLength = getUserSettingsLength();
+ int settingsLength = GetUserSettingsLength();
for (int i = bytes.Length - 0x200; i < bytes.Length - 0x200 + settingsLength; i++)
bytes[i] = 0xFF;
for (int i = bytes.Length - 0x100; i < bytes.Length - 0x100 + settingsLength; i++)
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_Settable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_Settable.cs
index a077d71831..e05a66e17b 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_Settable.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_Settable.cs
@@ -1,15 +1,21 @@
using System;
using System.Text;
using System.Runtime.InteropServices;
+using System.Drawing;
using BizHawk.Emulation.Common;
using Newtonsoft.Json;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
{
- unsafe partial class MelonDS : ISettable