Merge 13d94afd39
into 51605fafc0
This commit is contained in:
commit
4dab29ffa4
41 changed files with 4893 additions and 118 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Audio
|
||||
{
|
||||
public interface IAalOutput
|
||||
public interface IAalOutput : IDisposable
|
||||
{
|
||||
int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ using System.Threading;
|
|||
|
||||
namespace Ryujinx
|
||||
{
|
||||
static class ConsoleLog
|
||||
public static class ConsoleLog
|
||||
{
|
||||
private static Dictionary<LogLevel, ConsoleColor> LogColors;
|
||||
|
28
Ryujinx.Common/Input/GamePadButton.cs
Normal file
28
Ryujinx.Common/Input/GamePadButton.cs
Normal 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
|
||||
}
|
||||
}
|
34
Ryujinx.Common/Input/JoyConController.cs
Normal file
34
Ryujinx.Common/Input/JoyConController.cs
Normal 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;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.UI.Input
|
||||
namespace Ryujinx.Common.Input
|
||||
{
|
||||
public struct JoyConKeyboardLeft
|
||||
{
|
11
Ryujinx.Common/Ryujinx.Common.csproj
Normal file
11
Ryujinx.Common/Ryujinx.Common.csproj
Normal 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>
|
|
@ -2,7 +2,7 @@ using System;
|
|||
|
||||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public interface IGalRenderer
|
||||
public interface IGalRenderer : IDisposable
|
||||
{
|
||||
void QueueAction(Action ActionMthd);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -98,6 +98,8 @@ namespace Ryujinx.HLE
|
|||
{
|
||||
Os.Dispose();
|
||||
VFs.Dispose();
|
||||
Gpu.Dispose();
|
||||
AudioOut.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
315
Ryujinx.UI/Config.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
73
Ryujinx.UI/EmulationController.cs
Normal file
73
Ryujinx.UI/EmulationController.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
54
Ryujinx.UI/Extensions/ControlArchive.cs
Normal file
54
Ryujinx.UI/Extensions/ControlArchive.cs
Normal 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;
|
||||
}
|
||||
}
|
72
Ryujinx.UI/Extensions/Nro.cs
Normal file
72
Ryujinx.UI/Extensions/Nro.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
8
Ryujinx.UI/GUI/DialogResult.cs
Normal file
8
Ryujinx.UI/GUI/DialogResult.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
public enum DialogResult
|
||||
{
|
||||
OK,
|
||||
Cancel,
|
||||
Yes,
|
||||
No,
|
||||
None
|
||||
}
|
520
Ryujinx.UI/GUI/EmulationWindow.cs
Normal file
520
Ryujinx.UI/GUI/EmulationWindow.cs
Normal 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
22
Ryujinx.UI/GUI/Values.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
168
Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs
Normal file
168
Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
218
Ryujinx.UI/GUI/Widgets/FilePicker.cs
Normal file
218
Ryujinx.UI/GUI/Widgets/FilePicker.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
201
Ryujinx.UI/GUI/Widgets/GameList.cs
Normal file
201
Ryujinx.UI/GUI/Widgets/GameList.cs
Normal 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
|
||||
}
|
||||
}
|
117
Ryujinx.UI/GUI/Widgets/HomeUI.cs
Normal file
117
Ryujinx.UI/GUI/Widgets/HomeUI.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1210
Ryujinx.UI/GUI/Widgets/InputPage.cs
Normal file
1210
Ryujinx.UI/GUI/Widgets/InputPage.cs
Normal file
File diff suppressed because it is too large
Load diff
1008
Ryujinx.UI/GUI/Widgets/NanoJpeg.cs
Normal file
1008
Ryujinx.UI/GUI/Widgets/NanoJpeg.cs
Normal file
File diff suppressed because it is too large
Load diff
80
Ryujinx.UI/GUI/Widgets/PauseUI.cs
Normal file
80
Ryujinx.UI/GUI/Widgets/PauseUI.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
384
Ryujinx.UI/GUI/WindowHelper.cs
Normal file
384
Ryujinx.UI/GUI/WindowHelper.cs
Normal 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
21
Ryujinx.UI/InputDevice.cs
Normal 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
16
Ryujinx.UI/Program.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
39
Ryujinx.UI/Ryujinx.UI.csproj
Normal file
39
Ryujinx.UI/Ryujinx.UI.csproj
Normal 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
82
Ryujinx.UI/RyujinxUI.conf
Normal 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
|
16
Ryujinx.sln
16
Ryujinx.sln
|
@ -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
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue