This commit is contained in:
emmauss 2018-07-26 17:24:54 +00:00 committed by GitHub
commit 4dab29ffa4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 4893 additions and 118 deletions

View file

@ -8,6 +8,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Threading;
namespace ChocolArm64
{
@ -21,6 +22,8 @@ namespace ChocolArm64
public bool EnableCpuTrace { get; set; }
private ManualResetEvent PauseResetEvent = new ManualResetEvent(true);
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
{
CachedSubs = new ConcurrentDictionary<long, ATranslatedSub>();
@ -60,6 +63,8 @@ namespace ChocolArm64
AOpCode OpCode = ADecoder.DecodeOpCode(State, Memory, State.R15);
OpCode.Interpreter(State, Memory, OpCode);
PauseResetEvent.WaitOne();
}
while (State.R15 != 0 && State.Running);
}
@ -89,6 +94,8 @@ namespace ChocolArm64
}
Position = Sub.Execute(State, Memory);
PauseResetEvent.WaitOne();
}
while (Position != 0 && State.Running);
}
@ -202,5 +209,15 @@ namespace ChocolArm64
}
}
}
public void Pause()
{
PauseResetEvent.Reset();
}
public void Resume()
{
PauseResetEvent.Set();
}
}
}

View file

@ -1,6 +1,8 @@
using System;
namespace Ryujinx.Audio
{
public interface IAalOutput
public interface IAalOutput : IDisposable
{
int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback);

View file

@ -341,5 +341,30 @@ namespace Ryujinx.Audio.OpenAL
return PlaybackState.Stopped;
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
KeepPolling = false;
foreach (var Track in Tracks)
{
if (Track.Value.State == PlaybackState.Playing)
Stop(Track.Key);
Track.Value.Dispose();
}
Tracks.Clear();
Context.Dispose();
}
}
public void Dispose()
{
Dispose(true);
}
}
}

View file

@ -5,7 +5,7 @@ using System.Threading;
namespace Ryujinx
{
static class ConsoleLog
public static class ConsoleLog
{
private static Dictionary<LogLevel, ConsoleColor> LogColors;

View file

@ -0,0 +1,28 @@
namespace Ryujinx.Common.Input
{
public enum GamePadButton
{
A,
B,
X,
Y,
LStick,
RStick,
LShoulder,
RShoulder,
DPadUp,
DPadDown,
DPadLeft,
DPadRight,
Start,
Back,
LTrigger,
RTrigger,
}
public enum GamePadStick
{
LJoystick,
RJoystick
}
}

View file

@ -0,0 +1,34 @@
namespace Ryujinx.Common.Input
{
public struct JoyConControllerLeft
{
public GamePadStick Stick;
public GamePadButton StickButton;
public GamePadButton DPadUp;
public GamePadButton DPadDown;
public GamePadButton DPadLeft;
public GamePadButton DPadRight;
public GamePadButton ButtonMinus;
public GamePadButton ButtonL;
public GamePadButton ButtonZL;
}
public struct JoyConControllerRight
{
public GamePadStick Stick;
public GamePadButton StickButton;
public GamePadButton ButtonA;
public GamePadButton ButtonB;
public GamePadButton ButtonX;
public GamePadButton ButtonY;
public GamePadButton ButtonPlus;
public GamePadButton ButtonR;
public GamePadButton ButtonZR;
}
public struct JoyConController
{
public JoyConControllerLeft Left;
public JoyConControllerRight Right;
}
}

View file

@ -1,4 +1,4 @@
namespace Ryujinx.UI.Input
namespace Ryujinx.Common.Input
{
public struct JoyConKeyboardLeft
{

View file

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
</ItemGroup>
</Project>

View file

@ -2,7 +2,7 @@ using System;
namespace Ryujinx.Graphics.Gal
{
public interface IGalRenderer
public interface IGalRenderer : IDisposable
{
void QueueAction(Action ActionMthd);

View file

@ -46,5 +46,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
RenderAction();
}
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
ActionsQueue.Clear();
}
}
}
}

View file

@ -1,9 +1,10 @@
using Ryujinx.Graphics.Gal;
using Ryujinx.HLE.Gpu.Engines;
using System;
namespace Ryujinx.HLE.Gpu
{
class NvGpu
class NvGpu : IDisposable
{
public IGalRenderer Renderer { get; private set; }
@ -23,5 +24,10 @@ namespace Ryujinx.HLE.Gpu
Engine3d = new NvGpuEngine3d(this);
EngineDma = new NvGpuEngineDma(this);
}
public void Dispose()
{
Renderer.Dispose();
}
}
}

View file

@ -2,7 +2,7 @@ using System.IO;
namespace Ryujinx.HLE.Loaders.Executables
{
class Nro : IExecutable
public class Nro : IExecutable
{
public string FilePath { get; private set; }
@ -15,10 +15,11 @@ namespace Ryujinx.HLE.Loaders.Executables
public int ROOffset { get; private set; }
public int DataOffset { get; private set; }
public int BssSize { get; private set; }
public int FileSize { get; private set; }
public Nro(Stream Input, string FilePath)
{
this.FilePath = FilePath;
this.FilePath = this.FilePath;
BinaryReader Reader = new BinaryReader(Input);
@ -44,6 +45,7 @@ namespace Ryujinx.HLE.Loaders.Executables
this.ROOffset = ROOffset;
this.DataOffset = DataOffset;
this.BssSize = BssSize;
this.FileSize = FileSize;
byte[] Read(long Position, int Size)
{

View file

@ -43,6 +43,16 @@ namespace Ryujinx.HLE.Logging
EnabledClasses[(int)Class] = Enabled;
}
public bool IsEnabled(LogLevel LogLevel)
{
return EnabledLevels[(int)LogLevel];
}
public bool IsFiltered(LogClass LogClass)
{
return EnabledClasses[(int)LogClass];
}
internal void PrintDebug(LogClass Class, string Message, [CallerMemberName] string Caller = "")
{
Print(LogLevel.Debug, Class, GetFormattedMessage(Class, Message, Caller));

View file

@ -18,6 +18,8 @@ namespace Ryujinx.HLE.OsHle
private ConcurrentDictionary<int, Process> Processes;
private bool IsDisposing;
public SystemStateMgr SystemState { get; private set; }
internal MemoryAllocator Allocator { get; private set; }
@ -147,6 +149,22 @@ namespace Ryujinx.HLE.OsHle
return Process;
}
public void PauseAllProcesses()
{
foreach (Process Process in Processes.Values)
{
Process.Pause();
}
}
public void ResumeAllProcesses()
{
foreach (Process Process in Processes.Values)
{
Process.Resume();
}
}
private void InitializeProcess(Process Process)
{
Process.AppletState.SetFocus(true);
@ -154,7 +172,7 @@ namespace Ryujinx.HLE.OsHle
internal void ExitProcess(int ProcessId)
{
if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi && !IsDisposing)
{
string NextNro = Homebrew.ReadHbAbiNextLoadPath(Process.Memory, Process.HbAbiDataPosition);
@ -178,7 +196,6 @@ namespace Ryujinx.HLE.OsHle
if (Processes.TryRemove(ProcessId, out Process))
{
Process.StopAllThreadsAsync();
Process.Dispose();
if (Processes.Count == 0)
{
@ -199,6 +216,8 @@ namespace Ryujinx.HLE.OsHle
protected virtual void Dispose(bool Disposing)
{
IsDisposing = Disposing;
if (Disposing)
{
foreach (Process Process in Processes.Values)

View file

@ -169,6 +169,26 @@ namespace Ryujinx.HLE.OsHle
return true;
}
public void Pause()
{
if (Disposed)
{
throw new ObjectDisposedException(nameof(Process));
}
Translator.Pause();
}
public void Resume()
{
if (Disposed)
{
throw new ObjectDisposedException(nameof(Process));
}
Translator.Resume();
}
private void MapRWMemRegion(long Position, long Size, MemoryType Type)
{
Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW);
@ -178,7 +198,7 @@ namespace Ryujinx.HLE.OsHle
{
if (Disposed)
{
throw new ObjectDisposedException(nameof(Process));
return;
}
if (MainThread != null)
@ -403,6 +423,8 @@ namespace Ryujinx.HLE.OsHle
{
if (Disposing && !Disposed)
{
Translator.Resume();
//If there is still some thread running, disposing the objects is not
//safe as the thread may try to access those resources. Instead, we set
//the flag to have the Process disposed when all threads finishes.

View file

@ -98,6 +98,8 @@ namespace Ryujinx.HLE
{
Os.Dispose();
VFs.Dispose();
Gpu.Dispose();
AudioOut.Dispose();
}
}
}

View file

@ -3,7 +3,7 @@ using System.IO;
namespace Ryujinx.HLE
{
class VirtualFileSystem : IDisposable
public class VirtualFileSystem : IDisposable
{
private const string BasePath = "RyuFs";
private const string NandPath = "nand";

315
Ryujinx.UI/Config.cs Normal file
View file

@ -0,0 +1,315 @@
using Ryujinx.Common.Input;
using Ryujinx.HLE;
using Ryujinx.HLE.Logging;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Ryujinx
{
public static class Config
{
public static JoyConKeyboard JoyConKeyboard { get; set; }
public static JoyConController JoyConController { get; set; }
public static float GamePadDeadzone { get; set; }
public static bool GamePadEnable { get; set; }
public static int GamePadIndex { get; set; }
public static float GamePadTriggerThreshold { get; set; }
public static string IniPath { get; set; }
public static string DefaultGameDirectory { get; set; }
public static void Read(Logger Log)
{
string IniFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
IniPath = Path.Combine(IniFolder, "RyujinxUI.conf");
IniParser Parser = new IniParser(IniPath);
AOptimizations.DisableMemoryChecks = !Convert.ToBoolean(Parser.GetValue("Enable_Memory_Checks"));
Log.SetEnable(LogLevel.Debug, Convert.ToBoolean(Parser.GetValue("Logging_Enable_Debug")));
Log.SetEnable(LogLevel.Stub, Convert.ToBoolean(Parser.GetValue("Logging_Enable_Stub")));
Log.SetEnable(LogLevel.Info, Convert.ToBoolean(Parser.GetValue("Logging_Enable_Info")));
Log.SetEnable(LogLevel.Warning, Convert.ToBoolean(Parser.GetValue("Logging_Enable_Warn")));
Log.SetEnable(LogLevel.Error, Convert.ToBoolean(Parser.GetValue("Logging_Enable_Error")));
GamePadEnable = Convert.ToBoolean(Parser.GetValue("GamePad_Enable"));
GamePadIndex = Convert.ToInt32 (Parser.GetValue("GamePad_Index"));
GamePadDeadzone = (float)Convert.ToDouble (Parser.GetValue("GamePad_Deadzone"), CultureInfo.InvariantCulture);
GamePadTriggerThreshold = (float)Convert.ToDouble (Parser.GetValue("GamePad_Trigger_Threshold"), CultureInfo.InvariantCulture);
string[] FilteredLogClasses = Parser.GetValue("Logging_Filtered_Classes").Split(',', StringSplitOptions.RemoveEmptyEntries);
//When the classes are specified on the list, we only
//enable the classes that are on the list.
//So, first disable everything, then enable
//the classes that the user added to the list.
if (FilteredLogClasses.Length > 0)
{
foreach (LogClass Class in Enum.GetValues(typeof(LogClass)))
{
Log.SetEnable(Class, false);
}
}
foreach (string LogClass in FilteredLogClasses)
{
if (!string.IsNullOrEmpty(LogClass.Trim()))
{
foreach (LogClass Class in Enum.GetValues(typeof(LogClass)))
{
if (Class.ToString().ToLower().Contains(LogClass.Trim().ToLower()))
{
Log.SetEnable(Class, true);
}
}
}
}
JoyConKeyboard = new JoyConKeyboard
{
Left = new JoyConKeyboardLeft
{
StickUp = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Stick_Up")),
StickDown = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Stick_Down")),
StickLeft = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Stick_Left")),
StickRight = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Stick_Right")),
StickButton = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Stick_Button")),
DPadUp = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_DPad_Up")),
DPadDown = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_DPad_Down")),
DPadLeft = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_DPad_Left")),
DPadRight = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_DPad_Right")),
ButtonMinus = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Button_Minus")),
ButtonL = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Button_L")),
ButtonZL = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Button_ZL"))
},
Right = new JoyConKeyboardRight
{
StickUp = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Stick_Up")),
StickDown = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Stick_Down")),
StickLeft = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Stick_Left")),
StickRight = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Stick_Right")),
StickButton = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Stick_Button")),
ButtonA = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_A")),
ButtonB = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_B")),
ButtonX = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_X")),
ButtonY = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_Y")),
ButtonPlus = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_Plus")),
ButtonR = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_R")),
ButtonZR = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_ZR"))
}
};
JoyConController = new JoyConController
{
Left = new JoyConControllerLeft
{
Stick = Enum.Parse<GamePadStick>(Parser.GetValue("Controls_Left_JoyConController_Stick")),
StickButton = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_Stick_Button")),
DPadUp = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_DPad_Up")),
DPadDown = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_DPad_Down")),
DPadLeft = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_DPad_Left")),
DPadRight = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_DPad_Right")),
ButtonMinus = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_Button_Minus")),
ButtonL = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_Button_L")),
ButtonZL = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_Button_ZL"))
},
Right = new JoyConControllerRight
{
Stick = Enum.Parse<GamePadStick>(Parser.GetValue("Controls_Right_JoyConController_Stick")),
StickButton = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Stick_Button")),
ButtonA = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_A")),
ButtonB = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_B")),
ButtonX = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_X")),
ButtonY = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_Y")),
ButtonPlus = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_Plus")),
ButtonR = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_R")),
ButtonZR = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_ZR"))
}
};
DefaultGameDirectory = Parser.GetValue("Default_Game_Directory");
VirtualFileSystem FS = new HLE.VirtualFileSystem();
if (string.IsNullOrWhiteSpace(DefaultGameDirectory))
{
DefaultGameDirectory = Path.Combine(FS.GetSdCardPath(), "switch");
}
if (!Directory.Exists(DefaultGameDirectory))
{
if (!Directory.CreateDirectory(DefaultGameDirectory).Exists)
{
DefaultGameDirectory = Path.Combine(FS.GetSdCardPath(), "switch");
Directory.CreateDirectory(DefaultGameDirectory);
}
}
}
public static void Save(Logger Log)
{
IniParser Parser = new IniParser(IniPath);
Parser.SetValue("Enable_Memory_Checks", (!AOptimizations.DisableMemoryChecks).ToString());
Parser.SetValue("Logging_Enable_Debug", Log.IsEnabled(LogLevel.Debug).ToString());
Parser.SetValue("Logging_Enable_Stub", Log.IsEnabled(LogLevel.Stub).ToString());
Parser.SetValue("Logging_Enable_Info", Log.IsEnabled(LogLevel.Info).ToString());
Parser.SetValue("Logging_Enable_Warn", Log.IsEnabled(LogLevel.Warning).ToString());
Parser.SetValue("Logging_Enable_Error", Log.IsEnabled(LogLevel.Error).ToString());
List<string> FilteredClasses = new List<string>();
foreach(LogClass LogClass in Enum.GetValues(typeof(LogClass)))
{
if (Log.IsFiltered(LogClass))
FilteredClasses.Add(LogClass.ToString());
}
Parser.SetValue("Logging_Filtered_Classes", string.Join(',', FilteredClasses));
Parser.SetValue("Controls_Left_JoyConKeyboard_Stick_Up", JoyConKeyboard.Left.StickUp.ToString());
Parser.SetValue("Controls_Left_JoyConKeyboard_Stick_Down", JoyConKeyboard.Left.StickDown.ToString());
Parser.SetValue("Controls_Left_JoyConKeyboard_Stick_Left", JoyConKeyboard.Left.StickLeft.ToString());
Parser.SetValue("Controls_Left_JoyConKeyboard_Stick_Right", JoyConKeyboard.Left.StickRight.ToString());
Parser.SetValue("Controls_Left_JoyConKeyboard_Stick_Button", JoyConKeyboard.Left.StickButton.ToString());
Parser.SetValue("Controls_Left_JoyConKeyboard_DPad_Up", JoyConKeyboard.Left.DPadUp.ToString());
Parser.SetValue("Controls_Left_JoyConKeyboard_DPad_Down", JoyConKeyboard.Left.DPadDown.ToString());
Parser.SetValue("Controls_Left_JoyConKeyboard_DPad_Left", JoyConKeyboard.Left.DPadLeft.ToString());
Parser.SetValue("Controls_Left_JoyConKeyboard_DPad_Right", JoyConKeyboard.Left.DPadRight.ToString());
Parser.SetValue("Controls_Left_JoyConKeyboard_Button_Minus", JoyConKeyboard.Left.ButtonMinus.ToString());
Parser.SetValue("Controls_Left_JoyConKeyboard_Button_L", JoyConKeyboard.Left.ButtonL.ToString());
Parser.SetValue("Controls_Left_JoyConKeyboard_Button_ZL", JoyConKeyboard.Left.ButtonZL.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Stick_Up", JoyConKeyboard.Right.StickUp.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Stick_Down", JoyConKeyboard.Right.StickDown.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Stick_Left", JoyConKeyboard.Right.StickLeft.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Stick_Right", JoyConKeyboard.Right.StickRight.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Stick_Button", JoyConKeyboard.Right.StickButton.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_A", JoyConKeyboard.Right.ButtonA.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_B", JoyConKeyboard.Right.ButtonB.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_X", JoyConKeyboard.Right.ButtonX.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_Y", JoyConKeyboard.Right.ButtonY.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_Plus", JoyConKeyboard.Right.ButtonPlus.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_R", JoyConKeyboard.Right.ButtonR.ToString());
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_ZR", JoyConKeyboard.Right.ButtonZR.ToString());
Parser.SetValue("Controls_Left_JoyConController_Stick", JoyConController.Left.Stick.ToString());
Parser.SetValue("Controls_Left_JoyConController_Stick_Button", JoyConController.Left.StickButton.ToString());
Parser.SetValue("Controls_Left_JoyConController_DPad_Up", JoyConController.Left.DPadUp.ToString());
Parser.SetValue("Controls_Left_JoyConController_DPad_Down", JoyConController.Left.DPadDown.ToString());
Parser.SetValue("Controls_Left_JoyConController_DPad_Left", JoyConController.Left.DPadLeft.ToString());
Parser.SetValue("Controls_Left_JoyConController_DPad_Right", JoyConController.Left.DPadRight.ToString());
Parser.SetValue("Controls_Left_JoyConController_Button_Minus", JoyConController.Left.ButtonMinus.ToString());
Parser.SetValue("Controls_Left_JoyConController_Button_L", JoyConController.Left.ButtonL.ToString());
Parser.SetValue("Controls_Left_JoyConController_Button_ZL", JoyConController.Left.ButtonZL.ToString());
Parser.SetValue("Controls_Right_JoyConController_Stick_Up", JoyConController.Right.Stick.ToString());
Parser.SetValue("Controls_Right_JoyConController_Stick_Button", JoyConController.Right.StickButton.ToString());
Parser.SetValue("Controls_Right_JoyConController_Button_A", JoyConController.Right.ButtonA.ToString());
Parser.SetValue("Controls_Right_JoyConController_Button_B", JoyConController.Right.ButtonB.ToString());
Parser.SetValue("Controls_Right_JoyConController_Button_X", JoyConController.Right.ButtonX.ToString());
Parser.SetValue("Controls_Right_JoyConController_Button_Y", JoyConController.Right.ButtonY.ToString());
Parser.SetValue("Controls_Right_JoyConController_Button_Plus", JoyConController.Right.ButtonPlus.ToString());
Parser.SetValue("Controls_Right_JoyConController_Button_R", JoyConController.Right.ButtonR.ToString());
Parser.SetValue("Controls_Right_JoyConController_Button_ZR", JoyConController.Right.ButtonZR.ToString());
Parser.SetValue("GamePad_Enable", GamePadEnable.ToString());
Parser.SetValue("GamePad_Index", GamePadIndex.ToString());
Parser.SetValue("GamePad_Deadzone", Convert.ToString(GamePadDeadzone,CultureInfo.InvariantCulture));
Parser.SetValue("GamePad_Trigger_Threshold", GamePadTriggerThreshold.ToString());
Parser.SetValue("Default_Game_Directory", DefaultGameDirectory);
Parser.Save();
}
}
// https://stackoverflow.com/a/37772571
public class IniParser
{
private readonly Dictionary<string, string> Values;
private readonly Dictionary<string, string> Comments;
private readonly string Path;
public IniParser(string Path)
{
this.Path = Path;
string[] Lines = File.ReadAllLines(Path);
Values = Lines
.Where(Line => !string.IsNullOrWhiteSpace(Line) && !Line.StartsWith('#'))
.Select(Line => Line.Split('=', 2))
.ToDictionary(Parts => Parts[0].Trim(), Parts => Parts.Length > 1 ? Parts[1].Trim() : null);
string CurrentComment = string.Empty;
Comments = new Dictionary<string, string>();
foreach (string Line in Lines)
{
if (Line.StartsWith("#"))
CurrentComment += Line + Environment.NewLine;
else if (!string.IsNullOrWhiteSpace(Line))
{
string key = Line.Split("=", 2).First().Trim();
Comments.Add(key, CurrentComment.TrimEnd());
CurrentComment = string.Empty;
}
else CurrentComment = string.Empty;
}
}
public string GetValue(string Name)
{
return Values.TryGetValue(Name, out string Value) ? Value : null;
}
public void SetValue(string Name, string Value)
{
lock (Values)
if (Values.ContainsKey(Name))
{
Values[Name] = Value;
}
else
{
Values.Add(Name, Value);
}
}
public bool Save()
{
bool result = false;
List<string> Records = new List<string>();
foreach (var Record in Values)
{
if (Comments.ContainsKey(Record.Key))
{
string Comment = Comments[Record.Key];
if (!string.IsNullOrWhiteSpace(Comment))
{
Records.Add(Environment.NewLine);
Records.Add(Comments[Record.Key]);
}
}
Records.Add(string.Format("{0} = {1}", Record.Key, Record.Value));
}
File.WriteAllLines(Path, Records);
return result;
}
}
}

View file

@ -0,0 +1,73 @@
using Ryujinx.HLE;
using System;
using System.IO;
namespace Ryujinx.UI
{
class EmulationController
{
public bool IsLoaded = false;
private Switch Ns;
public event EventHandler IsShutDown;
public EmulationController(Switch Ns)
{
this.Ns = Ns;
}
public void Resume()
{
Ns.Os.ResumeAllProcesses();
}
public void Pause()
{
Ns.Os.PauseAllProcesses();
}
public void ShutDown()
{
Ns.Dispose();
Ns = null;
IsLoaded = false;
IsShutDown.Invoke(null,null);
}
public void Load(string Path)
{
if (Directory.Exists(Path))
{
string[] RomFsFiles = Directory.GetFiles(Path, "*.istorage");
if (RomFsFiles.Length == 0)
{
RomFsFiles = Directory.GetFiles(Path, "*.romfs");
}
if (RomFsFiles.Length > 0)
{
Console.WriteLine("Loading as cart with RomFS.");
Ns.LoadCart(Path, RomFsFiles[0]);
}
else
{
Console.WriteLine("Loading as cart WITHOUT RomFS.");
Ns.LoadCart(Path);
}
}
else if (File.Exists(Path))
{
Console.WriteLine("Loading as homebrew.");
Ns.LoadProgram(Path);
}
IsLoaded = true;
}
}
}

View file

@ -0,0 +1,54 @@
using System.IO;
using System.Text;
namespace Ryujinx.UI
{
public class ControlArchive
{
public LanguageEntry[] LanguageEntries { get; set; }
public long ApplicationTitleID { get; set; }
public long BaseTitleID { get; set; }
public long ProductCode { get; set; }
public string ApplicationVersion { get; set; }
public ControlArchive(Stream Input)
{
BinaryReader Reader = new BinaryReader(Input);
byte[] LanguageEntryData = Reader.ReadBytes(0x3000);
Input.Seek(0x3060, SeekOrigin.Begin);
ApplicationVersion = Encoding.ASCII.GetString(Reader.ReadBytes(0x10));
BaseTitleID = Reader.ReadInt64();
ApplicationTitleID = Reader.ReadInt64();
Input.Seek(0x30a8, SeekOrigin.Begin);
ProductCode = Reader.ReadInt64();
LanguageEntries = new LanguageEntry[16];
using (MemoryStream LanguageStream = new MemoryStream(LanguageEntryData))
{
BinaryReader LanguageReader = new BinaryReader(LanguageStream);
for (int Index = 0; Index < 16; Index++)
{
LanguageEntries[Index] = new LanguageEntry()
{
AplicationName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x200)).Trim('\0'),
DeveloperName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x100)).Trim('\0')
};
}
}
}
}
public struct LanguageEntry
{
public string AplicationName;
public string DeveloperName;
}
}

View file

@ -0,0 +1,72 @@
using System;
using System.IO;
using System.Text;
namespace Ryujinx.UI
{
class Nro : HLE.Loaders.Executables.Nro
{
public byte[] AssetRomfData { get; set; }
public byte[] IconData { get; set; }
public int AssetOffset { get; set; }
public ControlArchive ControlArchive { get; set; }
private byte[] NACPData { get; set; }
public Nro(Stream Input, string Name) : base(Input, Name)
{
BinaryReader Reader = new BinaryReader(Input);
byte[] Read(long Position, int Size)
{
Input.Seek(Position, SeekOrigin.Begin);
return Reader.ReadBytes(Size);
}
if (Input.Length > FileSize)
{
AssetOffset = FileSize;
string AssetMagic = Encoding.ASCII.GetString(Read(AssetOffset, 4));
if (AssetMagic == "ASET")
{
Input.Seek(AssetOffset, SeekOrigin.Begin);
int AssetMagic0 = Reader.ReadInt32();
int AssetFormat = Reader.ReadInt32();
byte[] IconSectionInfo = Reader.ReadBytes(0x10);
byte[] NACPSectionInfo = Reader.ReadBytes(0x10);
byte[] AssetRomfSectionInfo = Reader.ReadBytes(0x10);
long IconOffset = BitConverter.ToInt64(IconSectionInfo, 0);
long IconSize = BitConverter.ToInt64(IconSectionInfo, 8);
long NACPOffset = BitConverter.ToInt64(NACPSectionInfo, 0);
long NACPSize = BitConverter.ToInt64(NACPSectionInfo, 8);
long RomfOffset = BitConverter.ToInt64(AssetRomfSectionInfo, 0);
long RomfSize = BitConverter.ToInt64(AssetRomfSectionInfo, 8);
Input.Seek(AssetOffset + IconOffset, SeekOrigin.Begin);
IconData = Reader.ReadBytes((int)IconSize);
Input.Seek(AssetOffset + NACPOffset, SeekOrigin.Begin);
NACPData = Reader.ReadBytes((int)NACPSize);
Input.Seek(AssetOffset + RomfOffset, SeekOrigin.Begin);
AssetRomfData = Reader.ReadBytes((int)RomfSize);
}
}
if (NACPData != null)
using (MemoryStream NACPStream = new MemoryStream(NACPData))
{
ControlArchive = new ControlArchive(NACPStream);
}
}
}
}

View file

@ -0,0 +1,8 @@
public enum DialogResult
{
OK,
Cancel,
Yes,
No,
None
}

View file

@ -0,0 +1,520 @@
using ImGuiNET;
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics;
using Ryujinx.Audio;
using Ryujinx.Audio.OpenAL;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Gal.OpenGL;
using Ryujinx.HLE;
using Ryujinx.HLE.Input;
using System;
using System.Threading;
using Stopwatch = System.Diagnostics.Stopwatch;
namespace Ryujinx.UI
{
partial class EmulationWindow : WindowHelper
{
public static EmulationController EmulationController;
//toggles
private bool isRunning = false;
private bool IsRunning
{
get => isRunning;
set
{
isRunning = value;
UIActive = !value;
}
}
private bool showMainUI = true;
private bool ShowMainUI
{
get => showMainUI;
set
{
showMainUI = value;
if (value)
{
CurrentPage = Page.GameList;
UIActive = value;
}
else if (!ShowPauseUI)
UIActive = false;
}
}
private bool showPauseUI;
private bool ShowPauseUI
{
get => showPauseUI;
set
{
showPauseUI = value;
if (value)
{
CurrentPage = Page.Emulation;
UIActive = value;
}
else if (!ShowMainUI)
UIActive = false;
}
}
private Page CurrentPage = Page.GameList;
private bool EscapePressed;
private string CurrentPath;
private string PackagePath;
private const int TouchScreenWidth = 1280;
private const int TouchScreenHeight = 720;
private const float TouchScreenRatioX = (float)TouchScreenWidth / TouchScreenHeight;
private const float TouchScreenRatioY = (float)TouchScreenHeight / TouchScreenWidth;
private const int TargetFPS = 60;
FilePicker FileDialog;
IGalRenderer Renderer;
public static Switch Ns;
private Thread RenderThread;
private bool ResizeEvent;
private bool TitleEvent;
private string NewTitle;
public EmulationWindow() : base("Ryujinx")
{
CurrentPath = Environment.CurrentDirectory;
PackagePath = string.Empty;
FileDialog = FilePicker.GetFilePicker("rom",null);
InitializeSwitch();
ResizeEvent = false;
TitleEvent = false;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
VSync = VSyncMode.On;
}
private void RenderLoop()
{
MakeCurrent();
PrepareTexture();
Stopwatch Chrono = new Stopwatch();
Chrono.Start();
long TicksPerFrame = Stopwatch.Frequency / TargetFPS;
long Ticks = 0;
while (Exists && !IsExiting)
{
if (Ns.WaitFifo())
{
Ns.ProcessFrame();
}
Renderer.RunActions();
if (ResizeEvent)
{
ResizeEvent = false;
Renderer.FrameBuffer.SetWindowSize(Width, Height);
}
Ticks += Chrono.ElapsedTicks;
DeltaTime = (float)Chrono.Elapsed.TotalSeconds;
Chrono.Restart();
if (Ticks >= TicksPerFrame)
{
RenderFrame();
//Queue max. 1 vsync
Ticks = Math.Min(Ticks - TicksPerFrame, TicksPerFrame);
}
}
}
public void MainLoop()
{
VSync = VSyncMode.Off;
Visible = true;
Renderer.FrameBuffer.SetWindowSize(Width, Height);
Context.MakeCurrent(null);
//OpenTK doesn't like sleeps in its thread, to avoid this a renderer thread is created
RenderThread = new Thread(RenderLoop);
RenderThread.Start();
while (Exists && !IsExiting)
{
ProcessEvents();
if (!IsExiting)
{
UpdateFrame();
if (TitleEvent)
{
TitleEvent = false;
Title = NewTitle;
}
}
}
}
private new void RenderFrame()
{
if (UIActive)
{
StartFrame();
isRunning = false;
if (ShowMainUI)
{
showPauseUI = false;
RenderMainUI();
}
else if (ShowPauseUI)
{
showMainUI = false;
RenderPauseUI();
}
EndFrame();
}
else
{
Renderer.FrameBuffer.Render();
Ns.Statistics.RecordSystemFrameTime();
double HostFps = Ns.Statistics.GetSystemFrameRate();
double GameFps = Ns.Statistics.GetGameFrameRate();
NewTitle = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}";
TitleEvent = true;
SwapBuffers();
Ns.Os.SignalVsync();
}
}
public void InitializeSwitch()
{
MainContext.MakeCurrent(WindowInfo);
Renderer = new OGLRenderer();
Renderer.FrameBuffer.SetWindowSize(Width, Height);
IAalOutput AudioOut = new OpenALAudioOut();
Ns = new Switch(Renderer, AudioOut);
Config.Read(Ns.Log);
Ns.Log.Updated += ConsoleLog.PrintLog;
}
private new void UpdateFrame()
{
KeyboardState Keyboard = this.Keyboard ?? new KeyboardState();
if (!UIActive)
{
if (Keyboard[Key.Escape] && !EscapePressed)
{
EscapePressed = true;
IsRunning = false;
EmulationController.Pause();
if (EmulationController.IsLoaded)
ShowPauseUI = true;
UIActive = true;
return;
}
else if (Keyboard[Key.Escape])
EscapePressed = true;
else
EscapePressed = false;
HidControllerButtons CurrentButton = 0;
HidJoystickPosition LeftJoystick;
HidJoystickPosition RightJoystick;
int LeftJoystickDX = 0;
int LeftJoystickDY = 0;
int RightJoystickDX = 0;
int RightJoystickDY = 0;
float AnalogStickDeadzone = Config.GamePadDeadzone;
//LeftJoystick
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickUp]) LeftJoystickDY = short.MaxValue;
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickDown]) LeftJoystickDY = -short.MaxValue;
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickLeft]) LeftJoystickDX = -short.MaxValue;
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickRight]) LeftJoystickDX = short.MaxValue;
//LeftButtons
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickButton]) CurrentButton |= HidControllerButtons.KEY_LSTICK;
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadUp]) CurrentButton |= HidControllerButtons.KEY_DUP;
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadDown]) CurrentButton |= HidControllerButtons.KEY_DDOWN;
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadLeft]) CurrentButton |= HidControllerButtons.KEY_DLEFT;
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadRight]) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
if (Keyboard[(Key)Config.JoyConKeyboard.Left.ButtonMinus]) CurrentButton |= HidControllerButtons.KEY_MINUS;
if (Keyboard[(Key)Config.JoyConKeyboard.Left.ButtonL]) CurrentButton |= HidControllerButtons.KEY_L;
if (Keyboard[(Key)Config.JoyConKeyboard.Left.ButtonZL]) CurrentButton |= HidControllerButtons.KEY_ZL;
//RightJoystick
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickUp]) RightJoystickDY = short.MaxValue;
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickDown]) RightJoystickDY = -short.MaxValue;
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickLeft]) RightJoystickDX = -short.MaxValue;
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickRight]) RightJoystickDX = short.MaxValue;
//RightButtons
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickButton]) CurrentButton |= HidControllerButtons.KEY_RSTICK;
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonA]) CurrentButton |= HidControllerButtons.KEY_A;
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonB]) CurrentButton |= HidControllerButtons.KEY_B;
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonX]) CurrentButton |= HidControllerButtons.KEY_X;
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonY]) CurrentButton |= HidControllerButtons.KEY_Y;
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonPlus]) CurrentButton |= HidControllerButtons.KEY_PLUS;
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonR]) CurrentButton |= HidControllerButtons.KEY_R;
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonZR]) CurrentButton |= HidControllerButtons.KEY_ZR;
//Controller Input
if (Config.GamePadEnable)
{
GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex);
//LeftButtons
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadUp)) CurrentButton |= HidControllerButtons.KEY_DUP;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadDown)) CurrentButton |= HidControllerButtons.KEY_DDOWN;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadLeft)) CurrentButton |= HidControllerButtons.KEY_DLEFT;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadRight)) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.StickButton)) CurrentButton |= HidControllerButtons.KEY_LSTICK;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonMinus)) CurrentButton |= HidControllerButtons.KEY_MINUS;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonL)) CurrentButton |= HidControllerButtons.KEY_L;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonZL)) CurrentButton |= HidControllerButtons.KEY_ZL;
//RightButtons
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonA)) CurrentButton |= HidControllerButtons.KEY_A;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonB)) CurrentButton |= HidControllerButtons.KEY_B;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonX)) CurrentButton |= HidControllerButtons.KEY_X;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonY)) CurrentButton |= HidControllerButtons.KEY_Y;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.StickButton)) CurrentButton |= HidControllerButtons.KEY_RSTICK;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonPlus)) CurrentButton |= HidControllerButtons.KEY_PLUS;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonR)) CurrentButton |= HidControllerButtons.KEY_R;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonZR)) CurrentButton |= HidControllerButtons.KEY_ZR;
//LeftJoystick
if (GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).X >= AnalogStickDeadzone
|| GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).X <= -AnalogStickDeadzone)
LeftJoystickDX = (int)(GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).X * short.MaxValue);
if (GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).Y >= AnalogStickDeadzone
|| GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).Y <= -AnalogStickDeadzone)
LeftJoystickDY = (int)(GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).Y * short.MaxValue);
//RightJoystick
if (GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).X >= AnalogStickDeadzone
|| GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).X <= -AnalogStickDeadzone)
RightJoystickDX = (int)(GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).X * short.MaxValue);
if (GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).Y >= AnalogStickDeadzone
|| GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).Y <= -AnalogStickDeadzone)
RightJoystickDY = (int)(GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).Y * short.MaxValue);
}
LeftJoystick = new HidJoystickPosition
{
DX = LeftJoystickDX,
DY = LeftJoystickDY
};
RightJoystick = new HidJoystickPosition
{
DX = RightJoystickDX,
DY = RightJoystickDY
};
bool HasTouch = false;
//Get screen touch position from left mouse click
//OpenTK always captures mouse events, even if out of focus, so check if window is focused.
if (Focused && Mouse?.LeftButton == ButtonState.Pressed)
{
MouseState Mouse = this.Mouse.Value;
int ScrnWidth = Width;
int ScrnHeight = Height;
if (Width > Height * TouchScreenRatioX)
{
ScrnWidth = (int)(Height * TouchScreenRatioX);
}
else
{
ScrnHeight = (int)(Width * TouchScreenRatioY);
}
int StartX = (Width - ScrnWidth) >> 1;
int StartY = (Height - ScrnHeight) >> 1;
int EndX = StartX + ScrnWidth;
int EndY = StartY + ScrnHeight;
if (Mouse.X >= StartX &&
Mouse.Y >= StartY &&
Mouse.X < EndX &&
Mouse.Y < EndY)
{
int ScrnMouseX = Mouse.X - StartX;
int ScrnMouseY = Mouse.Y - StartY;
int MX = (int)(((float)ScrnMouseX / ScrnWidth) * TouchScreenWidth);
int MY = (int)(((float)ScrnMouseY / ScrnHeight) * TouchScreenHeight);
HidTouchPoint CurrentPoint = new HidTouchPoint
{
X = MX,
Y = MY,
//Placeholder values till more data is acquired
DiameterX = 10,
DiameterY = 10,
Angle = 90
};
HasTouch = true;
Ns.Hid.SetTouchPoints(CurrentPoint);
}
}
if (!HasTouch)
{
Ns.Hid.SetTouchPoints();
}
Ns.Hid.SetJoyconButton(
HidControllerId.CONTROLLER_HANDHELD,
HidControllerLayouts.Handheld_Joined,
CurrentButton,
LeftJoystick,
RightJoystick);
Ns.Hid.SetJoyconButton(
HidControllerId.CONTROLLER_HANDHELD,
HidControllerLayouts.Main,
CurrentButton,
LeftJoystick,
RightJoystick);
}
else if (EmulationController != null)
if (EmulationController.IsLoaded)
{
if (Keyboard[Key.Escape] && !EscapePressed)
{
EscapePressed = true;
EmulationController.Resume();
if (ShowPauseUI & EmulationController.IsLoaded)
showPauseUI = false;
UIActive = false;
IsRunning = true;
}
else if (Keyboard[Key.Escape])
EscapePressed = true;
else
EscapePressed = false;
}
}
protected override void OnUnload(EventArgs e)
{
RenderThread.Join();
base.OnUnload(e);
}
protected override void OnResize(EventArgs e)
{
ResizeEvent = true;
}
public void LoadPackage(string path)
{
MainContext.MakeCurrent(WindowInfo);
if (Ns == null)
InitializeSwitch();
if (EmulationController == null)
EmulationController = new EmulationController(Ns);
EmulationController.IsShutDown += EmulationController_IsShutDown;
EmulationController.Load(path);
IsRunning = true;
ShowMainUI = false;
}
private void EmulationController_IsShutDown(object sender, EventArgs e)
{
EmulationController = null;
Ns = null;
}
enum Page
{
Configuration,
Emulation,
GameList,
PackageLoader
}
}
}

22
Ryujinx.UI/GUI/Values.cs Normal file
View file

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Numerics;
namespace ImGuiNET
{
public struct Values
{
public const float ButtonWidth = 170f;
public const float ButtonHeight = 50f;
public const float DefaultWindowScale = 1.0f;
public const float SelectibleHeight = 20.0f;
public static float CurrentWindowScale = 1.0f;
public static float CurrentFontScale = 1.2f;
public struct Color
{
public static Vector4 Yellow = new Vector4(1.0f, 1.0f, 0, 1.0f);
}
}
}

View file

@ -0,0 +1,168 @@
using ImGuiNET;
using Ryujinx.Common.Input;
using System.Numerics;
namespace Ryujinx.UI.Widgets
{
public partial class ConfigurationWidget
{
static bool ConfigIntialized = false;
static bool OpenFolderPicker;
static string CurrentPath;
static float CurrentGamePadDeadzone;
static bool CurrentGamePadEnable;
static int CurrentGamePadIndex;
static float CurrentGamePadTriggerThreshold;
static IniParser IniParser;
static FilePicker FolderPicker;
static JoyConKeyboard KeyboardInputLayout;
static JoyConController ControllerInputLayout;
static Page CurrentPage = Page.General;
static ConfigurationWidget()
{
IniParser = new IniParser(Config.IniPath);
FolderPicker = FilePicker.GetFilePicker("FolderDialog",Config.DefaultGameDirectory);
CurrentPath = Config.DefaultGameDirectory.ToString();
}
static void Reset()
{
KeyboardInputLayout = Config.JoyConKeyboard;
ControllerInputLayout = Config.JoyConController;
CurrentGamePadTriggerThreshold = Config.GamePadTriggerThreshold;
CurrentGamePadIndex = Config.GamePadIndex;
CurrentGamePadEnable = Config.GamePadEnable;
CurrentGamePadDeadzone = Config.GamePadDeadzone;
}
static void Apply()
{
Config.JoyConKeyboard = KeyboardInputLayout;
Config.JoyConController = ControllerInputLayout;
Config.GamePadDeadzone = CurrentGamePadDeadzone;
Config.GamePadEnable = CurrentGamePadEnable;
Config.GamePadIndex = CurrentGamePadIndex;
Config.GamePadTriggerThreshold = CurrentGamePadTriggerThreshold;
}
public static void Draw()
{
if(!ConfigIntialized)
{
Reset();
ConfigIntialized = true;
}
if (ImGui.BeginChildFrame(2, ImGui.GetContentRegionAvailable()
- new Vector2(0,Values.ButtonHeight), WindowFlags.AlwaysAutoResize))
{
ImGuiNative.igBeginGroup();
if(ImGui.Button("General",new Vector2(Values.ButtonWidth,Values.ButtonHeight)))
{
CurrentPage = Page.General;
}
ImGui.SameLine();
if (ImGui.Button("Input", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
{
CurrentPage = Page.Input;
}
ImGuiNative.igEndGroup();
if (ImGui.BeginChildFrame(3, ImGui.GetContentRegionAvailable(), WindowFlags.AlwaysAutoResize))
{
switch (CurrentPage)
{
case Page.General:
if (ImGui.BeginChild("generalFrame", true, WindowFlags.AlwaysAutoResize))
{
ImGui.Text("General Emulation Settings");
ImGui.Spacing();
ImGui.LabelText("", "Default Game Directory");
ImGui.SameLine();
if (ImGui.Selectable(Config.DefaultGameDirectory))
{
OpenFolderPicker = true;
}
if (OpenFolderPicker)
ImGui.OpenPopup("Open Folder");
DialogResult DialogResult = FolderPicker.GetFolder(ref CurrentPath);
if (DialogResult == DialogResult.OK)
{
if (!string.IsNullOrWhiteSpace(CurrentPath))
{
Config.DefaultGameDirectory = CurrentPath;
}
}
if (DialogResult != DialogResult.None)
{
OpenFolderPicker = false;
}
ImGui.Spacing();
ImGui.Checkbox("Disable Cpu Memory Checks", ref AOptimizations.DisableMemoryChecks);
ImGui.EndChild();
}
break;
case Page.Input:
if (ImGui.BeginChild("inputFrame", true, WindowFlags.AlwaysAutoResize))
{
DrawInputPage();
ImGui.EndChild();
}
break;
}
ImGui.EndChildFrame();
}
ImGui.EndChildFrame();
if (CurrentPage == Page.Input)
{
if (ImGui.Button("Apply", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
{
Apply();
}
ImGui.SameLine();
}
if (ImGui.Button("Save", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
{
Apply();
Config.Save(EmulationWindow.Ns.Log);
}
ImGui.SameLine();
if (ImGui.Button("Discard", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
{
IniParser = new IniParser(Config.IniPath);
}
}
}
enum Page
{
General,
Input
}
}
}

View file

@ -0,0 +1,218 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Numerics;
namespace ImGuiNET
{
// Adapted from Mellinoe's file picker for imgui
// https://github.com/mellinoe/synthapp/blob/master/src/synthapp/Widgets/FilePicker.cs
public class FilePicker
{
private const string FilePickerID = "###FilePicker";
private static readonly Dictionary<object, FilePicker> FilePickers = new Dictionary<object, FilePicker>();
private static readonly Vector2 DefaultFilePickerSize = new Vector2(600, 400);
public string CurrentFolder { get; set; }
public string SelectedEntry { get; set; }
public string CurrentDrive { get; set; }
public static FilePicker GetFilePicker(object Id, string StartingPath)
{
if (File.Exists(StartingPath))
{
StartingPath = new FileInfo(StartingPath).DirectoryName;
}
else if (string.IsNullOrEmpty(StartingPath) || !Directory.Exists(StartingPath))
{
StartingPath = Environment.CurrentDirectory;
if (string.IsNullOrEmpty(StartingPath))
{
StartingPath = AppContext.BaseDirectory;
}
}
if (!FilePickers.TryGetValue(Id, out FilePicker FilePicker))
{
FilePicker = new FilePicker
{
CurrentFolder = StartingPath
};
FilePickers.Add(Id, FilePicker);
}
return FilePicker;
}
public DialogResult Draw(ref string SelectedPath, bool ReturnOnSelection, bool FoldersOnly = false)
{
return DrawFolder(ref SelectedPath, ReturnOnSelection, FoldersOnly);
}
private DialogResult DrawFolder(ref string SelectedPath, bool ReturnOnSelection = false, bool FoldersOnly = false)
{
ImGui.Text("Current Folder: " + CurrentFolder);
if(ImGui.BeginChildFrame(0,new Vector2(ImGui.GetContentRegionAvailableWidth()/3,
ImGui.GetContentRegionAvailable().Y - Values.ButtonHeight - 10), WindowFlags.Default))
{
DriveInfo[] DriveList = DriveInfo.GetDrives();
foreach(DriveInfo Drive in DriveList)
{
bool IsSelected = CurrentDrive == Drive.Name;
ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow);
if (ImGui.Selectable(Drive.Name + "/", IsSelected, SelectableFlags.DontClosePopups
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
{
CurrentDrive = Drive.Name;
CurrentFolder = Drive.Name;
}
ImGui.PopStyleColor();
}
ImGui.EndChildFrame();
}
ImGui.SameLine();
if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable() - new Vector2(20, Values.ButtonHeight + 10),
WindowFlags.Default))
{
DirectoryInfo CurrentDirectory = new DirectoryInfo(CurrentFolder);
if (CurrentDirectory.Exists)
{
if (CurrentDirectory.Parent != null)
{
ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow);
if (ImGui.Selectable("../", false, SelectableFlags.DontClosePopups
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
{
CurrentFolder = CurrentDirectory.Parent.FullName;
}
ImGui.PopStyleColor();
}
foreach (string Dir in Directory.EnumerateFileSystemEntries(CurrentDirectory.FullName))
{
if (Directory.Exists(Dir))
{
string Name = Path.GetFileName(Dir);
bool IsSelected = SelectedEntry == Dir;
ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow);
if (ImGui.Selectable(Name + "/", IsSelected, SelectableFlags.DontClosePopups
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
{
SelectedEntry = Dir;
SelectedPath = SelectedEntry;
}
if (SelectedEntry != null)
if (ImGui.IsMouseDoubleClicked(0) && SelectedEntry.Equals(Dir))
{
SelectedEntry = null;
SelectedPath = null;
CurrentFolder = Dir;
}
ImGui.PopStyleColor();
}
}
if (!FoldersOnly)
foreach (string File in Directory.EnumerateFiles(CurrentDirectory.FullName))
{
string Name = Path.GetFileName(File);
bool IsSelected = SelectedEntry == File;
if (ImGui.Selectable(Name, IsSelected, SelectableFlags.DontClosePopups
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
{
SelectedEntry = File;
if (ReturnOnSelection)
{
SelectedPath = SelectedEntry;
}
}
if (SelectedEntry != null)
if (ImGui.IsMouseDoubleClicked(0) && SelectedEntry.Equals(File))
{
SelectedPath = File;
}
}
}
}
ImGui.EndChildFrame();
if (ImGui.Button("Cancel", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
{
return DialogResult.Cancel;
}
if (SelectedEntry != null)
{
ImGui.SameLine();
if (ImGui.Button("Open", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
{
SelectedPath = SelectedEntry;
return DialogResult.OK;
}
else if (ReturnOnSelection)
{
SelectedPath = SelectedEntry;
return DialogResult.OK;
}
}
return DialogResult.None;
}
public DialogResult GetFolder(ref string CurrentPath)
{
ImGui.SetNextWindowSize(new Vector2(600, 600), Condition.FirstUseEver);
if (ImGui.BeginPopupModal("Open Folder", WindowFlags.NoResize))
{
try
{
string Output = CurrentPath;
DialogResult DialogResult = Draw(ref Output, false, true);
if (DialogResult == DialogResult.OK)
{
if (string.IsNullOrWhiteSpace(Output))
{
return DialogResult.None;
}
}
if (DialogResult != DialogResult.None)
ImGui.CloseCurrentPopup();
return DialogResult;
}
finally
{
ImGui.EndPopup();
}
}
return DialogResult.None;
}
}
}

View file

@ -0,0 +1,201 @@
using ImGuiNET;
using NanoJpeg;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
using System.IO;
using System.Numerics;
namespace Ryujinx.UI.Widgets
{
class GameList
{
static bool OpenFolderPicker;
static string GameDirectory;
static List<GameItem> GameItems;
static GameItem SelectedGame;
static FilePicker FolderPicker;
static GameList()
{
GameDirectory = Config.DefaultGameDirectory;
FolderPicker = FilePicker.GetFilePicker("FolderDialog", Config.DefaultGameDirectory);
Refresh(GameDirectory);
}
public unsafe static void Refresh(string Path)
{
GameItems = new List<GameItem>();
foreach (string entry in Directory.EnumerateFileSystemEntries(Path))
{
if (File.Exists(entry))
{
string Extension = System.IO.Path.GetExtension(entry).ToLower();
if (Extension == ".nro" || Extension == ".nso")
{
GameItem GameItem = new GameItem(entry);
if (GameItem.IsNro && GameItem.HasIcon)
{
GameItem.TextureID = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, GameItem.TextureID);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
NJImage Image = new NJImage();
Image.Decode(GameItem.GetIconData());
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, Image.Width, Image.Height, 0, PixelFormat.Rgb,
PixelType.UnsignedByte, new IntPtr(Image.Image));
Image.Dispose();
GL.BindTexture(TextureTarget.Texture2D, 0);
}
GameItems.Add(GameItem);
}
}
}
}
public unsafe static (bool,string) DrawList()
{
uint Id = 100;
if (ImGui.Button("Refresh GameList"))
Refresh(Config.DefaultGameDirectory);
ImGui.SameLine();
if(ImGui.Button("Select Game Directory"))
{
OpenFolderPicker = true;
}
if (OpenFolderPicker)
ImGui.OpenPopup("Open Folder");
DialogResult DialogResult = FolderPicker.GetFolder(ref GameDirectory);
if (DialogResult == DialogResult.OK)
{
Config.DefaultGameDirectory = GameDirectory;
Refresh(GameDirectory);
}
if (DialogResult != DialogResult.None)
OpenFolderPicker = false;
if (ImGui.BeginChildFrame(20, ImGui.GetContentRegionAvailable(), WindowFlags.AlwaysAutoResize))
{
foreach (GameItem GameItem in GameItems)
{
Id++;
if (GameItem == SelectedGame)
ImGui.PushStyleColor(ColorTarget.FrameBg, Values.Color.Yellow);
if (ImGui.BeginChildFrame(Id, new Vector2(ImGui.GetContentRegionAvailableWidth(), 60)
, WindowFlags.AlwaysAutoResize))
{
if (GameItem.IsNro && GameItem.HasIcon)
{
ImGui.Image(new IntPtr(GameItem.TextureID), new Vector2(50, 50), new Vector2(0, 0),
new Vector2(1, 1), new Vector4(255, 255, 255, 255), new Vector4(0, 0, 0, 255));
}
else
{
ImGui.BeginChildFrame(Id + 500, new Vector2(50, 50), WindowFlags.NoResize);
ImGui.EndChildFrame();
ImGui.SameLine();
ImGui.Text(Path.GetFileName(GameItem.Path));
}
ImGui.SameLine();
ImGuiNative.igBeginGroup();
if (GameItem.IsNro)
{
if (GameItem.Nro.ControlArchive != null)
{
ImGui.Text(GameItem.Nro.ControlArchive.LanguageEntries[0].AplicationName);
ImGui.Text(GameItem.Nro.ControlArchive.LanguageEntries[0].DeveloperName);
}
}
ImGuiNative.igEndGroup();
if (GameItem == SelectedGame)
ImGui.PopStyleColor();
if (ImGui.IsMouseDoubleClicked(0) && ImGui.IsItemHovered(HoveredFlags.AllowWhenOverlapped) && GameItem == SelectedGame)
{
return (true, GameItem.Path);
}
else if (ImGui.IsMouseClicked(0) && ImGui.IsItemHovered(HoveredFlags.AllowWhenOverlapped | HoveredFlags.RootAndChildWindows))
{
SelectedGame = GameItem;
}
ImGui.EndChildFrame();
}
}
ImGui.EndChildFrame();
}
return (false, string.Empty);
}
}
class GameItem
{
public AppletType AppletType { get; set; }
public Nro Nro { get; set; }
public string Path { get; set; }
public int TextureID { get; set; }
public bool IsNro => (System.IO.Path.GetExtension(Path) == ".nro");
public bool HasIcon => Nro?.IconData != null;
public GameItem(string Path)
{
this.Path = Path;
if (File.Exists(Path))
{
AppletType = AppletType.Homebrew;
FileInfo Package = new FileInfo(Path);
if (Package.Extension.ToLower() == ".nro")
{
Nro = new Nro(File.Open(Path, FileMode.Open), new FileInfo(Path).Name);
}
}
else
AppletType = AppletType.Cartridge;
}
public byte[] GetIconData()
{
return IsNro ? Nro.IconData : null;
}
}
enum AppletType
{
Homebrew,
Cartridge
}
}

View file

@ -0,0 +1,117 @@
using ImGuiNET;
using System;
using System.Numerics;
namespace Ryujinx.UI
{
partial class EmulationWindow
{
void RenderMainUI()
{
ImGui.SetNextWindowPos(Vector2.Zero, Condition.Always,
Vector2.Zero);
ImGui.SetNextWindowSize(new Vector2(Width, Height), Condition.Always);
if (ImGui.BeginWindow("MainWindow", ref showMainUI, WindowFlags.NoTitleBar
| WindowFlags.NoMove | WindowFlags.AlwaysAutoResize))
{
if (ImGui.BeginChildFrame(0, new Vector2(-1, -1),
WindowFlags.AlwaysAutoResize))
{
ImGuiNative.igBeginGroup();
if (ImGui.Button("Load Package", new Vector2(Values.ButtonWidth,
Values.ButtonHeight)))
{
CurrentPage = Page.PackageLoader;
}
if (ImGui.Button("Game List", new Vector2(Values.ButtonWidth,
Values.ButtonHeight)))
{
CurrentPage = Page.GameList;
}
if (ImGui.Button("Settings", new Vector2(Values.ButtonWidth,
Values.ButtonHeight)))
{
CurrentPage = Page.Configuration;
}
DrawQuitButton();
ImGuiNative.igEndGroup();
ImGui.SameLine();
if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable(),
WindowFlags.AlwaysAutoResize))
{
switch (CurrentPage)
{
case Page.PackageLoader:
string output = CurrentPath;
if (FileDialog.Draw(ref output, false) == DialogResult.OK)
{
if (!string.IsNullOrWhiteSpace(output))
{
PackagePath = output;
LoadPackage(PackagePath);
}
}
break;
case Page.Configuration:
Widgets.ConfigurationWidget.Draw();
break;
case Page.GameList:
var SelectedPath = Widgets.GameList.DrawList();
if (SelectedPath.Item1)
{
LoadPackage(SelectedPath.Item2);
}
break;
}
ImGui.EndChildFrame();
}
ImGui.EndChildFrame();
}
ImGui.EndWindow();
}
}
void DrawQuitButton()
{
if (ImGui.Button("Quit Ryujinx", new Vector2(Values.ButtonWidth,
Values.ButtonHeight)))
{
ImGui.OpenPopup("Quit");
}
if (ImGui.BeginPopupModal("Quit"))
{
ImGui.Text("Do you want to quit Ryujinx and return to desktop?");
if (ImGui.Button("Yes"))
{
Environment.Exit(0);
}
if (ImGui.Button("No"))
{
ImGui.CloseCurrentPopup();
}
ImGui.EndPopup();
}
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,80 @@
using ImGuiNET;
namespace Ryujinx.UI
{
partial class EmulationWindow
{
void RenderPauseUI()
{
ImGui.SetNextWindowPos(System.Numerics.Vector2.Zero, Condition.Always,
System.Numerics.Vector2.Zero);
ImGui.SetNextWindowSize(new System.Numerics.Vector2(Width, Height), Condition.Always);
if (ImGui.BeginWindow("PauseWindow", ref showMainUI, WindowFlags.NoTitleBar
| WindowFlags.NoMove | WindowFlags.AlwaysAutoResize))
{
if (ImGui.BeginChildFrame(0, new System.Numerics.Vector2(-1, -1),
WindowFlags.AlwaysAutoResize))
{
ImGuiNative.igBeginGroup();
if (ImGui.Button("Emulation", new System.Numerics.Vector2(Values.ButtonWidth,
Values.ButtonHeight)))
{
CurrentPage = Page.Emulation;
}
if (ImGui.Button("Settings", new System.Numerics.Vector2(Values.ButtonWidth,
Values.ButtonHeight)))
{
CurrentPage = Page.Configuration;
}
DrawQuitButton();
ImGuiNative.igEndGroup();
ImGui.SameLine();
if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable(),
WindowFlags.AlwaysAutoResize))
{
switch (CurrentPage)
{
case Page.Emulation:
if (ImGui.Button("Resume", new System.Numerics.Vector2(Values.ButtonWidth,
Values.ButtonHeight)))
{
ShowPauseUI = false;
EmulationController.Resume();
}
if (ImGui.Button("Stop", new System.Numerics.Vector2(Values.ButtonWidth,
Values.ButtonHeight)))
{
ShowPauseUI = false;
EmulationController.ShutDown();
ShowMainUI = true;
}
break;
case Page.Configuration:
Widgets.ConfigurationWidget.Draw();
break;
}
ImGui.EndChildFrame();
}
ImGui.EndChildFrame();
}
ImGui.EndWindow();
}
}
}
}

View file

@ -0,0 +1,384 @@
using ImGuiNET;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using System;
using Ryujinx.Common.Input;
namespace Ryujinx.UI
{
class WindowHelper : GameWindow
{
protected float DeltaTime;
protected bool UIActive;
protected GraphicsContext MainContext;
protected GraphicsContext UIContext;
private bool IsWindowOpened;
private int FontTexture;
private float WheelPosition;
protected KeyboardState? Keyboard = null;
protected MouseState? Mouse = null;
protected GamePadState? GamePad = null;
public WindowHelper(string Title) : base(1280, 720, GraphicsMode.Default, Title, GameWindowFlags.Default
, DisplayDevice.Default, 3, 3, GraphicsContextFlags.ForwardCompatible)
{
base.Title = Title;
IsWindowOpened = true;
Location = new Point(
(DisplayDevice.Default.Width / 2) - (Width / 2),
(DisplayDevice.Default.Height / 2) - (Height / 2));
MainContext = new GraphicsContext(GraphicsMode.Default,
WindowInfo, 3, 3, GraphicsContextFlags.ForwardCompatible);
UIContext = new GraphicsContext(GraphicsMode.Default,
WindowInfo, 3, 3, GraphicsContextFlags.ForwardCompatible);
UIContext.MakeCurrent(WindowInfo);
UIActive = true;
}
public void StartFrame()
{
UIContext.MakeCurrent(WindowInfo);
IO IO = ImGui.GetIO();
IO.DisplaySize = new System.Numerics.Vector2(Width, Height);
IO.DisplayFramebufferScale = new System.Numerics.Vector2(Values.CurrentWindowScale);
IO.DeltaTime = DeltaTime;
ImGui.NewFrame();
HandleInput(IO);
}
public unsafe void EndFrame()
{
ImGui.Render();
DrawData* data = ImGui.GetDrawData();
RenderImDrawData(data);
MainContext?.MakeCurrent(WindowInfo);
}
protected unsafe void PrepareTexture()
{
ImGui.GetIO().FontAtlas.AddDefaultFont();
IO IO = ImGui.GetIO();
// Build texture atlas
FontTextureData texData = IO.FontAtlas.GetTexDataAsAlpha8();
// Create OpenGL texture
FontTexture = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, FontTexture);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexImage2D(
TextureTarget.Texture2D,
0,
PixelInternalFormat.Alpha,
texData.Width,
texData.Height,
0,
PixelFormat.Alpha,
PixelType.UnsignedByte,
new IntPtr(texData.Pixels));
// Store the texture identifier in the ImFontAtlas substructure.
IO.FontAtlas.SetTexID(FontTexture);
IO.FontAtlas.ClearTexData();
GL.BindTexture(TextureTarget.Texture2D, 0);
}
unsafe void HandleInput(IO IO)
{
KeyboardState KeyboardState = default(KeyboardState);
if (Keyboard != null)
if (Keyboard.HasValue)
KeyboardState = Keyboard.Value;
MouseState MouseState = default(MouseState);
if (Mouse != null)
if (Mouse.HasValue)
MouseState = Mouse.Value;
if (Focused)
{
if (Mouse.HasValue)
{
Point WindowPoint = new Point(MouseState.X, MouseState.Y);
IO.MousePosition = new System.Numerics.Vector2(WindowPoint.X,
WindowPoint.Y);
}
if (this.Keyboard.HasValue)
foreach (Key Key in Enum.GetValues(typeof(Key)))
{
IO.KeysDown[(int)Key] = KeyboardState[Key];
if (KeyboardState[Key])
continue;
ImGuiNative.igGetIO()->KeyAlt = (byte)((KeyboardState[Key.AltLeft]
|| KeyboardState[Key.AltRight]) ? 1 : 0);
ImGuiNative.igGetIO()->KeyCtrl = (byte)((KeyboardState[Key.ControlLeft]
|| KeyboardState[Key.ControlRight]) ? 1 : 0);
ImGuiNative.igGetIO()->KeyShift = (byte)((KeyboardState[Key.ShiftLeft]
|| KeyboardState[Key.ShiftRight]) ? 1 : 0);
ImGuiNative.igGetIO()->KeySuper = (byte)((KeyboardState[Key.WinLeft]
|| KeyboardState[Key.WinRight]) ? 1 : 0);
}
}
else
{
IO.MousePosition = new System.Numerics.Vector2(-1f, -1f);
for (int i = 0; i <= 512; i++)
{
IO.KeysDown[i] = false;
}
}
if (Mouse.HasValue)
{
IO.MouseDown[0] = MouseState.LeftButton == ButtonState.Pressed;
IO.MouseDown[1] = MouseState.RightButton == ButtonState.Pressed;
IO.MouseDown[2] = MouseState.MiddleButton == ButtonState.Pressed;
float NewWheelPos = MouseState.WheelPrecise;
float Delta = NewWheelPos - WheelPosition;
WheelPosition = NewWheelPos;
IO.MouseWheel = Delta;
}
}
private unsafe void RenderImDrawData(DrawData* DrawData)
{
Vector4 ClearColor = new Vector4(114f / 255f, 144f / 255f, 154f / 255f, 1.0f);
GL.Viewport(0, 0, Width, Height);
GL.ClearColor(ClearColor.X, ClearColor.Y, ClearColor.Z, ClearColor.W);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.GetInteger(GetPName.TextureBinding2D, out int last_texture);
GL.PushAttrib(AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.TransformBit);
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
GL.Disable(EnableCap.CullFace);
GL.Disable(EnableCap.DepthTest);
GL.Enable(EnableCap.ScissorTest);
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
GL.EnableClientState(ArrayCap.ColorArray);
GL.Enable(EnableCap.Texture2D);
GL.UseProgram(0);
IO IO = ImGui.GetIO();
ImGui.ScaleClipRects(DrawData, IO.DisplayFramebufferScale);
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
GL.Ortho(
0.0f,
IO.DisplaySize.X / IO.DisplayFramebufferScale.X,
IO.DisplaySize.Y / IO.DisplayFramebufferScale.Y,
0.0f,
-1.0f,
1.0f);
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
// Render command lists
for (int n = 0; n < DrawData->CmdListsCount; n++)
{
NativeDrawList* CmdList = DrawData->CmdLists[n];
byte* VtxBuffer = (byte*)CmdList->VtxBuffer.Data;
ushort* IdxBuffer = (ushort*)CmdList->IdxBuffer.Data;
GL.VertexPointer(2, VertexPointerType.Float, sizeof(DrawVert), new IntPtr(VtxBuffer + DrawVert.PosOffset));
GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(DrawVert), new IntPtr(VtxBuffer + DrawVert.UVOffset));
GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(DrawVert), new IntPtr(VtxBuffer + DrawVert.ColOffset));
for (int Cmd = 0; Cmd < CmdList->CmdBuffer.Size; Cmd++)
{
DrawCmd* PCmd = &(((DrawCmd*)CmdList->CmdBuffer.Data)[Cmd]);
if (PCmd->UserCallback != IntPtr.Zero)
{
throw new NotImplementedException();
}
else
{
GL.BindTexture(TextureTarget.Texture2D, PCmd->TextureId.ToInt32());
GL.Scissor(
(int)PCmd->ClipRect.X,
(int)(IO.DisplaySize.Y - PCmd->ClipRect.W),
(int)(PCmd->ClipRect.Z - PCmd->ClipRect.X),
(int)(PCmd->ClipRect.W - PCmd->ClipRect.Y));
ushort[] indices = new ushort[PCmd->ElemCount];
for (int i = 0; i < indices.Length; i++)
indices[i] = IdxBuffer[i];
GL.DrawElements(PrimitiveType.Triangles, (int)PCmd->ElemCount, DrawElementsType.UnsignedShort, new IntPtr(IdxBuffer));
}
IdxBuffer += PCmd->ElemCount;
}
}
// Restore modified state
GL.DisableClientState(ArrayCap.ColorArray);
GL.DisableClientState(ArrayCap.TextureCoordArray);
GL.DisableClientState(ArrayCap.VertexArray);
GL.BindTexture(TextureTarget.Texture2D, last_texture);
GL.MatrixMode(MatrixMode.Modelview);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.PopAttrib();
SwapBuffers();
}
internal static bool IsGamePadButtonPressed(GamePadState GamePad, GamePadButton Button)
{
if (Button == GamePadButton.LTrigger || Button == GamePadButton.RTrigger)
{
return GetGamePadTrigger(GamePad, Button) >= Config.GamePadTriggerThreshold;
}
else
{
return (GetGamePadButton(GamePad, Button) == ButtonState.Pressed);
}
}
internal static ButtonState GetGamePadButton(GamePadState GamePad, GamePadButton Button)
{
switch (Button)
{
case GamePadButton.A: return GamePad.Buttons.A;
case GamePadButton.B: return GamePad.Buttons.B;
case GamePadButton.X: return GamePad.Buttons.X;
case GamePadButton.Y: return GamePad.Buttons.Y;
case GamePadButton.LStick: return GamePad.Buttons.LeftStick;
case GamePadButton.RStick: return GamePad.Buttons.RightStick;
case GamePadButton.LShoulder: return GamePad.Buttons.LeftShoulder;
case GamePadButton.RShoulder: return GamePad.Buttons.RightShoulder;
case GamePadButton.DPadUp: return GamePad.DPad.Up;
case GamePadButton.DPadDown: return GamePad.DPad.Down;
case GamePadButton.DPadLeft: return GamePad.DPad.Left;
case GamePadButton.DPadRight: return GamePad.DPad.Right;
case GamePadButton.Start: return GamePad.Buttons.Start;
case GamePadButton.Back: return GamePad.Buttons.Back;
default: throw new ArgumentException();
}
}
internal static float GetGamePadTrigger(GamePadState GamePad, GamePadButton Trigger)
{
switch (Trigger)
{
case GamePadButton.LTrigger: return GamePad.Triggers.Left;
case GamePadButton.RTrigger: return GamePad.Triggers.Right;
default: throw new ArgumentException();
}
}
internal static Vector2 GetJoystickAxis(GamePadState GamePad, GamePadStick Joystick)
{
switch (Joystick)
{
case GamePadStick.LJoystick: return GamePad.ThumbSticks.Left;
case GamePadStick.RJoystick: return new Vector2(-GamePad.ThumbSticks.Right.Y, -GamePad.ThumbSticks.Right.X);
default: throw new ArgumentException();
}
}
protected override void OnKeyDown(KeyboardKeyEventArgs e)
{
Keyboard = e.Keyboard;
}
protected override void OnKeyUp(KeyboardKeyEventArgs e)
{
Keyboard = e.Keyboard;
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
Mouse = e.Mouse;
}
protected override void OnMouseUp(MouseButtonEventArgs e)
{
Mouse = e.Mouse;
}
protected override void OnMouseMove(MouseMoveEventArgs e)
{
Mouse = e.Mouse;
}
}
}

21
Ryujinx.UI/InputDevice.cs Normal file
View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenTK.Input;
namespace Ryujinx.UI
{
public struct InputDevice
{
public int Index;
public string Name;
public IInputDevice Device;
public DeviceType DeviceType;
}
public enum DeviceType
{
GamePad,
Keyboard
}
}

16
Ryujinx.UI/Program.cs Normal file
View file

@ -0,0 +1,16 @@
using System;
namespace Ryujinx.UI
{
class Program
{
static void Main(string[] args)
{
EmulationWindow MainUI = new EmulationWindow();
MainUI.MainLoop();
Environment.Exit(0);
}
}
}

View file

@ -0,0 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputPath>..\Ryujinx\bin\Release\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>false</Optimize>
<OutputPath>..\Ryujinx\bin\Debug\</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ImGui.NET" Version="0.4.5" />
<PackageReference Include="OpenTK.NetStandard" Version="1.0.4" />
<PackageReference Include="System.Drawing.Common" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics\Ryujinx.Graphics.csproj" />
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="RyujinxUI.conf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

82
Ryujinx.UI/RyujinxUI.conf Normal file
View file

@ -0,0 +1,82 @@
#Enable cpu memory checks (slow)
Enable_Memory_Checks = false
#Enable print debug logs
Logging_Enable_Debug = false
#Enable print stubbed calls logs
Logging_Enable_Stub = true
#Enable print informations logs
Logging_Enable_Info = true
#Enable print warning logs
Logging_Enable_Warn = true
#Enable print error logs
Logging_Enable_Error = true
#Filtered log classes, seperated by ", ", eg. `Logging_Filtered_Classes = Loader, ServiceFS`
Logging_Filtered_Classes =
#Controller Device Index
GamePad_Index = 0
#Controller Analog Stick Deadzone
GamePad_Deadzone = 0.05
#The value of how pressed down each trigger has to be in order to register a button press
GamePad_Trigger_Threshold = 0.5
#Whether or not to enable Controller support
GamePad_Enable = true
#https://github.com/opentk/opentk/blob/develop/src/OpenTK/Input/Key.cs
Controls_Left_JoyConKeyboard_Stick_Up = 105
Controls_Left_JoyConKeyboard_Stick_Down = 101
Controls_Left_JoyConKeyboard_Stick_Left = 83
Controls_Left_JoyConKeyboard_Stick_Right = 86
Controls_Left_JoyConKeyboard_Stick_Button = 88
Controls_Left_JoyConKeyboard_DPad_Up = 45
Controls_Left_JoyConKeyboard_DPad_Down = 46
Controls_Left_JoyConKeyboard_DPad_Left = 47
Controls_Left_JoyConKeyboard_DPad_Right = 48
Controls_Left_JoyConKeyboard_Button_Minus = 120
Controls_Left_JoyConKeyboard_Button_L = 87
Controls_Left_JoyConKeyboard_Button_ZL = 99
Controls_Right_JoyConKeyboard_Stick_Up = 91
Controls_Right_JoyConKeyboard_Stick_Down = 93
Controls_Right_JoyConKeyboard_Stick_Left = 92
Controls_Right_JoyConKeyboard_Stick_Right = 94
Controls_Right_JoyConKeyboard_Stick_Button = 90
Controls_Right_JoyConKeyboard_Button_A = 108
Controls_Right_JoyConKeyboard_Button_B = 106
Controls_Right_JoyConKeyboard_Button_X = 85
Controls_Right_JoyConKeyboard_Button_Y = 104
Controls_Right_JoyConKeyboard_Button_Plus = 121
Controls_Right_JoyConKeyboard_Button_R = 103
Controls_Right_JoyConKeyboard_Button_ZR = 97
#Controller Controls
Controls_Left_JoyConController_Stick_Button = LStick
Controls_Left_JoyConController_DPad_Up = DPadUp
Controls_Left_JoyConController_DPad_Down = DPadDown
Controls_Left_JoyConController_DPad_Left = DPadLeft
Controls_Left_JoyConController_DPad_Right = DPadRight
Controls_Left_JoyConController_Button_Minus = Back
Controls_Left_JoyConController_Button_L = LShoulder
Controls_Left_JoyConController_Button_ZL = LTrigger
Controls_Right_JoyConController_Stick_Button = RStick
Controls_Right_JoyConController_Button_A = B
Controls_Right_JoyConController_Button_B = A
Controls_Right_JoyConController_Button_X = Y
Controls_Right_JoyConController_Button_Y = X
Controls_Right_JoyConController_Button_Plus = Start
Controls_Right_JoyConController_Button_R = RShoulder
Controls_Right_JoyConController_Button_ZR = RTrigger
Controls_Left_JoyConController_Stick = LJoystick
Controls_Right_JoyConController_Stick = RJoystick

View file

@ -15,9 +15,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics", "Ryujinx
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "Ryujinx.Audio\Ryujinx.Audio.csproj", "{5C1D818E-682A-46A5-9D54-30006E26C270}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.ShaderTools", "Ryujinx.ShaderTools\Ryujinx.ShaderTools.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.ShaderTools", "Ryujinx.ShaderTools\Ryujinx.ShaderTools.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Luea", "Ryujinx.LLE\Luea.csproj", "{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luea", "Ryujinx.LLE\Luea.csproj", "{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI", "Ryujinx.UI\Ryujinx.UI.csproj", "{00117502-1661-4C8B-8C07-177C1A8AA455}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Common", "Ryujinx.Common\Ryujinx.Common.csproj", "{E614B5D6-7497-4B8D-A6BE-76CA134BDCE7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -57,6 +61,14 @@ Global
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Release|Any CPU.Build.0 = Release|Any CPU
{00117502-1661-4C8B-8C07-177C1A8AA455}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{00117502-1661-4C8B-8C07-177C1A8AA455}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00117502-1661-4C8B-8C07-177C1A8AA455}.Release|Any CPU.ActiveCfg = Release|Any CPU
{00117502-1661-4C8B-8C07-177C1A8AA455}.Release|Any CPU.Build.0 = Release|Any CPU
{E614B5D6-7497-4B8D-A6BE-76CA134BDCE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E614B5D6-7497-4B8D-A6BE-76CA134BDCE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E614B5D6-7497-4B8D-A6BE-76CA134BDCE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E614B5D6-7497-4B8D-A6BE-76CA134BDCE7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -1,4 +1,4 @@
using Ryujinx.UI.Input;
using Ryujinx.Common.Input;
using Ryujinx.HLE.Logging;
using System;
using System.Globalization;
@ -109,28 +109,28 @@ namespace Ryujinx
{
Left = new JoyConControllerLeft
{
Stick = Parser.Value("Controls_Left_JoyConController_Stick"),
StickButton = Parser.Value("Controls_Left_JoyConController_Stick_Button"),
DPadUp = Parser.Value("Controls_Left_JoyConController_DPad_Up"),
DPadDown = Parser.Value("Controls_Left_JoyConController_DPad_Down"),
DPadLeft = Parser.Value("Controls_Left_JoyConController_DPad_Left"),
DPadRight = Parser.Value("Controls_Left_JoyConController_DPad_Right"),
ButtonMinus = Parser.Value("Controls_Left_JoyConController_Button_Minus"),
ButtonL = Parser.Value("Controls_Left_JoyConController_Button_L"),
ButtonZL = Parser.Value("Controls_Left_JoyConController_Button_ZL")
Stick = Enum.Parse<GamePadStick>(Parser.Value("Controls_Left_JoyConController_Stick")),
StickButton = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_Stick_Button")),
DPadUp = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_DPad_Up")),
DPadDown = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_DPad_Down")),
DPadLeft = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_DPad_Left")),
DPadRight = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_DPad_Right")),
ButtonMinus = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_Button_Minus")),
ButtonL = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_Button_L")),
ButtonZL = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_Button_ZL"))
},
Right = new JoyConControllerRight
{
Stick = Parser.Value("Controls_Right_JoyConController_Stick"),
StickButton = Parser.Value("Controls_Right_JoyConController_Stick_Button"),
ButtonA = Parser.Value("Controls_Right_JoyConController_Button_A"),
ButtonB = Parser.Value("Controls_Right_JoyConController_Button_B"),
ButtonX = Parser.Value("Controls_Right_JoyConController_Button_X"),
ButtonY = Parser.Value("Controls_Right_JoyConController_Button_Y"),
ButtonPlus = Parser.Value("Controls_Right_JoyConController_Button_Plus"),
ButtonR = Parser.Value("Controls_Right_JoyConController_Button_R"),
ButtonZR = Parser.Value("Controls_Right_JoyConController_Button_ZR")
Stick = Enum.Parse<GamePadStick>(Parser.Value("Controls_Right_JoyConController_Stick")),
StickButton = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Stick_Button")),
ButtonA = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_A")),
ButtonB = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_B")),
ButtonX = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_X")),
ButtonY = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_Y")),
ButtonPlus = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_Plus")),
ButtonR = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_R")),
ButtonZR = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_ZR"))
}
};
}

View file

@ -12,6 +12,7 @@
<ItemGroup>
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics\Ryujinx.Graphics.csproj" />
</ItemGroup>

View file

@ -4,6 +4,7 @@ using OpenTK.Input;
using Ryujinx.Graphics.Gal;
using Ryujinx.HLE;
using Ryujinx.HLE.Input;
using Ryujinx.Common.Input;
using System;
using System.Threading;
@ -130,57 +131,57 @@ namespace Ryujinx
}
}
private bool IsGamePadButtonPressedFromString(GamePadState GamePad, string Button)
private bool IsGamePadButtonPressed(GamePadState GamePad, GamePadButton Button)
{
if (Button.ToUpper() == "LTRIGGER" || Button.ToUpper() == "RTRIGGER")
if (Button == GamePadButton.LTrigger || Button == GamePadButton.RTrigger)
{
return GetGamePadTriggerFromString(GamePad, Button) >= Config.GamePadTriggerThreshold;
return GetGamePadTrigger(GamePad, Button) >= Config.GamePadTriggerThreshold;
}
else
{
return (GetGamePadButtonFromString(GamePad, Button) == ButtonState.Pressed);
return (GetGamePadButton(GamePad, Button) == ButtonState.Pressed);
}
}
private ButtonState GetGamePadButtonFromString(GamePadState GamePad, string Button)
private ButtonState GetGamePadButton(GamePadState GamePad, GamePadButton Button)
{
switch (Button.ToUpper())
switch (Button)
{
case "A": return GamePad.Buttons.A;
case "B": return GamePad.Buttons.B;
case "X": return GamePad.Buttons.X;
case "Y": return GamePad.Buttons.Y;
case "LSTICK": return GamePad.Buttons.LeftStick;
case "RSTICK": return GamePad.Buttons.RightStick;
case "LSHOULDER": return GamePad.Buttons.LeftShoulder;
case "RSHOULDER": return GamePad.Buttons.RightShoulder;
case "DPADUP": return GamePad.DPad.Up;
case "DPADDOWN": return GamePad.DPad.Down;
case "DPADLEFT": return GamePad.DPad.Left;
case "DPADRIGHT": return GamePad.DPad.Right;
case "START": return GamePad.Buttons.Start;
case "BACK": return GamePad.Buttons.Back;
default: throw new ArgumentException();
case GamePadButton.A: return GamePad.Buttons.A;
case GamePadButton.B: return GamePad.Buttons.B;
case GamePadButton.X: return GamePad.Buttons.X;
case GamePadButton.Y: return GamePad.Buttons.Y;
case GamePadButton.LStick: return GamePad.Buttons.LeftStick;
case GamePadButton.RStick: return GamePad.Buttons.RightStick;
case GamePadButton.LShoulder: return GamePad.Buttons.LeftShoulder;
case GamePadButton.RShoulder: return GamePad.Buttons.RightShoulder;
case GamePadButton.DPadUp: return GamePad.DPad.Up;
case GamePadButton.DPadDown: return GamePad.DPad.Down;
case GamePadButton.DPadLeft: return GamePad.DPad.Left;
case GamePadButton.DPadRight: return GamePad.DPad.Right;
case GamePadButton.Start: return GamePad.Buttons.Start;
case GamePadButton.Back: return GamePad.Buttons.Back;
default: throw new ArgumentException();
}
}
private float GetGamePadTriggerFromString(GamePadState GamePad, string Trigger)
private float GetGamePadTrigger(GamePadState GamePad, GamePadButton Trigger)
{
switch (Trigger.ToUpper())
switch (Trigger)
{
case "LTRIGGER": return GamePad.Triggers.Left;
case "RTRIGGER": return GamePad.Triggers.Right;
default: throw new ArgumentException();
case GamePadButton.LTrigger: return GamePad.Triggers.Left;
case GamePadButton.RTrigger: return GamePad.Triggers.Right;
default: throw new ArgumentException();
}
}
private Vector2 GetJoystickAxisFromString(GamePadState GamePad, string Joystick)
private Vector2 GetJoystickAxisFromString(GamePadState GamePad, GamePadStick Joystick)
{
switch (Joystick.ToUpper())
switch (Joystick)
{
case "LJOYSTICK": return GamePad.ThumbSticks.Left;
case "RJOYSTICK": return new Vector2(-GamePad.ThumbSticks.Right.Y, -GamePad.ThumbSticks.Right.X);
default: throw new ArgumentException();
case GamePadStick.LJoystick: return GamePad.ThumbSticks.Left;
case GamePadStick.RJoystick: return new Vector2(-GamePad.ThumbSticks.Right.Y, -GamePad.ThumbSticks.Right.X);
default: throw new ArgumentException();
}
}
@ -241,24 +242,24 @@ namespace Ryujinx
{
GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex);
//LeftButtons
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadUp)) CurrentButton |= HidControllerButtons.KEY_DUP;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadDown)) CurrentButton |= HidControllerButtons.KEY_DDOWN;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadLeft)) CurrentButton |= HidControllerButtons.KEY_DLEFT;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadRight)) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.StickButton)) CurrentButton |= HidControllerButtons.KEY_LSTICK;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.ButtonMinus)) CurrentButton |= HidControllerButtons.KEY_MINUS;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.ButtonL)) CurrentButton |= HidControllerButtons.KEY_L;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.ButtonZL)) CurrentButton |= HidControllerButtons.KEY_ZL;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadUp)) CurrentButton |= HidControllerButtons.KEY_DUP;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadDown)) CurrentButton |= HidControllerButtons.KEY_DDOWN;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadLeft)) CurrentButton |= HidControllerButtons.KEY_DLEFT;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadRight)) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.StickButton)) CurrentButton |= HidControllerButtons.KEY_LSTICK;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonMinus)) CurrentButton |= HidControllerButtons.KEY_MINUS;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonL)) CurrentButton |= HidControllerButtons.KEY_L;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonZL)) CurrentButton |= HidControllerButtons.KEY_ZL;
//RightButtons
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonA)) CurrentButton |= HidControllerButtons.KEY_A;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonB)) CurrentButton |= HidControllerButtons.KEY_B;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonX)) CurrentButton |= HidControllerButtons.KEY_X;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonY)) CurrentButton |= HidControllerButtons.KEY_Y;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.StickButton)) CurrentButton |= HidControllerButtons.KEY_RSTICK;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonPlus)) CurrentButton |= HidControllerButtons.KEY_PLUS;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonR)) CurrentButton |= HidControllerButtons.KEY_R;
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonZR)) CurrentButton |= HidControllerButtons.KEY_ZR;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonA)) CurrentButton |= HidControllerButtons.KEY_A;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonB)) CurrentButton |= HidControllerButtons.KEY_B;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonX)) CurrentButton |= HidControllerButtons.KEY_X;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonY)) CurrentButton |= HidControllerButtons.KEY_Y;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.StickButton)) CurrentButton |= HidControllerButtons.KEY_RSTICK;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonPlus)) CurrentButton |= HidControllerButtons.KEY_PLUS;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonR)) CurrentButton |= HidControllerButtons.KEY_R;
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonZR)) CurrentButton |= HidControllerButtons.KEY_ZR;
//LeftJoystick
if (GetJoystickAxisFromString(GamePad, Config.JoyConController.Left.Stick).X >= AnalogStickDeadzone

View file

@ -1,38 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Ryujinx.UI.Input
{
public struct JoyConControllerLeft
{
public string Stick;
public string StickButton;
public string DPadUp;
public string DPadDown;
public string DPadLeft;
public string DPadRight;
public string ButtonMinus;
public string ButtonL;
public string ButtonZL;
}
public struct JoyConControllerRight
{
public string Stick;
public string StickButton;
public string ButtonA;
public string ButtonB;
public string ButtonX;
public string ButtonY;
public string ButtonPlus;
public string ButtonR;
public string ButtonZR;
}
public struct JoyConController
{
public JoyConControllerLeft Left;
public JoyConControllerRight Right;
}
}