From 71e1f0bda6f4fde92f6c73e88f549811ccea340f Mon Sep 17 00:00:00 2001 From: emmaus Date: Wed, 13 Jun 2018 20:32:07 +0000 Subject: [PATCH 01/11] minimal gui --- ChocolArm64/ATranslator.cs | 17 + Ryujinx.Audio/IAalOutput.cs | 4 +- Ryujinx.Audio/OpenAL/OpenALAudioOut.cs | 25 + Ryujinx.Graphics/Gal/IGalRenderer.cs | 2 +- Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs | 2 +- Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs | 13 + Ryujinx.HLE/Gpu/NvGpu.cs | 8 +- Ryujinx.HLE/OsHle/Horizon.cs | 16 + Ryujinx.HLE/OsHle/Process.cs | 21 + Ryujinx.HLE/Switch.cs | 1 + Ryujinx.ImGui/Config.cs | 169 ++++++ Ryujinx.ImGui/ConsoleLog.cs | 51 ++ Ryujinx.ImGui/EmulationController.cs | 37 ++ Ryujinx.ImGui/GUI/EmulationWindow.cs | 354 ++++++++++++ Ryujinx.ImGui/GUI/Values.cs | 22 + .../GUI/Widgets/ConfigurationWidget.cs | 102 ++++ Ryujinx.ImGui/GUI/Widgets/FilePicker.cs | 148 +++++ Ryujinx.ImGui/GUI/Widgets/HomeUI.cs | 92 +++ Ryujinx.ImGui/GUI/Widgets/InputPage.cs | 535 ++++++++++++++++++ Ryujinx.ImGui/GUI/Widgets/PauseUI.cs | 71 +++ Ryujinx.ImGui/GUI/WindowHelper.cs | 243 ++++++++ Ryujinx.ImGui/Program.cs | 15 + Ryujinx.ImGui/Ryujinx.UI.csproj | 35 ++ Ryujinx.ImGui/RyujinxUI.conf | 47 ++ Ryujinx.sln | 10 +- 25 files changed, 2034 insertions(+), 6 deletions(-) create mode 100644 Ryujinx.ImGui/Config.cs create mode 100644 Ryujinx.ImGui/ConsoleLog.cs create mode 100644 Ryujinx.ImGui/EmulationController.cs create mode 100644 Ryujinx.ImGui/GUI/EmulationWindow.cs create mode 100644 Ryujinx.ImGui/GUI/Values.cs create mode 100644 Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs create mode 100644 Ryujinx.ImGui/GUI/Widgets/FilePicker.cs create mode 100644 Ryujinx.ImGui/GUI/Widgets/HomeUI.cs create mode 100644 Ryujinx.ImGui/GUI/Widgets/InputPage.cs create mode 100644 Ryujinx.ImGui/GUI/Widgets/PauseUI.cs create mode 100644 Ryujinx.ImGui/GUI/WindowHelper.cs create mode 100644 Ryujinx.ImGui/Program.cs create mode 100644 Ryujinx.ImGui/Ryujinx.UI.csproj create mode 100644 Ryujinx.ImGui/RyujinxUI.conf diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs index 2d9fcb1415..7c2d9cd4f7 100644 --- a/ChocolArm64/ATranslator.cs +++ b/ChocolArm64/ATranslator.cs @@ -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,12 @@ namespace ChocolArm64 public bool EnableCpuTrace { get; set; } + public static long CyclesExecuted { get; set; } + + public static bool Pause { get; set; } = false; + + public static ManualResetEvent PauseResetEvent = new ManualResetEvent(false); + public ATranslator(IReadOnlyDictionary SymbolTable = null) { CachedSubs = new ConcurrentDictionary(); @@ -60,6 +67,11 @@ namespace ChocolArm64 AOpCode OpCode = ADecoder.DecodeOpCode(State, Memory, State.R15); OpCode.Interpreter(State, Memory, OpCode); + + CyclesExecuted++; + + while (Pause) + PauseResetEvent.WaitOne(1000); } while (State.R15 != 0 && State.Running); } @@ -89,6 +101,11 @@ namespace ChocolArm64 } Position = Sub.Execute(State, Memory); + + CyclesExecuted++; + + while (Pause) + PauseResetEvent.WaitOne(1000); } while (Position != 0 && State.Running); } diff --git a/Ryujinx.Audio/IAalOutput.cs b/Ryujinx.Audio/IAalOutput.cs index e903c5c5cc..1dfac377f7 100644 --- a/Ryujinx.Audio/IAalOutput.cs +++ b/Ryujinx.Audio/IAalOutput.cs @@ -1,6 +1,8 @@ +using System; + namespace Ryujinx.Audio { - public interface IAalOutput + public interface IAalOutput : IDisposable { int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback); diff --git a/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs b/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs index 1dd63202ba..4b1aeb2cf8 100644 --- a/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs +++ b/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs @@ -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); + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs index c6324c4a35..61d42dfa3b 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderer.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs @@ -2,7 +2,7 @@ using System; namespace Ryujinx.Graphics.Gal { - public interface IGalRenderer + public unsafe interface IGalRenderer : IDisposable { void QueueAction(Action ActionMthd); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index cd52762c79..8837f49b92 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs @@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - private class FrameBuffer + public class FrameBuffer { public int Width { get; set; } public int Height { get; set; } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs index ca70d4f666..40a26b3e91 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs @@ -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(); + } + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/NvGpu.cs b/Ryujinx.HLE/Gpu/NvGpu.cs index 625cb727fe..0b57599e4a 100644 --- a/Ryujinx.HLE/Gpu/NvGpu.cs +++ b/Ryujinx.HLE/Gpu/NvGpu.cs @@ -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(); + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Horizon.cs b/Ryujinx.HLE/OsHle/Horizon.cs index 70ae24be32..c2a84bbf3e 100644 --- a/Ryujinx.HLE/OsHle/Horizon.cs +++ b/Ryujinx.HLE/OsHle/Horizon.cs @@ -147,6 +147,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); diff --git a/Ryujinx.HLE/OsHle/Process.cs b/Ryujinx.HLE/OsHle/Process.cs index c7606dc902..8551480ab9 100644 --- a/Ryujinx.HLE/OsHle/Process.cs +++ b/Ryujinx.HLE/OsHle/Process.cs @@ -169,6 +169,27 @@ namespace Ryujinx.HLE.OsHle return true; } + public void Pause() + { + if (Disposed) + { + throw new ObjectDisposedException(nameof(Process)); + } + + ATranslator.Pause = true; + } + + public void Resume() + { + if (Disposed) + { + throw new ObjectDisposedException(nameof(Process)); + } + + ATranslator.Pause = false; + ATranslator.PauseResetEvent.Set(); + } + private void MapRWMemRegion(long Position, long Size, MemoryType Type) { Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW); diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index 74c0564a9f..2e17ca6c5d 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -98,6 +98,7 @@ namespace Ryujinx.HLE { Os.Dispose(); VFs.Dispose(); + Gpu.Dispose(); } } } diff --git a/Ryujinx.ImGui/Config.cs b/Ryujinx.ImGui/Config.cs new file mode 100644 index 0000000000..0fadb2757a --- /dev/null +++ b/Ryujinx.ImGui/Config.cs @@ -0,0 +1,169 @@ +using Ryujinx.HLE.Input; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Ryujinx +{ + public static class Config + { + public static JoyCon FakeJoyCon { get; internal set; } + + public static string IniPath { 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"))); + + 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); + } + } + } + } + + FakeJoyCon = new JoyCon + { + Left = new JoyConLeft + { + StickUp = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Stick_Up")), + StickDown = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Stick_Down")), + StickLeft = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Stick_Left")), + StickRight = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Stick_Right")), + StickButton = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Stick_Button")), + DPadUp = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_DPad_Up")), + DPadDown = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_DPad_Down")), + DPadLeft = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_DPad_Left")), + DPadRight = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_DPad_Right")), + ButtonMinus = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Button_Minus")), + ButtonL = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Button_L")), + ButtonZL = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Button_ZL")) + }, + + Right = new JoyConRight + { + StickUp = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Stick_Up")), + StickDown = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Stick_Down")), + StickLeft = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Stick_Left")), + StickRight = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Stick_Right")), + StickButton = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Stick_Button")), + ButtonA = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_A")), + ButtonB = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_B")), + ButtonX = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_X")), + ButtonY = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_Y")), + ButtonPlus = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_Plus")), + ButtonR = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_R")), + ButtonZR = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_ZR")) + } + }; + } + } + + // https://stackoverflow.com/a/37772571 + public class IniParser + { + private readonly Dictionary Values; + private readonly Dictionary Comments; + private 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(); + 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 Records = new List(); + 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; + } + } +} diff --git a/Ryujinx.ImGui/ConsoleLog.cs b/Ryujinx.ImGui/ConsoleLog.cs new file mode 100644 index 0000000000..1a2899946b --- /dev/null +++ b/Ryujinx.ImGui/ConsoleLog.cs @@ -0,0 +1,51 @@ +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Ryujinx +{ + static class ConsoleLog + { + private static Dictionary LogColors; + + private static object ConsoleLock; + + static ConsoleLog() + { + LogColors = new Dictionary() + { + { LogLevel.Stub, ConsoleColor.DarkGray }, + { LogLevel.Info, ConsoleColor.White }, + { LogLevel.Warning, ConsoleColor.Yellow }, + { LogLevel.Error, ConsoleColor.Red } + }; + + ConsoleLock = new object(); + } + + public static void PrintLog(object sender, LogEventArgs e) + { + string FormattedTime = e.Time.ToString(@"hh\:mm\:ss\.fff"); + + string CurrentThread = Thread.CurrentThread.ManagedThreadId.ToString("d4"); + + string Message = FormattedTime + " | " + CurrentThread + " " + e.Message; + + if (LogColors.TryGetValue(e.Level, out ConsoleColor Color)) + { + lock (ConsoleLock) + { + Console.ForegroundColor = Color; + + Console.WriteLine(Message); + Console.ResetColor(); + } + } + else + { + Console.WriteLine(Message); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.ImGui/EmulationController.cs b/Ryujinx.ImGui/EmulationController.cs new file mode 100644 index 0000000000..3e205f070c --- /dev/null +++ b/Ryujinx.ImGui/EmulationController.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Ryujinx.HLE; + +namespace Ryujinx.UI +{ + class EmulationController + { + public bool IsLoaded = false; + private Switch Ns; + + public EmulationController(Switch Ns) + { + this.Ns = Ns; + } + + public void Resume() + { + lock(Ns) + Ns.Os.ResumeAllProcesses(); + } + + public void Pause() + { + lock(Ns) + Ns.Os.PauseAllProcesses(); + } + + public void ShutDown() + { + lock (Ns) + Ns.Dispose(); + + } + } +} diff --git a/Ryujinx.ImGui/GUI/EmulationWindow.cs b/Ryujinx.ImGui/GUI/EmulationWindow.cs new file mode 100644 index 0000000000..35565ab4e1 --- /dev/null +++ b/Ryujinx.ImGui/GUI/EmulationWindow.cs @@ -0,0 +1,354 @@ +using ImGuiNET; +using OpenTK; +using Ryujinx.Audio; +using Ryujinx.Audio.OpenAL; +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Gal.OpenGL; +using Ryujinx.HLE; +using Ryujinx.HLE.Input; +using OpenTK.Graphics; +using OpenTK.Input; +using System; +using System.IO; + +namespace Ryujinx.UI +{ + partial class EmulationWindow : WindowHelper + { + //toggles + private bool showMainUI = true; + private bool showPauseUI; + private bool isRunning = false; + private bool IsRunning + { + get => isRunning; + set + { + isRunning = value; + UIActive = !value; + if (!value) + { + //ShowMainUI = true; + } + } + } + + private bool ShowMainUI + { + get => showMainUI; + set + { + showMainUI = value; + showPauseUI = !value && !isRunning; + UIActive = value; + } + } + + private bool ShowPauseUI + { + get => showPauseUI; + set + { + showPauseUI = value; + UIActive = value; + showMainUI = !value; + } + } + + private EmulationController EmulationController; + + private Page CurrentPage = Page.PackageLoader; + + private bool EscapePressed; + + private string CurrentPath = Environment.CurrentDirectory; + private string PackagePath = string.Empty; + + private const int TouchScreenWidth = 1280; + private const int TouchScreenHeight = 720; + + private const float TouchScreenRatioX = (float)TouchScreenWidth / TouchScreenHeight; + private const float TouchScreenRatioY = (float)TouchScreenHeight / TouchScreenWidth; + + FilePicker FileDialog; + + IGalRenderer Renderer; + IAalOutput AudioOut; + Switch Ns; + + public EmulationWindow() : base("Test") + { + FileDialog = FilePicker.GetFilePicker("rom",null); + + Renderer = new OGLRenderer(); + + AudioOut = new OpenALAudioOut(); + + Ns = new Switch(Renderer, AudioOut); + + Config.Read(Ns.Log); + + EmulationController = new EmulationController(Ns); + + Ns.Log.Updated += ConsoleLog.PrintLog; + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + + VSync = VSyncMode.On; + + Renderer.FrameBuffer.SetWindowSize(Width, Height); + } + + protected override void OnRenderFrame(FrameEventArgs e) + { + _deltaTime = (float)e.Time; + 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(); + + Title = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}"; + + SwapBuffers(); + + Ns.Os.SignalVsync(); + } + } + + protected override void OnUpdateFrame(FrameEventArgs e) + { + 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; + + //RightJoystick + if (Keyboard[(Key)Config.FakeJoyCon.Left.StickUp]) LeftJoystickDY = short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Left.StickDown]) LeftJoystickDY = -short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Left.StickLeft]) LeftJoystickDX = -short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Left.StickRight]) LeftJoystickDX = short.MaxValue; + + //LeftButtons + if (Keyboard[(Key)Config.FakeJoyCon.Left.StickButton]) CurrentButton |= HidControllerButtons.KEY_LSTICK; + if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadUp]) CurrentButton |= HidControllerButtons.KEY_DUP; + if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadDown]) CurrentButton |= HidControllerButtons.KEY_DDOWN; + if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadLeft]) CurrentButton |= HidControllerButtons.KEY_DLEFT; + if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadRight]) CurrentButton |= HidControllerButtons.KEY_DRIGHT; + if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonMinus]) CurrentButton |= HidControllerButtons.KEY_MINUS; + if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonL]) CurrentButton |= HidControllerButtons.KEY_L; + if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonZL]) CurrentButton |= HidControllerButtons.KEY_ZL; + + //RightJoystick + if (Keyboard[(Key)Config.FakeJoyCon.Right.StickUp]) RightJoystickDY = short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Right.StickDown]) RightJoystickDY = -short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Right.StickLeft]) RightJoystickDX = -short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Right.StickRight]) RightJoystickDX = short.MaxValue; + + //RightButtons + if (Keyboard[(Key)Config.FakeJoyCon.Right.StickButton]) CurrentButton |= HidControllerButtons.KEY_RSTICK; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonA]) CurrentButton |= HidControllerButtons.KEY_A; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonB]) CurrentButton |= HidControllerButtons.KEY_B; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonX]) CurrentButton |= HidControllerButtons.KEY_X; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonY]) CurrentButton |= HidControllerButtons.KEY_Y; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonPlus]) CurrentButton |= HidControllerButtons.KEY_PLUS; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonR]) CurrentButton |= HidControllerButtons.KEY_R; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonZR]) CurrentButton |= HidControllerButtons.KEY_ZR; + + 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?.GetState().LeftButton == ButtonState.Pressed) + { + 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); + + Ns.ProcessFrame(); + + Renderer.RunActions(); + } + else 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; + } + } + + public void LoadPackage(string path) + { + ShowMainUI = false; + MainContext.MakeCurrent(WindowInfo); + 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); + } + IsRunning = true; + EmulationController.IsLoaded = true; + } + + enum Page + { + Configuration, + Emulation, + PackageLoader + } + + } +} diff --git a/Ryujinx.ImGui/GUI/Values.cs b/Ryujinx.ImGui/GUI/Values.cs new file mode 100644 index 0000000000..0f7460ab67 --- /dev/null +++ b/Ryujinx.ImGui/GUI/Values.cs @@ -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); + } + } +} diff --git a/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs b/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs new file mode 100644 index 0000000000..856841c267 --- /dev/null +++ b/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ImGuiNET; +using System.Numerics; +using Ryujinx.HLE.Input; +using OpenTK.Input; + +namespace Ryujinx.UI.Widgets +{ + public partial class ConfigurationWidget + { + public static JoyCon CurrentJoyConLayout; + static Page CurrentPage = Page.General; + static bool ConfigIntialized = false; + static IniParser IniParser; + + static ConfigurationWidget() + { + IniParser = new IniParser(Config.IniPath); + } + + public static void Draw() + { + if(!ConfigIntialized) + { + CurrentJoyConLayout = Config.FakeJoyCon; + 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.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))) + { + Config.FakeJoyCon = CurrentJoyConLayout; + } + ImGui.SameLine(); + } + if (ImGui.Button("Save", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) + { + IniParser.Save(); + } + ImGui.SameLine(); + if (ImGui.Button("Discard", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) + { + IniParser = new IniParser(Config.IniPath); + } + } + } + + enum Page + { + General, + Input + } + } +} diff --git a/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs b/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs new file mode 100644 index 0000000000..d616b8822b --- /dev/null +++ b/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs @@ -0,0 +1,148 @@ +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 s_filePickers = new Dictionary(); + private static readonly Vector2 DefaultFilePickerSize = new Vector2(600, 400); + + public string CurrentFolder { get; set; } + public string SelectedFile { get; set; } + + public static FilePicker GetFilePicker(object o, 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 (!s_filePickers.TryGetValue(o, out FilePicker fp)) + { + fp = new FilePicker(); + fp.CurrentFolder = startingPath; + s_filePickers.Add(o, fp); + } + + return fp; + } + + public bool Draw(ref string selected, bool returnOnSelection) + { + bool result = false; + result = DrawFolder(ref selected, returnOnSelection); + return result; + } + + private bool DrawFolder(ref string selected, bool returnOnSelection = false) + { + ImGui.Text("Current Folder: " + CurrentFolder); + bool result = false; + + if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable() - new Vector2(20, Values.ButtonHeight), + WindowFlags.Default)) + { + DirectoryInfo di = new DirectoryInfo(CurrentFolder); + if (di.Exists) + { + if (di.Parent != null) + { + ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow); + + if (ImGui.Selectable("../", false, SelectableFlags.DontClosePopups + , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) + { + CurrentFolder = di.Parent.FullName; + } + + ImGui.PopStyleColor(); + } + foreach (var dir in Directory.EnumerateFileSystemEntries(di.FullName)) + { + if (Directory.Exists(dir)) + { + string name = Path.GetFileName(dir); + bool isSelected = SelectedFile == dir; + + ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow); + + if (ImGui.Selectable(name + "/", isSelected, SelectableFlags.DontClosePopups + , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) + { + SelectedFile = dir; + selected = SelectedFile; + } + + if (SelectedFile != null) + if (ImGui.IsMouseDoubleClicked(0) && SelectedFile.Equals(dir)) + { + SelectedFile = null; + selected = null; + CurrentFolder = dir; + } + + ImGui.PopStyleColor(); + } + } + foreach (var file in Directory.EnumerateFiles(di.FullName)) + { + string name = Path.GetFileName(file); + bool isSelected = SelectedFile == file; + + if (ImGui.Selectable(name, isSelected, SelectableFlags.DontClosePopups + , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) + { + SelectedFile = file; + if (returnOnSelection) + { + selected = SelectedFile; + } + } + + if (SelectedFile != null) + if (ImGui.IsMouseDoubleClicked(0) && SelectedFile.Equals(file)) + { + selected = file; + result = true; + } + } + } + } + ImGui.EndChildFrame(); + + + if (ImGui.Button("Cancel", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) + { + result = false; + } + + if (SelectedFile != null) + { + ImGui.SameLine(); + if (ImGui.Button("Load", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) + { + result = true; + selected = SelectedFile; + } + } + + return result; + } + } +} diff --git a/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs b/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs new file mode 100644 index 0000000000..8a25240a99 --- /dev/null +++ b/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs @@ -0,0 +1,92 @@ +using ImGuiNET; +using System; + +namespace Ryujinx.UI +{ + partial class EmulationWindow + { + void RenderMainUI() + { + 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("MainWindow", 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("Load Package", new System.Numerics.Vector2(Values.ButtonWidth, + Values.ButtonHeight))) + { + CurrentPage = Page.PackageLoader; + } + + 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.PackageLoader: + string output = CurrentPath; + if (FileDialog.Draw(ref output, false)) + { + if (!string.IsNullOrWhiteSpace(output)) + { + PackagePath = output; + LoadPackage(PackagePath); + } + } + break; + case Page.Configuration: + Widgets.ConfigurationWidget.Draw(); + break; + } + ImGui.EndChildFrame(); + } + ImGui.EndChildFrame(); + } + ImGui.EndWindow(); + } + } + + void DrawQuitButton() + { + if (ImGui.Button("Quit Ryujinx", new System.Numerics.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(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.ImGui/GUI/Widgets/InputPage.cs b/Ryujinx.ImGui/GUI/Widgets/InputPage.cs new file mode 100644 index 0000000000..8aabcb348b --- /dev/null +++ b/Ryujinx.ImGui/GUI/Widgets/InputPage.cs @@ -0,0 +1,535 @@ +using System; +using ImGuiNET; +using System.Numerics; +using Ryujinx.HLE.Input; +using OpenTK.Input; +using System.Linq; + + +namespace Ryujinx.UI.Widgets +{ + public partial class ConfigurationWidget + { + static bool[] Toggles = new bool[50]; + static float ContentWidth; + static Vector2 GroupSize; + static Key pressedKey; + static bool RequestPopup = false; + + public static void DrawInputPage() + { + Vector2 AvailableSpace = ImGui.GetContentRegionAvailable(); + GroupSize = new Vector2(AvailableSpace.X / 2, AvailableSpace.Y / 3); + + if (ImGui.BeginChildFrame(11, GroupSize, WindowFlags.AlwaysAutoResize)) + { + ContentWidth = (ImGui.GetContentRegionAvailableWidth() - 10) / 2; + GroupSize = ImGui.GetContentRegionMax(); + DrawLeftAnalog(); + ImGui.EndChildFrame(); + } + ImGui.SameLine(); + if (ImGui.BeginChildFrame(12, GroupSize, WindowFlags.AlwaysAutoResize)) + { + DrawRightAnalog(); + ImGui.EndChildFrame(); + } + + if (ImGui.BeginChildFrame(13, GroupSize, WindowFlags.AlwaysAutoResize)) + { + DrawDpad(); + ImGui.EndChildFrame(); + } + + ImGui.SameLine(); + if (ImGui.BeginChildFrame(14, GroupSize, WindowFlags.AlwaysAutoResize)) + { + DrawActionKeys(); + ImGui.EndChildFrame(); + } + + if (ImGui.BeginChildFrame(15, GroupSize, WindowFlags.AlwaysAutoResize)) + { + DrawTriggers(); + ImGui.EndChildFrame(); + } + + ImGui.SameLine(); + if (ImGui.BeginChildFrame(16, GroupSize, WindowFlags.AlwaysAutoResize)) + { + DrawExtras(); + ImGui.EndChildFrame(); + } + + if (Toggles.Contains(true)) + { + ImGui.OpenPopup("Enter Key"); + RequestPopup = true; + } + else + RequestPopup = false; + + if (ImGui.BeginPopupModal("Enter Key", WindowFlags.AlwaysAutoResize| WindowFlags.NoMove + | WindowFlags.NoResize)) + { + ImGui.Text("Please enter a key"); + if (!RequestPopup) + ImGui.CloseCurrentPopup(); + ImGui.EndPopup(); + } + } + + + static void DrawLeftAnalog() + { + // Show the Left Analog bindings + ImGui.Text("Left Analog"); + ImGuiNative.igBeginGroup(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickUp).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[0] = true; + } + if (Toggles[0]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Left.StickUp = (int)pressedKey; + Toggles[0] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickDown).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[1] = true; + } + if (Toggles[1]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Left.StickDown = (int)pressedKey; + Toggles[1] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickLeft).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[2] = true; + } + if (Toggles[2]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Left.StickLeft = (int)pressedKey; + Toggles[2] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickRight).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[3] = true; + } + if (Toggles[3]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Left.StickRight = (int)pressedKey; + Toggles[3] = false; + } + } + + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawRightAnalog() + { + //Show Right Analog Bindings + ImGui.Text("Right Analog"); + ImGuiNative.igBeginGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickUp).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[4] = true; + } + if (Toggles[4]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Right.StickUp = (int)pressedKey; + Toggles[4] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickDown).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[5] = true; + } + if (Toggles[5]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Right.StickDown = (int)pressedKey; + Toggles[5] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickLeft).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[6] = true; + } + if (Toggles[6]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Right.StickLeft = (int)pressedKey; + Toggles[6] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickRight).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[7] = true; + } + if (Toggles[7]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Right.StickRight = (int)pressedKey; + Toggles[7] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawDpad() + { + //Show DPad Bindings + ImGui.Text("D-Pad"); + ImGuiNative.igBeginGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadUp).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[8] = true; + } + if (Toggles[8]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Left.DPadUp = (int)pressedKey; + Toggles[8] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadDown).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[9] = true; + } + if (Toggles[9]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Left.DPadDown = (int)pressedKey; + Toggles[9] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadLeft).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[10] = true; + } + if (Toggles[10]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Left.DPadLeft = (int)pressedKey; + Toggles[10] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadRight).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[11] = true; + } + if (Toggles[11]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Left.DPadRight = (int)pressedKey; + Toggles[11] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawActionKeys() + { + //Show Action Key Bindings + ImGui.Text("Action Keys"); + ImGuiNative.igBeginGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("A"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonA).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[12] = true; + } + if (Toggles[12]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Right.ButtonA = (int)pressedKey; + Toggles[12] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("B"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonB).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[13] = true; + } + if (Toggles[13]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Right.ButtonB = (int)pressedKey; + Toggles[13] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("X"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonX).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[14] = true; + } + if (Toggles[14]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Right.ButtonX = (int)pressedKey; + Toggles[14] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Y"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonY).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[15] = true; + } + if (Toggles[15]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Right.ButtonY = (int)pressedKey; + Toggles[15] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawTriggers() + { + //Draw Triggers + ImGuiNative.igBeginGroup(); + + ImGui.Text("Triggers"); + + ImGuiNative.igBeginGroup(); + ImGui.Text("L"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.ButtonL).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[17] = true; + } + if (Toggles[17]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Left.ButtonL = (int)pressedKey; + Toggles[17] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("R"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonR).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[16] = true; + } + if (Toggles[16]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Right.ButtonR = (int)pressedKey; + Toggles[16] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("ZL"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.ButtonZL).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[19] = true; + } + if (Toggles[19]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Left.ButtonZL = (int)pressedKey; + Toggles[19] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("ZR"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonZR).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[18] = true; + } + if (Toggles[18]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Right.ButtonZR = (int)pressedKey; + Toggles[18] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawExtras() + { + //Draw Extra + ImGuiNative.igBeginGroup(); + ImGui.Text("Extra Keys"); + ImGuiNative.igBeginGroup(); + ImGui.Text("-"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.ButtonMinus).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[20] = true; + } + if (Toggles[20]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Left.ButtonMinus = (int)pressedKey; + Toggles[20] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("+"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonPlus).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[21] = true; + } + if (Toggles[21]) + { + if (GetKey(ref pressedKey)) + { + CurrentJoyConLayout.Right.ButtonPlus = (int)pressedKey; + Toggles[21] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static bool GetKey(ref Key pressedKey) + { + IO IO = ImGui.GetIO(); + foreach (Key key in Enum.GetValues(typeof(Key))) + { + if (IO.KeysDown[(int)key]) + { + pressedKey = key; + return true; + } + } + return false; + } + } +} \ No newline at end of file diff --git a/Ryujinx.ImGui/GUI/Widgets/PauseUI.cs b/Ryujinx.ImGui/GUI/Widgets/PauseUI.cs new file mode 100644 index 0000000000..d5d7926d91 --- /dev/null +++ b/Ryujinx.ImGui/GUI/Widgets/PauseUI.cs @@ -0,0 +1,71 @@ +using System; +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.Resume(); + EmulationController.ShutDown(); + ShowMainUI = true; + } + break; + case Page.Configuration: + Widgets.ConfigurationWidget.Draw(); + break; + } + ImGui.EndChildFrame(); + } + ImGui.EndChildFrame(); + } + ImGui.EndWindow(); + } + } + } +} diff --git a/Ryujinx.ImGui/GUI/WindowHelper.cs b/Ryujinx.ImGui/GUI/WindowHelper.cs new file mode 100644 index 0000000000..b9e429e4f7 --- /dev/null +++ b/Ryujinx.ImGui/GUI/WindowHelper.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenTK; +using OpenTK.Input; +using OpenTK.Graphics; +using OpenTK.Graphics.OpenGL; +using ImGuiNET; + +namespace Ryujinx.UI +{ + class WindowHelper : GameWindow + { + protected float _deltaTime; + bool IsWindowOpened = false; + int s_fontTexture; + float _wheelPosition; + protected GraphicsContext MainContext; + protected GraphicsContext UIContext; + protected bool UIActive; + + public WindowHelper(string title) : base(1280, 720, GraphicsMode.Default, title, GameWindowFlags.Default + , DisplayDevice.Default, 3, 3, GraphicsContextFlags.ForwardCompatible) + { + Title = title; + IsWindowOpened = true; + + Location = new Point( + (DisplayDevice.Default.Width / 2) - (Width / 2), + (DisplayDevice.Default.Height / 2) - (Height / 2)); + + MainContext = (GraphicsContext)Context; + + UIContext = new GraphicsContext(GraphicsMode.Default, + WindowInfo,4,5,GraphicsContextFlags.ForwardCompatible); + UIContext.MakeCurrent(WindowInfo); + UIActive = true; + } + + public void ShowDemo() + { + ImGuiNative.igShowDemoWindow(ref IsWindowOpened); + } + + 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 + s_fontTexture = GL.GenTexture(); + GL.BindTexture(TextureTarget.Texture2D, s_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(s_fontTexture); + + // Cleanup (don't clear the input data if you want to append new fonts later) + //io.Fonts->ClearInputData(); + io.FontAtlas.ClearTexData(); + GL.BindTexture(TextureTarget.Texture2D, 0); + } + + protected unsafe override void OnLoad(EventArgs e) + { + PrepareTexture(); + } + + unsafe void HandleInput(IO io) + { + MouseState cursorState = Mouse.GetCursorState(); + MouseState mouseState = Mouse.GetState(); + if (Focused) + { + Point windowPoint = PointToClient(new Point(cursorState.X, cursorState.Y)); + io.MousePosition = new System.Numerics.Vector2(windowPoint.X / io.DisplayFramebufferScale.X, + windowPoint.Y / io.DisplayFramebufferScale.Y); + + foreach (Key key in Enum.GetValues(typeof(Key))) + { + io.KeysDown[(int)key] = Keyboard[key]; + if (Keyboard[key]) + continue; + ImGuiNative.igGetIO()->KeyAlt = (byte)((Keyboard[Key.AltLeft] + || Keyboard[Key.AltRight]) ? 1 : 0); + ImGuiNative.igGetIO()->KeyCtrl = (byte)((Keyboard[Key.ControlLeft] + || Keyboard[Key.ControlRight]) ? 1 : 0); + ImGuiNative.igGetIO()->KeyShift = (byte)((Keyboard[Key.ShiftLeft] + || Keyboard[Key.ShiftRight]) ? 1 : 0); + ImGuiNative.igGetIO()->KeySuper = (byte)((Keyboard[Key.WinLeft] + || Keyboard[Key.WinRight]) ? 1 : 0); + } + } + else + { + io.MousePosition = new System.Numerics.Vector2(-1f, -1f); + for (int i = 0; i <= 512; i++) + { + io.KeysDown[i] = false; + } + } + + 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* draw_data) + { + // Rendering + int display_w, display_h; + display_w = Width; + display_h = Height; + + Vector4 clear_color = new Vector4(114f / 255f, 144f / 255f, 154f / 255f, 1.0f); + GL.Viewport(0, 0, display_w, display_h); + GL.ClearColor(clear_color.X, clear_color.Y, clear_color.Z, clear_color.W); + GL.Clear(ClearBufferMask.ColorBufferBit); + + // We are using the OpenGL fixed pipeline to make the example code simpler to read! + // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. + int last_texture; + GL.GetInteger(GetPName.TextureBinding2D, out last_texture); + GL.PushAttrib(AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.TransformBit); + GL.Enable(EnableCap.Blend); + GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.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(1); + + // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) + IO io = ImGui.GetIO(); + ImGui.ScaleClipRects(draw_data, io.DisplayFramebufferScale); + + // Setup orthographic projection matrix + 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 < draw_data->CmdListsCount; n++) + { + NativeDrawList* cmd_list = draw_data->CmdLists[n]; + byte* vtx_buffer = (byte*)cmd_list->VtxBuffer.Data; + ushort* idx_buffer = (ushort*)cmd_list->IdxBuffer.Data; + + GL.VertexPointer(2, VertexPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.PosOffset)); + GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.UVOffset)); + GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.ColOffset)); + + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + DrawCmd* pcmd = &(((DrawCmd*)cmd_list->CmdBuffer.Data)[cmd_i]); + 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)); + GL.DrawElements(PrimitiveType.Triangles, (int)pcmd->ElemCount, DrawElementsType.UnsignedShort, new IntPtr(idx_buffer)); + } + idx_buffer += 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(); + } + } +} diff --git a/Ryujinx.ImGui/Program.cs b/Ryujinx.ImGui/Program.cs new file mode 100644 index 0000000000..4830567316 --- /dev/null +++ b/Ryujinx.ImGui/Program.cs @@ -0,0 +1,15 @@ +using System; + +namespace Ryujinx.UI +{ + class Program + { + static void Main(string[] args) + { + EmulationWindow mainUI = new EmulationWindow(); + mainUI.Run(60.0, 60.0); + + Environment.Exit(0); + } + } +} diff --git a/Ryujinx.ImGui/Ryujinx.UI.csproj b/Ryujinx.ImGui/Ryujinx.UI.csproj new file mode 100644 index 0000000000..0206435cb4 --- /dev/null +++ b/Ryujinx.ImGui/Ryujinx.UI.csproj @@ -0,0 +1,35 @@ + + + + Exe + netcoreapp2.1 + + + + true + + + + true + false + + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/Ryujinx.ImGui/RyujinxUI.conf b/Ryujinx.ImGui/RyujinxUI.conf new file mode 100644 index 0000000000..611f320717 --- /dev/null +++ b/Ryujinx.ImGui/RyujinxUI.conf @@ -0,0 +1,47 @@ +#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 = + +#https://github.com/opentk/opentk/blob/develop/src/OpenTK/Input/Key.cs +Controls_Left_FakeJoycon_Stick_Up = 105 +Controls_Left_FakeJoycon_Stick_Down = 101 +Controls_Left_FakeJoycon_Stick_Left = 83 +Controls_Left_FakeJoycon_Stick_Right = 86 +Controls_Left_FakeJoycon_Stick_Button = 88 +Controls_Left_FakeJoycon_DPad_Up = 45 +Controls_Left_FakeJoycon_DPad_Down = 46 +Controls_Left_FakeJoycon_DPad_Left = 47 +Controls_Left_FakeJoycon_DPad_Right = 48 +Controls_Left_FakeJoycon_Button_Minus = 120 +Controls_Left_FakeJoycon_Button_L = 87 +Controls_Left_FakeJoycon_Button_ZL = 99 + +Controls_Right_FakeJoycon_Stick_Up = 91 +Controls_Right_FakeJoycon_Stick_Down = 93 +Controls_Right_FakeJoycon_Stick_Left = 92 +Controls_Right_FakeJoycon_Stick_Right = 94 +Controls_Right_FakeJoycon_Stick_Button = 90 +Controls_Right_FakeJoycon_Button_A = 108 +Controls_Right_FakeJoycon_Button_B = 106 +Controls_Right_FakeJoycon_Button_X = 85 +Controls_Right_FakeJoycon_Button_Y = 104 +Controls_Right_FakeJoycon_Button_Plus = 121 +Controls_Right_FakeJoycon_Button_R = 103 +Controls_Right_FakeJoycon_Button_ZR = 97 \ No newline at end of file diff --git a/Ryujinx.sln b/Ryujinx.sln index cd04dabc20..97fe49d623 100644 --- a/Ryujinx.sln +++ b/Ryujinx.sln @@ -15,9 +15,11 @@ 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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.UI", "Ryujinx.ImGui\Ryujinx.UI.csproj", "{00117502-1661-4C8B-8C07-177C1A8AA455}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -57,6 +59,10 @@ 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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From f1ffb129d660476729cf9ed000b089cdcbc78342 Mon Sep 17 00:00:00 2001 From: emmaus Date: Sun, 17 Jun 2018 09:37:34 +0000 Subject: [PATCH 02/11] Implemented Gamelist --- Ryujinx.HLE/Loaders/Executables/Nro.cs | 21 +- Ryujinx.HLE/Logging/Logger.cs | 10 + Ryujinx.HLE/VirtualFileSystem.cs | 2 +- Ryujinx.ImGui/Config.cs | 67 +- Ryujinx.ImGui/Extensions/ControlArchive.cs | 53 + Ryujinx.ImGui/Extensions/Nro.cs | 72 ++ Ryujinx.ImGui/GUI/EmulationWindow.cs | 8 +- .../GUI/Widgets/ConfigurationWidget.cs | 34 +- Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs | 127 +++ Ryujinx.ImGui/GUI/Widgets/GameList.cs | 198 ++++ Ryujinx.ImGui/GUI/Widgets/HomeUI.cs | 9 + Ryujinx.ImGui/GUI/Widgets/NanoJpeg.cs | 1008 +++++++++++++++++ Ryujinx.ImGui/GUI/WindowHelper.cs | 9 +- Ryujinx.ImGui/Ryujinx.UI.csproj | 1 + Ryujinx/Properties/launchSettings.json | 8 + 15 files changed, 1611 insertions(+), 16 deletions(-) create mode 100644 Ryujinx.ImGui/Extensions/ControlArchive.cs create mode 100644 Ryujinx.ImGui/Extensions/Nro.cs create mode 100644 Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs create mode 100644 Ryujinx.ImGui/GUI/Widgets/GameList.cs create mode 100644 Ryujinx.ImGui/GUI/Widgets/NanoJpeg.cs create mode 100644 Ryujinx/Properties/launchSettings.json diff --git a/Ryujinx.HLE/Loaders/Executables/Nro.cs b/Ryujinx.HLE/Loaders/Executables/Nro.cs index 0b5068d7b9..4861920c7f 100644 --- a/Ryujinx.HLE/Loaders/Executables/Nro.cs +++ b/Ryujinx.HLE/Loaders/Executables/Nro.cs @@ -1,8 +1,11 @@ +using System; +using System.Drawing; using System.IO; +using System.Text; namespace Ryujinx.HLE.Loaders.Executables { - class Nro : IExecutable + public class Nro : IExecutable { public string FilePath { get; private set; } @@ -15,10 +18,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); @@ -39,11 +43,12 @@ namespace Ryujinx.HLE.Loaders.Executables int DataSize = Reader.ReadInt32(); int BssSize = Reader.ReadInt32(); - this.Mod0Offset = Mod0Offset; - this.TextOffset = TextOffset; - this.ROOffset = ROOffset; - this.DataOffset = DataOffset; - this.BssSize = BssSize; + this.Mod0Offset = Mod0Offset; + this.TextOffset = TextOffset; + this.ROOffset = ROOffset; + this.DataOffset = DataOffset; + this.BssSize = BssSize; + this.FileSize = FileSize; byte[] Read(long Position, int Size) { diff --git a/Ryujinx.HLE/Logging/Logger.cs b/Ryujinx.HLE/Logging/Logger.cs index 5376b253a3..8603810ee6 100644 --- a/Ryujinx.HLE/Logging/Logger.cs +++ b/Ryujinx.HLE/Logging/Logger.cs @@ -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)); diff --git a/Ryujinx.HLE/VirtualFileSystem.cs b/Ryujinx.HLE/VirtualFileSystem.cs index df1fc9db13..8fac345c1c 100644 --- a/Ryujinx.HLE/VirtualFileSystem.cs +++ b/Ryujinx.HLE/VirtualFileSystem.cs @@ -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"; diff --git a/Ryujinx.ImGui/Config.cs b/Ryujinx.ImGui/Config.cs index 0fadb2757a..289da4731a 100644 --- a/Ryujinx.ImGui/Config.cs +++ b/Ryujinx.ImGui/Config.cs @@ -1,4 +1,5 @@ -using Ryujinx.HLE.Input; +using Ryujinx.HLE; +using Ryujinx.HLE.Input; using Ryujinx.HLE.Logging; using System; using System.Collections.Generic; @@ -14,6 +15,8 @@ namespace Ryujinx 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); @@ -92,6 +95,68 @@ namespace Ryujinx ButtonZR = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_ZR")) } }; + + DefaultGameDirectory = Parser.GetValue("Default_Game_Directory"); + + if (string.IsNullOrWhiteSpace(DefaultGameDirectory)) + { + VirtualFileSystem FS = new HLE.VirtualFileSystem(); + DefaultGameDirectory = Path.Combine(FS.GetSdCardPath(), "switch"); + } + } + + 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 FilteredClasses = new List(); + + 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_FakeJoycon_Stick_Up", FakeJoyCon.Left.StickUp.ToString()); + Parser.SetValue("Controls_Left_FakeJoycon_Stick_Down", FakeJoyCon.Left.StickDown.ToString()); + Parser.SetValue("Controls_Left_FakeJoycon_Stick_Left", FakeJoyCon.Left.StickLeft.ToString()); + Parser.SetValue("Controls_Left_FakeJoycon_Stick_Right", FakeJoyCon.Left.StickRight.ToString()); + Parser.SetValue("Controls_Left_FakeJoycon_Stick_Button", FakeJoyCon.Left.StickButton.ToString()); + Parser.SetValue("Controls_Left_FakeJoycon_DPad_Up", FakeJoyCon.Left.DPadUp.ToString()); + Parser.SetValue("Controls_Left_FakeJoycon_DPad_Down", FakeJoyCon.Left.DPadDown.ToString()); + Parser.SetValue("Controls_Left_FakeJoycon_DPad_Left", FakeJoyCon.Left.DPadLeft.ToString()); + Parser.SetValue("Controls_Left_FakeJoycon_DPad_Right", FakeJoyCon.Left.DPadRight.ToString()); + Parser.SetValue("Controls_Left_FakeJoycon_Button_Minus", FakeJoyCon.Left.ButtonMinus.ToString()); + Parser.SetValue("Controls_Left_FakeJoycon_Button_L", FakeJoyCon.Left.ButtonL.ToString()); + Parser.SetValue("Controls_Left_FakeJoycon_Button_ZL", FakeJoyCon.Left.ButtonZL.ToString()); + + Parser.SetValue("Controls_Right_FakeJoycon_Stick_Up", FakeJoyCon.Right.StickUp.ToString()); + Parser.SetValue("Controls_Right_FakeJoycon_Stick_Down", FakeJoyCon.Right.StickDown.ToString()); + Parser.SetValue("Controls_Right_FakeJoycon_Stick_Left", FakeJoyCon.Right.StickLeft.ToString()); + Parser.SetValue("Controls_Right_FakeJoycon_Stick_Right", FakeJoyCon.Right.StickRight.ToString()); + Parser.SetValue("Controls_Right_FakeJoycon_Stick_Button", FakeJoyCon.Right.StickButton.ToString()); + Parser.SetValue("Controls_Right_FakeJoycon_Button_A", FakeJoyCon.Right.StickUp.ToString()); + Parser.SetValue("Controls_Right_FakeJoycon_Button_B", FakeJoyCon.Right.StickUp.ToString()); + Parser.SetValue("Controls_Right_FakeJoycon_Button_X", FakeJoyCon.Right.StickUp.ToString()); + Parser.SetValue("Controls_Right_FakeJoycon_Button_Y", FakeJoyCon.Right.StickUp.ToString()); + Parser.SetValue("Controls_Right_FakeJoycon_Button_Plus", FakeJoyCon.Right.StickUp.ToString()); + Parser.SetValue("Controls_Right_FakeJoycon_Button_R", FakeJoyCon.Right.StickUp.ToString()); + Parser.SetValue("Controls_Right_FakeJoycon_Button_ZR", FakeJoyCon.Right.StickUp.ToString()); + + Parser.SetValue("Default_Game_Directory", DefaultGameDirectory); + + Parser.Save(); } } diff --git a/Ryujinx.ImGui/Extensions/ControlArchive.cs b/Ryujinx.ImGui/Extensions/ControlArchive.cs new file mode 100644 index 0000000000..b598e527a7 --- /dev/null +++ b/Ryujinx.ImGui/Extensions/ControlArchive.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +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; + } +} diff --git a/Ryujinx.ImGui/Extensions/Nro.cs b/Ryujinx.ImGui/Extensions/Nro.cs new file mode 100644 index 0000000000..35f32fa390 --- /dev/null +++ b/Ryujinx.ImGui/Extensions/Nro.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using Ryujinx.HLE.Loaders; + +namespace Ryujinx.UI +{ + class Nro : HLE.Loaders.Executables.Nro + { + public byte[] AssetRomfData { get; set; } + public byte[] IconData { get; set; } + + private byte[] NACPData { get; set; } + + public int AssetOffset { get; set; } + + public ControlArchive ControlArchive { 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); + } + } + } +} diff --git a/Ryujinx.ImGui/GUI/EmulationWindow.cs b/Ryujinx.ImGui/GUI/EmulationWindow.cs index 35565ab4e1..9e1f685ece 100644 --- a/Ryujinx.ImGui/GUI/EmulationWindow.cs +++ b/Ryujinx.ImGui/GUI/EmulationWindow.cs @@ -57,7 +57,7 @@ namespace Ryujinx.UI private EmulationController EmulationController; - private Page CurrentPage = Page.PackageLoader; + private Page CurrentPage = Page.GameList; private bool EscapePressed; @@ -74,7 +74,7 @@ namespace Ryujinx.UI IGalRenderer Renderer; IAalOutput AudioOut; - Switch Ns; + public static Switch Ns; public EmulationWindow() : base("Test") { @@ -107,7 +107,7 @@ namespace Ryujinx.UI _deltaTime = (float)e.Time; if (UIActive) { - StartFrame(); + StartFrame(); isRunning = false; if (ShowMainUI) { @@ -119,6 +119,7 @@ namespace Ryujinx.UI showMainUI = false; RenderPauseUI(); } + ImGuiNative.igShowMetricsWindow(ref UIActive); EndFrame(); } else @@ -347,6 +348,7 @@ namespace Ryujinx.UI { Configuration, Emulation, + GameList, PackageLoader } diff --git a/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs b/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs index 856841c267..f1251c7b00 100644 --- a/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs +++ b/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs @@ -13,11 +13,16 @@ namespace Ryujinx.UI.Widgets public static JoyCon CurrentJoyConLayout; static Page CurrentPage = Page.General; static bool ConfigIntialized = false; + static bool OpenFolderPicker; + static string CurrentPath; static IniParser IniParser; + static FolderPicker FolderPicker; static ConfigurationWidget() { IniParser = new IniParser(Config.IniPath); + FolderPicker = FolderPicker.GetFolderPicker("FolderDialog",Config.DefaultGameDirectory); + CurrentPath = Config.DefaultGameDirectory.ToString(); } public static void Draw() @@ -54,6 +59,33 @@ namespace Ryujinx.UI.Widgets 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("OpenFolder"); + + ImGui.SetNextWindowSize(new Vector2(500, 500), Condition.FirstUseEver); + if(ImGui.BeginPopupModal("OpenFolder",WindowFlags.NoResize)) + { + string output = CurrentPath; + if (FolderPicker.Draw(ref output, false)) + { + if (!string.IsNullOrWhiteSpace(output)) + { + Config.DefaultGameDirectory = output; + } + ImGui.CloseCurrentPopup(); + OpenFolderPicker = false; + } + ImGui.EndPopup(); + } + ImGui.Spacing(); ImGui.Checkbox("Disable Cpu Memory Checks", ref AOptimizations.DisableMemoryChecks); ImGui.EndChild(); @@ -83,7 +115,7 @@ namespace Ryujinx.UI.Widgets } if (ImGui.Button("Save", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { - IniParser.Save(); + Config.Save(EmulationWindow.Ns.Log); } ImGui.SameLine(); if (ImGui.Button("Discard", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) diff --git a/Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs b/Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs new file mode 100644 index 0000000000..9d9039715a --- /dev/null +++ b/Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs @@ -0,0 +1,127 @@ +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 FolderPicker + { + private const string FilePickerID = "###FilePicker"; + private static readonly Dictionary s_folderPickers + = new Dictionary(); + private static readonly Vector2 DefaultFilePickerSize = new Vector2(600, 400); + + public string CurrentFolder { get; set; } + public string SelectedFile { get; set; } + + public static FolderPicker GetFolderPicker(object o, 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 (!s_folderPickers.TryGetValue(o, out FolderPicker fp)) + { + fp = new FolderPicker(); + fp.CurrentFolder = startingPath; + s_folderPickers.Add(o, fp); + } + + return fp; + } + + public bool Draw(ref string selected, bool returnOnSelection) + { + bool result = false; + result = DrawFolder(ref selected, returnOnSelection); + return result; + } + + private bool DrawFolder(ref string selected, bool returnOnSelection = false) + { + ImGui.Text("Current Folder: " + CurrentFolder); + bool result = false; + + if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable() - new Vector2(20, Values.ButtonHeight), + WindowFlags.Default)) + { + DirectoryInfo di = new DirectoryInfo(CurrentFolder); + if (di.Exists) + { + if (di.Parent != null) + { + ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow); + + if (ImGui.Selectable("../", false, SelectableFlags.DontClosePopups + , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) + { + CurrentFolder = di.Parent.FullName; + } + + ImGui.PopStyleColor(); + } + foreach (var dir in Directory.EnumerateFileSystemEntries(di.FullName)) + { + if (Directory.Exists(dir)) + { + string name = Path.GetFileName(dir); + bool isSelected = SelectedFile == dir; + + ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow); + + if (ImGui.Selectable(name + "/", isSelected, SelectableFlags.DontClosePopups + , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) + { + SelectedFile = dir; + selected = SelectedFile; + } + + if (SelectedFile != null) + if (ImGui.IsMouseDoubleClicked(0) && SelectedFile.Equals(dir)) + { + SelectedFile = null; + selected = null; + CurrentFolder = dir; + } + + ImGui.PopStyleColor(); + } + } + } + } + ImGui.EndChildFrame(); + + + if (ImGui.Button("Cancel", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) + { + result = false; + } + + if (SelectedFile != null) + { + ImGui.SameLine(); + if (ImGui.Button("Open", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) + { + result = true; + selected = SelectedFile; + } + } + + return result; + } + } +} diff --git a/Ryujinx.ImGui/GUI/Widgets/GameList.cs b/Ryujinx.ImGui/GUI/Widgets/GameList.cs new file mode 100644 index 0000000000..d4a3ce4530 --- /dev/null +++ b/Ryujinx.ImGui/GUI/Widgets/GameList.cs @@ -0,0 +1,198 @@ +using System; +using System.IO; +using System.Drawing; +using System.Drawing.Imaging; +using System.Collections.Generic; +using System.Text; +using ImGuiNET; +using System.Numerics; +using NanoJpeg; +using OpenTK.Graphics.OpenGL; + +namespace Ryujinx.UI.Widgets +{ + class GameList + { + static List GameItems = new List(); + static GameItem SelectedGame; + static bool OpenFolderPicker; + static FolderPicker FolderPicker; + static string CurrentPath; + + static GameList() + { + Refresh(Config.DefaultGameDirectory); + FolderPicker = FolderPicker.GetFolderPicker("FolderDialog", Config.DefaultGameDirectory); + } + + public unsafe static void Refresh(string Path) + { + GameItems = new List(); + 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); + NanoJpeg.NJImage image = new NJImage(); + image.Decode(GameItem.GetIconData()); + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, image.Width, image.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgb, + PixelType.UnsignedByte, new IntPtr(image.Image)); + image.Dispose(); + GL.BindTexture(TextureTarget.Texture2D, 0); + } + GameItems.Add(GameItem); + } + } + else if (Directory.Exists(Path)) + { + + } + + } + } + + public unsafe static void 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("OpenFolder"); + + ImGui.SetNextWindowSize(new Vector2(500, 500), Condition.FirstUseEver); + if (ImGui.BeginPopupModal("OpenFolder", WindowFlags.NoResize)) + { + string output = CurrentPath; + if (FolderPicker.Draw(ref output, false)) + { + if (!string.IsNullOrWhiteSpace(output)) + { + Config.DefaultGameDirectory = output; + Refresh(output); + } + ImGui.CloseCurrentPopup(); + OpenFolderPicker = false; + } + ImGui.EndPopup(); + } + 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) + { + + } + else if (ImGui.IsMouseClicked(0) && ImGui.IsItemHovered(HoveredFlags.AllowWhenOverlapped | HoveredFlags.RootAndChildWindows)) + { + SelectedGame = GameItem; + } + ImGui.EndChildFrame(); + } + } + + ImGui.EndChildFrame(); + } + } + } + + class GameItem + { + public AppletType AppletType; + public string Path; + public Nro Nro; + public bool IsNro; + public bool HasIcon => Nro?.IconData != null; + public int TextureID; + + public GameItem(string Path) + { + this.Path = Path; + + if (File.Exists(Path)) + { + AppletType = AppletType.Homebrew; + FileInfo Package = new FileInfo(Path); + if (Package.Extension.ToLower() == ".nro") + { + IsNro = true; + Nro = new Nro(File.Open(Path, FileMode.Open), new FileInfo(Path).Name); + } + } + else + AppletType = AppletType.Cartridge; + } + + public Bitmap GetBitmap() + { + if (IsNro) + { + return new Bitmap(new Bitmap(new MemoryStream(Nro.IconData)),new Size(50,50)); + } + else return null; + } + + public byte[] GetIconData() + { + if (IsNro) + { + return Nro.IconData; + } + else return null; + } + } + + enum AppletType + { + Homebrew, + Cartridge + } +} diff --git a/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs b/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs index 8a25240a99..c53dfb2732 100644 --- a/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs +++ b/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs @@ -24,6 +24,12 @@ namespace Ryujinx.UI CurrentPage = Page.PackageLoader; } + if (ImGui.Button("Game List", new System.Numerics.Vector2(Values.ButtonWidth, + Values.ButtonHeight))) + { + CurrentPage = Page.GameList; + } + if (ImGui.Button("Settings", new System.Numerics.Vector2(Values.ButtonWidth, Values.ButtonHeight))) { @@ -54,6 +60,9 @@ namespace Ryujinx.UI case Page.Configuration: Widgets.ConfigurationWidget.Draw(); break; + case Page.GameList: + Widgets.GameList.DrawList(); + break; } ImGui.EndChildFrame(); } diff --git a/Ryujinx.ImGui/GUI/Widgets/NanoJpeg.cs b/Ryujinx.ImGui/GUI/Widgets/NanoJpeg.cs new file mode 100644 index 0000000000..fc7b708434 --- /dev/null +++ b/Ryujinx.ImGui/GUI/Widgets/NanoJpeg.cs @@ -0,0 +1,1008 @@ +/////////////////////////////////////////////////////////////////////////////// +// INFO // +/////////////////////////////////////////////////////////////////////////////// + +// NanoJPEG -- Unmanaged C# Port +// version 1.0.0 (10-Aug-2015) +// by Johannes Bildstein +// original license below + +/////////////////////////////////////////////////////////////////////////////// +// START ORIGINAL LICENSE SECTION // +/////////////////////////////////////////////////////////////////////////////// + +// NanoJPEG -- KeyJ's Tiny Baseline JPEG Decoder +// version 1.3.2 (2014-02-02) +// by Martin J. Fiedler +// +// This software is published under the terms of KeyJ's Research License, +// version 0.2. Usage of this software is subject to the following conditions: +// 0. There's no warranty whatsoever. The author(s) of this software can not +// be held liable for any damages that occur when using this software. +// 1. This software may be used freely for both non-commercial and commercial +// purposes. +// 2. This software may be redistributed freely as long as no fees are charged +// for the distribution and this license information is included. +// 3. This software may be modified freely except for this license information, +// which must not be changed in any way. +// 4. If anything other than configuration, indentation or comments have been +// altered in the code, the original author(s) must receive a copy of the +// modified code. + +/////////////////////////////////////////////////////////////////////////////// +// END ORIGINAL LICENSE SECTION // +/////////////////////////////////////////////////////////////////////////////// + +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace NanoJpeg +{ + /// + /// Error codes for decoding errors + /// + public enum NJErrorCode + { + /// + /// Not a JPEG file + /// + NoJpeg, + /// + /// Unsupported format + /// + Unsupported, + /// + /// Internal error + /// + InternalError, + /// + /// Syntax error + /// + SyntaxError, + } + + /// + /// Exception for decoding errors + /// + public class NJException : Exception + { + /// + /// The error code of this exception + /// + public NJErrorCode ErrorCode + { + get { return _ErrorCode; } + } + private NJErrorCode _ErrorCode = NJErrorCode.InternalError; + + /// + /// Creates a new instance of the class + /// + /// The error code of this exception + public NJException(NJErrorCode ErrorCode) + : base(ErrorCode.ToString()) + { + _ErrorCode = ErrorCode; + } + } + + /// + /// Provides methods to decode a Jpeg image. + /// NOT thread safe + /// + public unsafe sealed class NJImage : IDisposable + { + #region Variables/Constants + + private bool IsDisposed; + private bool IsDone; + + private byte* pos; + private int size; + private int length; + private int width, height; + private int mbwidth, mbheight; + private int mbsizex, mbsizey; + private int ncomp; + private Component* comp; + private int qtused, qtavail; + private byte** qtab; + private VLCCode** vlctab; + private int buf, bufbits; + private int* block; + private int rstinterval; + private byte* rgb; + + const int W1 = 2841; + const int W2 = 2676; + const int W3 = 2408; + const int W5 = 1609; + const int W6 = 1108; + const int W7 = 565; + + const int CF4A = -9; + const int CF4B = 111; + const int CF4C = 29; + const int CF4D = -3; + const int CF3A = 28; + const int CF3B = 109; + const int CF3C = -9; + const int CF3X = 104; + const int CF3Y = 27; + const int CF3Z = -3; + const int CF2A = 139; + const int CF2B = -11; + + static byte[] njZZ = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, +11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, +42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, +38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; + + #endregion + + #region Properties + + /// + /// The width of the last decoded image + /// + public int Width + { + get { return width; } + } + /// + /// The height of the last decoded image + /// + public int Height + { + get { return height; } + } + /// + /// States if the last decoded image is a color (RGB) or grayscale image + /// + public bool IsColor + { + get { return ncomp != 1; } + } + /// + /// Pointer to the pixels + /// + public byte* Image + { + get + { + if (ncomp == 1) return comp[0].pixels; + else return rgb; + } + } + /// + /// Size of the image in bytes + /// + public int ImageSize + { + get { return width * height * ncomp; } + } + + #endregion + + #region Helper Structs + + private struct VLCCode + { + public byte bits; + public byte code; + } + + private struct Component + { + public int cid; + public int ssx; + public int ssy; + public int width; + public int height; + public int stride; + public int qtsel; + public int actabsel; + public int dctabsel; + public int dcpred; + public byte* pixels; + } + + #endregion + + #region Init/Dispose + + /// + /// Creates a new instance of the class + /// + public NJImage() + { + comp = (Component*)Marshal.AllocHGlobal(3 * Marshal.SizeOf(typeof(Component))); + block = (int*)Marshal.AllocHGlobal(64 * Marshal.SizeOf(typeof(int))); + + FillMem(comp, new Component(), 3); + + qtab = (byte**)Marshal.AllocHGlobal(4 * IntPtr.Size); + vlctab = (VLCCode**)Marshal.AllocHGlobal(4 * IntPtr.Size); + for (int i = 0; i < 4; i++) + { + qtab[i] = (byte*)Marshal.AllocHGlobal(64 * Marshal.SizeOf(typeof(byte))); + vlctab[i] = (VLCCode*)Marshal.AllocHGlobal(65536 * Marshal.SizeOf(typeof(VLCCode))); + + FillMem((long*)qtab[i], 0, 64 / 8);//use long instead of byte + FillMem((long*)vlctab[i], 0, 65536 / 4);//use long instead of VLCCode (length=2) + } + } + + /// + /// Finalizer of the class + /// + ~NJImage() + { + Dispose(false); + } + + /// + /// Releases all allocated resources + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool managed) + { + if (!IsDisposed) + { + if (rgb != null) + { + Marshal.FreeHGlobal((IntPtr)rgb); + rgb = null; + } + + for (int i = 0; i < 4; i++) + { + if (qtab[i] != null) Marshal.FreeHGlobal((IntPtr)qtab[i]); + if (vlctab[i] != null) Marshal.FreeHGlobal((IntPtr)vlctab[i]); + } + + if (qtab != null) Marshal.FreeHGlobal((IntPtr)qtab); + if (vlctab != null) Marshal.FreeHGlobal((IntPtr)vlctab); + if (comp != null) Marshal.FreeHGlobal((IntPtr)comp); + if (block != null) Marshal.FreeHGlobal((IntPtr)block); + + IsDisposed = true; + } + } + + #endregion + + #region Public Methods + + /// + /// Decodes a jpeg image + /// + /// Path to the image file + public void Decode(string jpeg) + { + byte[] data = File.ReadAllBytes(jpeg); + fixed (byte* ptr = data) + { + Decode(ptr, data.Length, false); + } + } + + /// + /// Decodes a jpeg image + /// + /// The stream that contains the jpeg data + public void Decode(Stream jpeg) + { + byte[] data = new byte[jpeg.Length]; + jpeg.Read(data, 0, (int)jpeg.Length); + + fixed (byte* ptr = data) + { + Decode(ptr, data.Length, false); + } + } + + /// + /// Decodes a jpeg image + /// + /// The stream that contains the jpeg data + public void Decode(MemoryStream jpeg) + { + fixed (byte* ptr = jpeg.GetBuffer()) + { + Decode(ptr, (int)jpeg.Length, false); + } + } + + /// + /// Decodes a jpeg image + /// + /// The stream that contains the jpeg data + public void Decode(UnmanagedMemoryStream jpeg) + { + Decode(jpeg.PositionPointer, (int)jpeg.Length, false); + } + + /// + /// Decodes a jpeg image + /// + /// + public void Decode(byte[] jpeg) + { + fixed(byte* ptr = jpeg) + { + Decode(ptr, jpeg.Length, false); + } + } + + /// + /// Decodes a jpeg image + /// + /// Pointer to the jpeg data + /// Size of the jpeg data in bytes + public void Decode(byte* jpeg, int size) + { + Decode(jpeg, size, false); + } + + /// + /// Decodes a jpeg image + /// + /// Pointer to the jpeg data + /// Size of the jpeg data in bytes + /// True to flip the Red and Blue channel. This is useful for System.Drawing (GDI+) classes. + public void Decode(byte* jpeg, int size, bool flip) + { + Init(); + + this.pos = jpeg; + this.size = size & 0x7FFFFFFF; + if (this.size < 2) throw new NJException(NJErrorCode.NoJpeg); + if (((this.pos[0] ^ 0xFF) | (this.pos[1] ^ 0xD8)) != 0) throw new NJException(NJErrorCode.NoJpeg); + Skip(2); + while (!IsDone) + { + if ((this.size < 2) || (this.pos[0] != 0xFF)) throw new NJException(NJErrorCode.SyntaxError); + Skip(2); + switch (this.pos[-1]) + { + case 0xC0: DecodeSOF(); break; + case 0xC4: DecodeDHT(); break; + case 0xDB: DecodeDQT(); break; + case 0xDD: DecodeDRI(); break; + case 0xDA: DecodeScan(); break; + case 0xFE: SkipMarker(); break; + default: + if ((this.pos[-1] & 0xF0) == 0xE0) SkipMarker(); + else throw new NJException(NJErrorCode.Unsupported); + break; + } + } + ConvertYCC(flip); + } + + #endregion + + #region Private Methods + + private void Init() + { + if (rgb != null) + { + Marshal.FreeHGlobal((IntPtr)rgb); + rgb = null; + } + + FillMem(comp, new Component(), 3); + IsDone = false; + bufbits = 0; + } + + private void RowIDCT(int* blk) + { + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + if (((x1 = blk[4] << 11) + | (x2 = blk[6]) + | (x3 = blk[2]) + | (x4 = blk[1]) + | (x5 = blk[7]) + | (x6 = blk[5]) + | (x7 = blk[3])) == 0) + { + blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = blk[0] << 3; + return; + } + x0 = (blk[0] << 11) + 128; + x8 = W7 * (x4 + x5); + x4 = x8 + (W1 - W7) * x4; + x5 = x8 - (W1 + W7) * x5; + x8 = W3 * (x6 + x7); + x6 = x8 - (W3 - W5) * x6; + x7 = x8 - (W3 + W5) * x7; + x8 = x0 + x1; + x0 -= x1; + x1 = W6 * (x3 + x2); + x2 = x1 - (W2 + W6) * x2; + x3 = x1 + (W2 - W6) * x3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181 * (x4 + x5) + 128) >> 8; + x4 = (181 * (x4 - x5) + 128) >> 8; + blk[0] = (x7 + x1) >> 8; + blk[1] = (x3 + x2) >> 8; + blk[2] = (x0 + x4) >> 8; + blk[3] = (x8 + x6) >> 8; + blk[4] = (x8 - x6) >> 8; + blk[5] = (x0 - x4) >> 8; + blk[6] = (x3 - x2) >> 8; + blk[7] = (x7 - x1) >> 8; + } + + private void ColIDCT(int* blk, byte* outv, int stride) + { + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + if (((x1 = blk[8 * 4] << 8) + | (x2 = blk[8 * 6]) + | (x3 = blk[8 * 2]) + | (x4 = blk[8 * 1]) + | (x5 = blk[8 * 7]) + | (x6 = blk[8 * 5]) + | (x7 = blk[8 * 3])) == 0) + { + x1 = Clip(((blk[0] + 32) >> 6) + 128); + for (x0 = 8; x0 != 0; --x0) + { + *outv = (byte)x1; + outv += stride; + } + return; + } + x0 = (blk[0] << 8) + 8192; + x8 = W7 * (x4 + x5) + 4; + x4 = (x8 + (W1 - W7) * x4) >> 3; + x5 = (x8 - (W1 + W7) * x5) >> 3; + x8 = W3 * (x6 + x7) + 4; + x6 = (x8 - (W3 - W5) * x6) >> 3; + x7 = (x8 - (W3 + W5) * x7) >> 3; + x8 = x0 + x1; + x0 -= x1; + x1 = W6 * (x3 + x2) + 4; + x2 = (x1 - (W2 + W6) * x2) >> 3; + x3 = (x1 + (W2 - W6) * x3) >> 3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181 * (x4 + x5) + 128) >> 8; + x4 = (181 * (x4 - x5) + 128) >> 8; + *outv = Clip(((x7 + x1) >> 14) + 128); outv += stride; + *outv = Clip(((x3 + x2) >> 14) + 128); outv += stride; + *outv = Clip(((x0 + x4) >> 14) + 128); outv += stride; + *outv = Clip(((x8 + x6) >> 14) + 128); outv += stride; + *outv = Clip(((x8 - x6) >> 14) + 128); outv += stride; + *outv = Clip(((x0 - x4) >> 14) + 128); outv += stride; + *outv = Clip(((x3 - x2) >> 14) + 128); outv += stride; + *outv = Clip(((x7 - x1) >> 14) + 128); + } + + private int ShowBits(int bits) + { + byte newbyte; + if (bits == 0) return 0; + while (this.bufbits < bits) + { + if (this.size <= 0) + { + this.buf = (this.buf << 8) | 0xFF; + this.bufbits += 8; + continue; + } + newbyte = *this.pos++; + this.size--; + this.bufbits += 8; + this.buf = (this.buf << 8) | newbyte; + if (newbyte == 0xFF) + { + if (this.size != 0) + { + byte marker = *this.pos++; + this.size--; + switch (marker) + { + case 0x00: + case 0xFF: + break; + case 0xD9: this.size = 0; break; + default: + if ((marker & 0xF8) != 0xD0) throw new NJException(NJErrorCode.SyntaxError); + else + { + this.buf = (this.buf << 8) | marker; + this.bufbits += 8; + } + break; + } + } + else throw new NJException(NJErrorCode.SyntaxError); + } + } + return (this.buf >> (this.bufbits - bits)) & ((1 << bits) - 1); + } + + private void DecodeSOF() + { + int i, ssxmax = 0, ssymax = 0; + Component* c; + DecodeLength(); + if (this.length < 9) throw new NJException(NJErrorCode.SyntaxError); + if (this.pos[0] != 8) throw new NJException(NJErrorCode.Unsupported); + this.height = Decode16(this.pos + 1); + this.width = Decode16(this.pos + 3); + this.ncomp = this.pos[5]; + Skip(6); + switch (this.ncomp) + { + case 1: + case 3: + break; + default: + throw new NJException(NJErrorCode.Unsupported); + } + if (this.length < (this.ncomp * 3)) throw new NJException(NJErrorCode.SyntaxError); + for (i = 0, c = this.comp; i < this.ncomp; ++i, ++c) + { + c->cid = this.pos[0]; + if ((c->ssx = this.pos[1] >> 4) == 0) throw new NJException(NJErrorCode.SyntaxError); + if ((c->ssx & (c->ssx - 1)) != 0) throw new NJException(NJErrorCode.Unsupported); // non-power of two + if ((c->ssy = this.pos[1] & 15) == 0) throw new NJException(NJErrorCode.SyntaxError); + if ((c->ssy & (c->ssy - 1)) != 0) throw new NJException(NJErrorCode.Unsupported); // non-power of two + if (((c->qtsel = this.pos[2]) & 0xFC) != 0) throw new NJException(NJErrorCode.SyntaxError); + Skip(3); + this.qtused |= 1 << c->qtsel; + if (c->ssx > ssxmax) ssxmax = c->ssx; + if (c->ssy > ssymax) ssymax = c->ssy; + } + if (this.ncomp == 1) + { + c = this.comp; + c->ssx = c->ssy = ssxmax = ssymax = 1; + } + this.mbsizex = ssxmax << 3; + this.mbsizey = ssymax << 3; + this.mbwidth = (this.width + this.mbsizex - 1) / this.mbsizex; + this.mbheight = (this.height + this.mbsizey - 1) / this.mbsizey; + for (i = 0, c = this.comp; i < this.ncomp; ++i, ++c) + { + c->width = (this.width * c->ssx + ssxmax - 1) / ssxmax; + c->height = (this.height * c->ssy + ssymax - 1) / ssymax; + c->stride = this.mbwidth * c->ssx << 3; + if (((c->width < 3) && (c->ssx != ssxmax)) || ((c->height < 3) && (c->ssy != ssymax))) throw new NJException(NJErrorCode.Unsupported); + c->pixels = (byte*)Marshal.AllocHGlobal(c->stride * this.mbheight * c->ssy << 3); + } + if (this.ncomp == 3) this.rgb = (byte*)Marshal.AllocHGlobal(this.width * this.height * this.ncomp); + Skip(this.length); + } + + private void DecodeDHT() + { + int codelen, currcnt, remain, spread, i, j; + VLCCode* vlc; + byte* counts = stackalloc byte[16]; + DecodeLength(); + while (this.length >= 17) + { + i = this.pos[0]; + if ((i & 0xEC) != 0) throw new NJException(NJErrorCode.SyntaxError); + if ((i & 0x02) != 0) throw new NJException(NJErrorCode.Unsupported); + i = (i | (i >> 3)) & 3; // combined DC/AC + tableid value + for (codelen = 1; codelen <= 16; ++codelen) + counts[codelen - 1] = this.pos[codelen]; + Skip(17); + vlc = &this.vlctab[i][0]; + remain = spread = 65536; + for (codelen = 1; codelen <= 16; ++codelen) + { + spread >>= 1; + currcnt = counts[codelen - 1]; + if (currcnt == 0) continue; + if (this.length < currcnt) throw new NJException(NJErrorCode.SyntaxError); + remain -= currcnt << (16 - codelen); + if (remain < 0) throw new NJException(NJErrorCode.SyntaxError); + for (i = 0; i < currcnt; ++i) + { + byte code = this.pos[i]; + for (j = spread; j != 0; --j) + { + vlc->bits = (byte)codelen; + vlc->code = code; + ++vlc; + } + } + Skip(currcnt); + } + while (remain-- != 0) + { + vlc->bits = 0; + ++vlc; + } + } + if (this.length != 0) throw new NJException(NJErrorCode.SyntaxError); + } + + private void DecodeDQT() + { + int i; + byte* t; + DecodeLength(); + while (this.length >= 65) + { + i = this.pos[0]; + if ((i & 0xFC) != 0) throw new NJException(NJErrorCode.SyntaxError); + this.qtavail |= 1 << i; + t = &this.qtab[i][0]; + for (i = 0; i < 64; ++i) t[i] = this.pos[i + 1]; + Skip(65); + } + if (this.length != 0) throw new NJException(NJErrorCode.SyntaxError); + } + + private int GetVLC(VLCCode* vlc, byte* code) + { + int value = ShowBits(16); + int bits = vlc[value].bits; + if (bits == 0) throw new NJException(NJErrorCode.SyntaxError); + SkipBits(bits); + value = vlc[value].code; + if (code != null) *code = (byte)value; + bits = value & 15; + if (bits == 0) return 0; + value = GetBits(bits); + if (value < (1 << (bits - 1))) value += ((-1) << bits) + 1; + return value; + } + + private void DecodeBlock(Component* c, byte* outv) + { + byte code = 0; + int value, coef = 0; + FillMem((long*)block, 0, 64 / 2);//use long instead of int + c->dcpred += GetVLC(&this.vlctab[c->dctabsel][0], null); + this.block[0] = (c->dcpred) * this.qtab[c->qtsel][0]; + do + { + value = GetVLC(&this.vlctab[c->actabsel][0], &code); + if (code == 0) break; // EOB + if ((code & 0x0F) == 0 && code != 0xF0) throw new NJException(NJErrorCode.SyntaxError); + coef += (code >> 4) + 1; + if (coef > 63) throw new NJException(NJErrorCode.SyntaxError); + this.block[(int)njZZ[coef]] = value * this.qtab[c->qtsel][coef]; + } while (coef < 63); + for (coef = 0; coef < 64; coef += 8) { RowIDCT(&this.block[coef]); } + for (coef = 0; coef < 8; ++coef) { ColIDCT(&this.block[coef], &outv[coef], c->stride); } + } + + private void DecodeScan() + { + int i, mbx, mby, sbx, sby; + int rstcount = this.rstinterval, nextrst = 0; + Component* c; + DecodeLength(); + if (this.length < (4 + 2 * this.ncomp)) throw new NJException(NJErrorCode.SyntaxError); + if (this.pos[0] != this.ncomp) throw new NJException(NJErrorCode.Unsupported); + Skip(1); + for (i = 0, c = this.comp; i < this.ncomp; ++i, ++c) + { + if (this.pos[0] != c->cid) throw new NJException(NJErrorCode.SyntaxError); + if ((this.pos[1] & 0xEE) != 0) throw new NJException(NJErrorCode.SyntaxError); + c->dctabsel = this.pos[1] >> 4; + c->actabsel = (this.pos[1] & 1) | 2; + Skip(2); + } + if (this.pos[0] != 0 || this.pos[1] != 63 || this.pos[2] != 0) throw new NJException(NJErrorCode.Unsupported); + Skip(this.length); + mbx = mby = 0; + while(true) + { + for (i = 0, c = this.comp; i < this.ncomp; ++i, ++c) + { + for (sby = 0; sby < c->ssy; ++sby) + { + for (sbx = 0; sbx < c->ssx; ++sbx) + { + DecodeBlock(c, &c->pixels[((mby * c->ssy + sby) * c->stride + mbx * c->ssx + sbx) << 3]); + } + } + } + if (++mbx >= this.mbwidth) + { + mbx = 0; + if (++mby >= this.mbheight) break; + } + if (this.rstinterval != 0 && --rstcount == 0) + { + this.bufbits &= 0xF8; + i = GetBits(16); + if ((i & 0xFFF8) != 0xFFD0 || (i & 7) != nextrst) throw new NJException(NJErrorCode.SyntaxError); + nextrst = (nextrst + 1) & 7; + rstcount = this.rstinterval; + for (i = 0; i < 3; ++i) { this.comp[i].dcpred = 0; } + } + } + IsDone = true; + } + + private void UpsampleH(Component* c) + { + int xmax = c->width - 3; + byte* outv, lin, lout; + int x, y; + try + { + outv = (byte*)Marshal.AllocHGlobal((c->width * c->height) << 1); + lin = c->pixels; + lout = outv; + for (y = c->height; y != 0; --y) + { + lout[0] = CF(CF2A * lin[0] + CF2B * lin[1]); + lout[1] = CF(CF3X * lin[0] + CF3Y * lin[1] + CF3Z * lin[2]); + lout[2] = CF(CF3A * lin[0] + CF3B * lin[1] + CF3C * lin[2]); + + for (x = 0; x < xmax; ++x) + { + lout[(x << 1) + 3] = CF(CF4A * lin[x] + CF4B * lin[x + 1] + CF4C * lin[x + 2] + CF4D * lin[x + 3]); + lout[(x << 1) + 4] = CF(CF4D * lin[x] + CF4C * lin[x + 1] + CF4B * lin[x + 2] + CF4A * lin[x + 3]); + } + + lin += c->stride; + lout += c->width << 1; + + lout[-3] = CF(CF3A * lin[-1] + CF3B * lin[-2] + CF3C * lin[-3]); + lout[-2] = CF(CF3X * lin[-1] + CF3Y * lin[-2] + CF3Z * lin[-3]); + lout[-1] = CF(CF2A * lin[-1] + CF2B * lin[-2]); + } + c->width <<= 1; + c->stride = c->width; + } + finally { if (c->pixels != null) Marshal.FreeHGlobal((IntPtr)c->pixels); } + c->pixels = outv; + } + + private void UpsampleV(Component* c) + { + int w = c->width, s1 = c->stride, s2 = s1 + s1; + byte* outv, cin, cout; + int x, y; + try + { + outv = (byte*)Marshal.AllocHGlobal((c->width * c->height) << 1); + for (x = 0; x < w; ++x) + { + cin = &c->pixels[x]; + cout = &outv[x]; + *cout = CF(CF2A * cin[0] + CF2B * cin[s1]); cout += w; + *cout = CF(CF3X * cin[0] + CF3Y * cin[s1] + CF3Z * cin[s2]); cout += w; + *cout = CF(CF3A * cin[0] + CF3B * cin[s1] + CF3C * cin[s2]); cout += w; + cin += s1; + for (y = c->height - 3; y != 0; --y) + { + *cout = CF(CF4A * cin[-s1] + CF4B * cin[0] + CF4C * cin[s1] + CF4D * cin[s2]); cout += w; + *cout = CF(CF4D * cin[-s1] + CF4C * cin[0] + CF4B * cin[s1] + CF4A * cin[s2]); cout += w; + cin += s1; + } + cin += s1; + *cout = CF(CF3A * cin[0] + CF3B * cin[-s1] + CF3C * cin[-s2]); cout += w; + *cout = CF(CF3X * cin[0] + CF3Y * cin[-s1] + CF3Z * cin[-s2]); cout += w; + *cout = CF(CF2A * cin[0] + CF2B * cin[-s1]); + } + c->height <<= 1; + c->stride = c->width; + } + finally { if (c->pixels != null) Marshal.FreeHGlobal((IntPtr)c->pixels); } + c->pixels = outv; + } + + private void ConvertYCC(bool flip) + { + int i; + int w = this.width; + int h = this.height; + Component* c; + + for (i = 0, c = this.comp; i < this.ncomp; ++i, ++c) + { + while ((c->width < w) || (c->height < h)) + { + if (c->width < w) UpsampleH(c); + if (c->height < h) UpsampleV(c); + } + if ((c->width < w) || (c->height < h)) throw new NJException(NJErrorCode.InternalError); + } + + if (this.ncomp == 3) + { + // convert to RGB + int x, yy, y, cb, cr, r, g, b; + byte* prgb = this.rgb; + byte* py = this.comp[0].pixels; + byte* pcb = this.comp[1].pixels; + byte* pcr = this.comp[2].pixels; + int rs = this.comp[0].stride - w; + int gs = this.comp[1].stride - w; + int bs = this.comp[2].stride - w; + + for (yy = this.height; yy != 0; --yy) + { + for (x = 0; x < w; ++x) + { + y = *py++ << 8; + cb = *pcb++ - 128; + cr = *pcr++ - 128; + + g = (y - 88 * cb - 183 * cr + 128) >> 8; + + if (flip) + { + b = (y + 359 * cr + 128) >> 8; + r = (y + 454 * cb + 128) >> 8; + } + else + { + r = (y + 359 * cr + 128) >> 8; + b = (y + 454 * cb + 128) >> 8; + } + + if (r < 0) *prgb++ = 0; + else if (r > 0xFF) *prgb++ = 0xFF; + else *prgb++ = (byte)r; + + if (g < 0) *prgb++ = 0; + else if (g > 0xFF) *prgb++ = 0xFF; + else *prgb++ = (byte)g; + + if (b < 0) *prgb++ = 0; + else if (b > 0xFF) *prgb++ = 0xFF; + else *prgb++ = (byte)b; + } + py += rs; + pcb += gs; + pcr += bs; + } + + Marshal.FreeHGlobal((IntPtr)this.comp[0].pixels); + Marshal.FreeHGlobal((IntPtr)this.comp[1].pixels); + Marshal.FreeHGlobal((IntPtr)this.comp[2].pixels); + this.comp[0].pixels = this.comp[1].pixels = this.comp[2].pixels = null; + } + else if (this.comp[0].width != this.comp[0].stride) + { + // grayscale -> only remove stride + int y, x; + int cw = this.comp[0].width; + int cs = this.comp[0].stride; + int d = cs - cw; + byte* pin = &this.comp[0].pixels[cs]; + byte* pout = &this.comp[0].pixels[cw]; + + for (y = this.comp[0].height - 1; y != 0; --y) + { + for (x = 0; x < cw; x++) *pout++ = *pin++; + pin += d; + } + this.comp[0].stride = cw; + + Marshal.FreeHGlobal((IntPtr)this.comp[0].pixels); + this.comp[0].pixels = null; + } + } + + #endregion + + #region Helper Methods + + private static byte Clip(int x) + { + if (x < 0) return 0; + else if (x > 0xFF) return 0xFF; + else return (byte)x; + } + + private static byte CF(int x) + { + x = (x + 64) >> 7; + if (x < 0) return 0; + else if (x > 0xFF) return 0xFF; + else return (byte)x; + } + + private void SkipBits(int bits) + { + if (this.bufbits < bits) ShowBits(bits); + this.bufbits -= bits; + } + + private int GetBits(int bits) + { + int res = ShowBits(bits); + SkipBits(bits); + return res; + } + + private void Skip(int count) + { + this.pos += count; + this.size -= count; + this.length -= count; + if (this.size < 0) throw new NJException(NJErrorCode.SyntaxError); + } + + private void DecodeLength() + { + if (this.size < 2) throw new NJException(NJErrorCode.SyntaxError); + this.length = Decode16(this.pos); + if (this.length > this.size) throw new NJException(NJErrorCode.SyntaxError); + Skip(2); + } + + private void SkipMarker() + { + DecodeLength(); + Skip(this.length); + } + + private void DecodeDRI() + { + DecodeLength(); + if (this.length < 2) throw new NJException(NJErrorCode.SyntaxError); + this.rstinterval = Decode16(this.pos); + Skip(this.length); + } + + private static ushort Decode16(byte* pos) + { + return (ushort)((pos[0] << 8) | pos[1]); + } + + private static void FillMem(byte* block, byte value, int count) + { + for (int i = 0; i < count; i++) block[i] = value; + } + + private static void FillMem(int* block, int value, int count) + { + for (int i = 0; i < count; i++) block[i] = value; + } + + private static void FillMem(long* block, int value, int count) + { + for (int i = 0; i < count; i++) block[i] = value; + } + + private static void FillMem(Component* block, Component value, int count) + { + for (int i = 0; i < count; i++) block[i] = value; + } + + private static void FillMem(VLCCode* block, VLCCode value, int count) + { + for (int i = 0; i < count; i++) block[i] = value; + } + + #endregion + } +} \ No newline at end of file diff --git a/Ryujinx.ImGui/GUI/WindowHelper.cs b/Ryujinx.ImGui/GUI/WindowHelper.cs index b9e429e4f7..15d4d88321 100644 --- a/Ryujinx.ImGui/GUI/WindowHelper.cs +++ b/Ryujinx.ImGui/GUI/WindowHelper.cs @@ -172,7 +172,7 @@ namespace Ryujinx.UI GL.EnableClientState(ArrayCap.ColorArray); GL.Enable(EnableCap.Texture2D); - GL.UseProgram(1); + GL.UseProgram(0); // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) IO io = ImGui.GetIO(); @@ -194,13 +194,16 @@ namespace Ryujinx.UI GL.LoadIdentity(); // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) { NativeDrawList* cmd_list = draw_data->CmdLists[n]; byte* vtx_buffer = (byte*)cmd_list->VtxBuffer.Data; ushort* idx_buffer = (ushort*)cmd_list->IdxBuffer.Data; + DrawVert vert0 = *((DrawVert*)vtx_buffer); + DrawVert vert1 = *(((DrawVert*)vtx_buffer) + 1); + DrawVert vert2 = *(((DrawVert*)vtx_buffer) + 2); + GL.VertexPointer(2, VertexPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.PosOffset)); GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.UVOffset)); GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.ColOffset)); @@ -220,6 +223,8 @@ namespace Ryujinx.UI (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] = idx_buffer[i]; } GL.DrawElements(PrimitiveType.Triangles, (int)pcmd->ElemCount, DrawElementsType.UnsignedShort, new IntPtr(idx_buffer)); } idx_buffer += pcmd->ElemCount; diff --git a/Ryujinx.ImGui/Ryujinx.UI.csproj b/Ryujinx.ImGui/Ryujinx.UI.csproj index 0206435cb4..28669ca7b9 100644 --- a/Ryujinx.ImGui/Ryujinx.UI.csproj +++ b/Ryujinx.ImGui/Ryujinx.UI.csproj @@ -17,6 +17,7 @@ + diff --git a/Ryujinx/Properties/launchSettings.json b/Ryujinx/Properties/launchSettings.json new file mode 100644 index 0000000000..e59dd2a51e --- /dev/null +++ b/Ryujinx/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Ryujinx": { + "commandName": "Project", + "commandLineArgs": "\"C:\\Users\\Emmanuel Hansen\\AppData\\Roaming\\RyuFs\\sdmc\\switch\\fruity\\fruity.nro\"" + } + } +} \ No newline at end of file From b9d2039995f6f3a5ce5aa73ab032364b58e042b7 Mon Sep 17 00:00:00 2001 From: emmaus Date: Sat, 23 Jun 2018 10:15:29 +0000 Subject: [PATCH 03/11] cleanup, refactoring, style changes, fixes --- ChocolArm64/ATranslator.cs | 16 +- Ryujinx.HLE/OsHle/Horizon.cs | 17 +- Ryujinx.HLE/OsHle/Process.cs | 5 +- Ryujinx.HLE/Switch.cs | 3 +- Ryujinx.ImGui/Config.cs | 21 +- Ryujinx.ImGui/EmulationController.cs | 53 +++- Ryujinx.ImGui/Extensions/ControlArchive.cs | 1 + Ryujinx.ImGui/Extensions/DialogResult.cs | 12 + Ryujinx.ImGui/Extensions/Nro.cs | 25 +- Ryujinx.ImGui/GUI/EmulationWindow.cs | 164 +++++++------ .../GUI/Widgets/ConfigurationWidget.cs | 42 ++-- Ryujinx.ImGui/GUI/Widgets/FilePicker.cs | 113 +++++---- Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs | 123 ++++++---- Ryujinx.ImGui/GUI/Widgets/GameList.cs | 118 +++++---- Ryujinx.ImGui/GUI/Widgets/HomeUI.cs | 8 +- Ryujinx.ImGui/GUI/Widgets/InputPage.cs | 85 ++++++- Ryujinx.ImGui/GUI/Widgets/PauseUI.cs | 7 +- Ryujinx.ImGui/GUI/WindowHelper.cs | 227 +++++++++++------- Ryujinx.ImGui/Program.cs | 1 + Ryujinx.ImGui/Ryujinx.UI.csproj | 2 +- Ryujinx/Properties/launchSettings.json | 8 - 21 files changed, 634 insertions(+), 417 deletions(-) create mode 100644 Ryujinx.ImGui/Extensions/DialogResult.cs delete mode 100644 Ryujinx/Properties/launchSettings.json diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs index 7c2d9cd4f7..7937aaf7fd 100644 --- a/ChocolArm64/ATranslator.cs +++ b/ChocolArm64/ATranslator.cs @@ -22,11 +22,7 @@ namespace ChocolArm64 public bool EnableCpuTrace { get; set; } - public static long CyclesExecuted { get; set; } - - public static bool Pause { get; set; } = false; - - public static ManualResetEvent PauseResetEvent = new ManualResetEvent(false); + public static ManualResetEvent PauseResetEvent = new ManualResetEvent(true); public ATranslator(IReadOnlyDictionary SymbolTable = null) { @@ -68,10 +64,7 @@ namespace ChocolArm64 OpCode.Interpreter(State, Memory, OpCode); - CyclesExecuted++; - - while (Pause) - PauseResetEvent.WaitOne(1000); + PauseResetEvent.WaitOne(1000); } while (State.R15 != 0 && State.Running); } @@ -102,10 +95,7 @@ namespace ChocolArm64 Position = Sub.Execute(State, Memory); - CyclesExecuted++; - - while (Pause) - PauseResetEvent.WaitOne(1000); + PauseResetEvent.WaitOne(); } while (Position != 0 && State.Running); } diff --git a/Ryujinx.HLE/OsHle/Horizon.cs b/Ryujinx.HLE/OsHle/Horizon.cs index c2a84bbf3e..7b8b4b40c4 100644 --- a/Ryujinx.HLE/OsHle/Horizon.cs +++ b/Ryujinx.HLE/OsHle/Horizon.cs @@ -18,6 +18,8 @@ namespace Ryujinx.HLE.OsHle private ConcurrentDictionary Processes; + private bool IsDisposing; + public SystemStateMgr SystemState { get; private set; } internal MemoryAllocator Allocator { get; private set; } @@ -170,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); @@ -193,8 +195,15 @@ namespace Ryujinx.HLE.OsHle if (Processes.TryRemove(ProcessId, out Process)) { - Process.StopAllThreadsAsync(); - Process.Dispose(); + try + { + Process.StopAllThreadsAsync(); + Process.Dispose(); + } + catch (ObjectDisposedException Ex) + { + + } if (Processes.Count == 0) { @@ -215,6 +224,8 @@ namespace Ryujinx.HLE.OsHle protected virtual void Dispose(bool Disposing) { + IsDisposing = Disposing; + if (Disposing) { foreach (Process Process in Processes.Values) diff --git a/Ryujinx.HLE/OsHle/Process.cs b/Ryujinx.HLE/OsHle/Process.cs index 8551480ab9..f0619111ee 100644 --- a/Ryujinx.HLE/OsHle/Process.cs +++ b/Ryujinx.HLE/OsHle/Process.cs @@ -176,7 +176,7 @@ namespace Ryujinx.HLE.OsHle throw new ObjectDisposedException(nameof(Process)); } - ATranslator.Pause = true; + ATranslator.PauseResetEvent.Reset(); } public void Resume() @@ -186,7 +186,6 @@ namespace Ryujinx.HLE.OsHle throw new ObjectDisposedException(nameof(Process)); } - ATranslator.Pause = false; ATranslator.PauseResetEvent.Set(); } @@ -424,6 +423,8 @@ namespace Ryujinx.HLE.OsHle { if (Disposing && !Disposed) { + ATranslator.PauseResetEvent.Set(); + //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. diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index 2e17ca6c5d..53f425c3b9 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -98,7 +98,8 @@ namespace Ryujinx.HLE { Os.Dispose(); VFs.Dispose(); - Gpu.Dispose(); + Gpu.Dispose(); + AudioOut.Dispose(); } } } diff --git a/Ryujinx.ImGui/Config.cs b/Ryujinx.ImGui/Config.cs index 289da4731a..c2f3dadd13 100644 --- a/Ryujinx.ImGui/Config.cs +++ b/Ryujinx.ImGui/Config.cs @@ -98,11 +98,21 @@ namespace Ryujinx DefaultGameDirectory = Parser.GetValue("Default_Game_Directory"); + VirtualFileSystem FS = new HLE.VirtualFileSystem(); + if (string.IsNullOrWhiteSpace(DefaultGameDirectory)) - { - VirtualFileSystem FS = new HLE.VirtualFileSystem(); + { 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) @@ -165,7 +175,7 @@ namespace Ryujinx { private readonly Dictionary Values; private readonly Dictionary Comments; - private string Path; + private readonly string Path; public IniParser(string Path) { @@ -214,20 +224,25 @@ namespace Ryujinx { bool result = false; List Records = new List(); + 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; } } diff --git a/Ryujinx.ImGui/EmulationController.cs b/Ryujinx.ImGui/EmulationController.cs index 3e205f070c..b965d27652 100644 --- a/Ryujinx.ImGui/EmulationController.cs +++ b/Ryujinx.ImGui/EmulationController.cs @@ -1,15 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Ryujinx.HLE; +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; @@ -17,21 +19,56 @@ namespace Ryujinx.UI public void Resume() { - lock(Ns) - Ns.Os.ResumeAllProcesses(); + lock (Ns) + Ns.Os.ResumeAllProcesses(); } public void Pause() { - lock(Ns) - Ns.Os.PauseAllProcesses(); + lock (Ns) + Ns.Os.PauseAllProcesses(); } public void ShutDown() { lock (Ns) 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; } } } diff --git a/Ryujinx.ImGui/Extensions/ControlArchive.cs b/Ryujinx.ImGui/Extensions/ControlArchive.cs index b598e527a7..c85ef04302 100644 --- a/Ryujinx.ImGui/Extensions/ControlArchive.cs +++ b/Ryujinx.ImGui/Extensions/ControlArchive.cs @@ -20,6 +20,7 @@ namespace Ryujinx.UI byte[] LanguageEntryData = Reader.ReadBytes(0x3000); Input.Seek(0x3060, SeekOrigin.Begin); + ApplicationVersion = Encoding.ASCII.GetString(Reader.ReadBytes(0x10)); BaseTitleID = Reader.ReadInt64(); ApplicationTitleID = Reader.ReadInt64(); diff --git a/Ryujinx.ImGui/Extensions/DialogResult.cs b/Ryujinx.ImGui/Extensions/DialogResult.cs new file mode 100644 index 0000000000..515cbb1a5a --- /dev/null +++ b/Ryujinx.ImGui/Extensions/DialogResult.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +public enum DialogResult +{ + OK, + Cancel, + Yes, + No, + None +} \ No newline at end of file diff --git a/Ryujinx.ImGui/Extensions/Nro.cs b/Ryujinx.ImGui/Extensions/Nro.cs index 35f32fa390..c94d6b6c17 100644 --- a/Ryujinx.ImGui/Extensions/Nro.cs +++ b/Ryujinx.ImGui/Extensions/Nro.cs @@ -8,12 +8,10 @@ namespace Ryujinx.UI { class Nro : HLE.Loaders.Executables.Nro { - public byte[] AssetRomfData { get; set; } - public byte[] IconData { get; set; } - - private byte[] NACPData { get; set; } - - public int AssetOffset { get; set; } + public byte[] AssetRomfData { get; set; } + public byte[] IconData { get; set; } + private byte[] NACPData { get; set; } + public int AssetOffset { get; set; } public ControlArchive ControlArchive { get; set; } @@ -38,18 +36,19 @@ namespace Ryujinx.UI 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); + + 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 IconSize = BitConverter.ToInt64(IconSectionInfo, 8); long NACPOffset = BitConverter.ToInt64(NACPSectionInfo, 0); - long NACPSize = BitConverter.ToInt64(NACPSectionInfo, 8); + long NACPSize = BitConverter.ToInt64(NACPSectionInfo, 8); long RomfOffset = BitConverter.ToInt64(AssetRomfSectionInfo, 0); - long RomfSize = BitConverter.ToInt64(AssetRomfSectionInfo, 8); + long RomfSize = BitConverter.ToInt64(AssetRomfSectionInfo, 8); Input.Seek(AssetOffset + IconOffset, SeekOrigin.Begin); IconData = Reader.ReadBytes((int)IconSize); diff --git a/Ryujinx.ImGui/GUI/EmulationWindow.cs b/Ryujinx.ImGui/GUI/EmulationWindow.cs index 9e1f685ece..89bc47dcc0 100644 --- a/Ryujinx.ImGui/GUI/EmulationWindow.cs +++ b/Ryujinx.ImGui/GUI/EmulationWindow.cs @@ -1,20 +1,20 @@ 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 OpenTK.Graphics; -using OpenTK.Input; using System; -using System.IO; namespace Ryujinx.UI { partial class EmulationWindow : WindowHelper { + public static EmulationController EmulationController; //toggles private bool showMainUI = true; private bool showPauseUI; @@ -26,10 +26,6 @@ namespace Ryujinx.UI { isRunning = value; UIActive = !value; - if (!value) - { - //ShowMainUI = true; - } } } @@ -39,8 +35,13 @@ namespace Ryujinx.UI set { showMainUI = value; - showPauseUI = !value && !isRunning; - UIActive = value; + if (value) + { + CurrentPage = Page.GameList; + UIActive = value; + } + else if (!ShowPauseUI) + UIActive = false; } } @@ -50,12 +51,15 @@ namespace Ryujinx.UI set { showPauseUI = value; - UIActive = value; - showMainUI = !value; + if (value) + { + CurrentPage = Page.Emulation; + UIActive = value; + } + else if (!ShowMainUI) + UIActive = false; } - } - - private EmulationController EmulationController; + } private Page CurrentPage = Page.GameList; @@ -73,42 +77,33 @@ namespace Ryujinx.UI FilePicker FileDialog; IGalRenderer Renderer; - IAalOutput AudioOut; + public static Switch Ns; - public EmulationWindow() : base("Test") + public EmulationWindow() : base("Ryujinx") { FileDialog = FilePicker.GetFilePicker("rom",null); - Renderer = new OGLRenderer(); - - AudioOut = new OpenALAudioOut(); - - Ns = new Switch(Renderer, AudioOut); - - Config.Read(Ns.Log); - - EmulationController = new EmulationController(Ns); - - Ns.Log.Updated += ConsoleLog.PrintLog; + InitializeSwitch(); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); - VSync = VSyncMode.On; - - Renderer.FrameBuffer.SetWindowSize(Width, Height); + VSync = VSyncMode.On; } protected override void OnRenderFrame(FrameEventArgs e) { - _deltaTime = (float)e.Time; + DeltaTime = (float)e.Time; + if (UIActive) { - StartFrame(); + StartFrame(); + isRunning = false; + if (ShowMainUI) { showPauseUI = false; @@ -119,7 +114,7 @@ namespace Ryujinx.UI showMainUI = false; RenderPauseUI(); } - ImGuiNative.igShowMetricsWindow(ref UIActive); + EndFrame(); } else @@ -139,9 +134,28 @@ namespace Ryujinx.UI } } + 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; + } + protected override void OnUpdateFrame(FrameEventArgs e) { - if(!UIActive) + KeyboardState Keyboard = this.Keyboard.HasValue ? this.Keyboard.Value : new KeyboardState(); + + if (!UIActive) { if (Keyboard[Key.Escape] && !EscapePressed) { @@ -153,7 +167,9 @@ namespace Ryujinx.UI if (EmulationController.IsLoaded) ShowPauseUI = true; + UIActive = true; + return; } else if (Keyboard[Key.Escape]) @@ -218,8 +234,10 @@ namespace Ryujinx.UI //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?.GetState().LeftButton == ButtonState.Pressed) + if (Focused && Mouse?.LeftButton == ButtonState.Pressed) { + MouseState Mouse = this.Mouse.Value; + int ScrnWidth = Width; int ScrnHeight = Height; @@ -289,59 +307,53 @@ namespace Ryujinx.UI Renderer.RunActions(); } - else if(EmulationController.IsLoaded) - { - if (Keyboard[Key.Escape] && !EscapePressed) + else if (EmulationController != null) + if (EmulationController.IsLoaded) { - EscapePressed = true; - EmulationController.Resume(); + if (Keyboard[Key.Escape] && !EscapePressed) + { + EscapePressed = true; - if (ShowPauseUI & EmulationController.IsLoaded) - showPauseUI = false; - UIActive = false; - IsRunning = true; + EmulationController.Resume(); + + if (ShowPauseUI & EmulationController.IsLoaded) + showPauseUI = false; + + UIActive = false; + IsRunning = true; + } + else if (Keyboard[Key.Escape]) + EscapePressed = true; + else + EscapePressed = false; } - else if (Keyboard[Key.Escape]) - EscapePressed = true; - else - EscapePressed = false; - } - } + } public void LoadPackage(string path) - { - ShowMainUI = false; + { + MainContext.MakeCurrent(WindowInfo); - if (Directory.Exists(path)) - { - string[] RomFsFiles = Directory.GetFiles(path, "*.istorage"); - if (RomFsFiles.Length == 0) - { - RomFsFiles = Directory.GetFiles(path, "*.romfs"); - } + if(Ns == null) + InitializeSwitch(); - if (RomFsFiles.Length > 0) - { - Console.WriteLine("Loading as cart with RomFS."); + if (EmulationController == null) + EmulationController = new EmulationController(Ns); - Ns.LoadCart(path, RomFsFiles[0]); - } - else - { - Console.WriteLine("Loading as cart WITHOUT RomFS."); + EmulationController.IsShutDown += EmulationController_IsShutDown; - Ns.LoadCart(path); - } - } - else if (File.Exists(path)) - { - Console.WriteLine("Loading as homebrew."); + EmulationController.Load(path); - Ns.LoadProgram(path); - } IsRunning = true; - EmulationController.IsLoaded = true; + + ShowMainUI = false; + } + + private void EmulationController_IsShutDown(object sender, EventArgs e) + { + EmulationController = null; + + Ns = null; } enum Page diff --git a/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs b/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs index f1251c7b00..b2c758c1e3 100644 --- a/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs +++ b/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs @@ -1,28 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Text; -using ImGuiNET; -using System.Numerics; +using ImGuiNET; using Ryujinx.HLE.Input; -using OpenTK.Input; +using System.Numerics; namespace Ryujinx.UI.Widgets { public partial class ConfigurationWidget - { - public static JoyCon CurrentJoyConLayout; - static Page CurrentPage = Page.General; + { static bool ConfigIntialized = false; static bool OpenFolderPicker; static string CurrentPath; + static IniParser IniParser; static FolderPicker FolderPicker; + static JoyCon CurrentJoyConLayout; + static Page CurrentPage = Page.General; static ConfigurationWidget() { - IniParser = new IniParser(Config.IniPath); + IniParser = new IniParser(Config.IniPath); FolderPicker = FolderPicker.GetFolderPicker("FolderDialog",Config.DefaultGameDirectory); - CurrentPath = Config.DefaultGameDirectory.ToString(); + CurrentPath = Config.DefaultGameDirectory.ToString(); } public static void Draw() @@ -60,30 +57,27 @@ namespace Ryujinx.UI.Widgets { ImGui.Text("General Emulation Settings"); ImGui.Spacing(); - ImGui.LabelText("","Default Game Directory"); + ImGui.LabelText("", "Default Game Directory"); ImGui.SameLine(); - if( ImGui.Selectable(Config.DefaultGameDirectory)) + if (ImGui.Selectable(Config.DefaultGameDirectory)) { OpenFolderPicker = true; } if (OpenFolderPicker) ImGui.OpenPopup("OpenFolder"); - ImGui.SetNextWindowSize(new Vector2(500, 500), Condition.FirstUseEver); - if(ImGui.BeginPopupModal("OpenFolder",WindowFlags.NoResize)) + DialogResult DialogResult = FolderPicker.GetFolder(ref CurrentPath); + if (DialogResult == DialogResult.OK) { - string output = CurrentPath; - if (FolderPicker.Draw(ref output, false)) + if (!string.IsNullOrWhiteSpace(CurrentPath)) { - if (!string.IsNullOrWhiteSpace(output)) - { - Config.DefaultGameDirectory = output; - } - ImGui.CloseCurrentPopup(); - OpenFolderPicker = false; + Config.DefaultGameDirectory = CurrentPath; } - ImGui.EndPopup(); + } + if (DialogResult != DialogResult.None) + { + OpenFolderPicker = false; } ImGui.Spacing(); diff --git a/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs b/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs index d616b8822b..9653b02e0a 100644 --- a/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs +++ b/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs @@ -11,115 +11,115 @@ namespace ImGuiNET /// public class FilePicker { - private const string FilePickerID = "###FilePicker"; - private static readonly Dictionary s_filePickers = new Dictionary(); + private const string FilePickerID = "###FilePicker"; + private static readonly Dictionary FilePickers = new Dictionary(); private static readonly Vector2 DefaultFilePickerSize = new Vector2(600, 400); public string CurrentFolder { get; set; } - public string SelectedFile { get; set; } + public string SelectedEntry { get; set; } - public static FilePicker GetFilePicker(object o, string startingPath) + public static FilePicker GetFilePicker(object Id, string StartingPath) { - if (File.Exists(startingPath)) + if (File.Exists(StartingPath)) { - startingPath = new FileInfo(startingPath).DirectoryName; + StartingPath = new FileInfo(StartingPath).DirectoryName; } - else if (string.IsNullOrEmpty(startingPath) || !Directory.Exists(startingPath)) + else if (string.IsNullOrEmpty(StartingPath) || !Directory.Exists(StartingPath)) { - startingPath = Environment.CurrentDirectory; - if (string.IsNullOrEmpty(startingPath)) + StartingPath = Environment.CurrentDirectory; + if (string.IsNullOrEmpty(StartingPath)) { - startingPath = AppContext.BaseDirectory; + StartingPath = AppContext.BaseDirectory; } } - if (!s_filePickers.TryGetValue(o, out FilePicker fp)) + if (!FilePickers.TryGetValue(Id, out FilePicker FilePicker)) { - fp = new FilePicker(); - fp.CurrentFolder = startingPath; - s_filePickers.Add(o, fp); + FilePicker = new FilePicker + { + CurrentFolder = StartingPath + }; + + FilePickers.Add(Id, FilePicker); } - return fp; + return FilePicker; } - public bool Draw(ref string selected, bool returnOnSelection) + public DialogResult Draw(ref string SelectedPath, bool ReturnOnSelection) { - bool result = false; - result = DrawFolder(ref selected, returnOnSelection); - return result; + return DrawFolder(ref SelectedPath, ReturnOnSelection); } - private bool DrawFolder(ref string selected, bool returnOnSelection = false) + private DialogResult DrawFolder(ref string SelectedPath, bool ReturnOnSelection = false) { ImGui.Text("Current Folder: " + CurrentFolder); - bool result = false; if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable() - new Vector2(20, Values.ButtonHeight), WindowFlags.Default)) { - DirectoryInfo di = new DirectoryInfo(CurrentFolder); - if (di.Exists) + DirectoryInfo CurrentDirectory = new DirectoryInfo(CurrentFolder); + if (CurrentDirectory.Exists) { - if (di.Parent != null) + if (CurrentDirectory.Parent != null) { ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow); if (ImGui.Selectable("../", false, SelectableFlags.DontClosePopups , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) { - CurrentFolder = di.Parent.FullName; + CurrentFolder = CurrentDirectory.Parent.FullName; } ImGui.PopStyleColor(); } - foreach (var dir in Directory.EnumerateFileSystemEntries(di.FullName)) + + foreach (string Dir in Directory.EnumerateFileSystemEntries(CurrentDirectory.FullName)) { - if (Directory.Exists(dir)) + if (Directory.Exists(Dir)) { - string name = Path.GetFileName(dir); - bool isSelected = SelectedFile == dir; + string Name = Path.GetFileName(Dir); + bool IsSelected = SelectedEntry == Dir; ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow); - if (ImGui.Selectable(name + "/", isSelected, SelectableFlags.DontClosePopups + if (ImGui.Selectable(Name + "/", IsSelected, SelectableFlags.DontClosePopups , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) { - SelectedFile = dir; - selected = SelectedFile; + SelectedEntry = Dir; + SelectedPath = SelectedEntry; } - if (SelectedFile != null) - if (ImGui.IsMouseDoubleClicked(0) && SelectedFile.Equals(dir)) + if (SelectedEntry != null) + if (ImGui.IsMouseDoubleClicked(0) && SelectedEntry.Equals(Dir)) { - SelectedFile = null; - selected = null; - CurrentFolder = dir; + SelectedEntry = null; + SelectedPath = null; + CurrentFolder = Dir; } ImGui.PopStyleColor(); } } - foreach (var file in Directory.EnumerateFiles(di.FullName)) + foreach (string File in Directory.EnumerateFiles(CurrentDirectory.FullName)) { - string name = Path.GetFileName(file); - bool isSelected = SelectedFile == file; + string Name = Path.GetFileName(File); + bool IsSelected = SelectedEntry == File; - if (ImGui.Selectable(name, isSelected, SelectableFlags.DontClosePopups + if (ImGui.Selectable(Name, IsSelected, SelectableFlags.DontClosePopups , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) { - SelectedFile = file; - if (returnOnSelection) + SelectedEntry = File; + if (ReturnOnSelection) { - selected = SelectedFile; + SelectedPath = SelectedEntry; } } - if (SelectedFile != null) - if (ImGui.IsMouseDoubleClicked(0) && SelectedFile.Equals(file)) + if (SelectedEntry != null) + if (ImGui.IsMouseDoubleClicked(0) && SelectedEntry.Equals(File)) { - selected = file; - result = true; + SelectedPath = File; } } } @@ -129,20 +129,27 @@ namespace ImGuiNET if (ImGui.Button("Cancel", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { - result = false; + return DialogResult.Cancel; } - if (SelectedFile != null) + if (SelectedEntry != null) { ImGui.SameLine(); if (ImGui.Button("Load", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { - result = true; - selected = SelectedFile; + SelectedPath = SelectedEntry; + + return DialogResult.OK; + } + else if (ReturnOnSelection) + { + SelectedPath = SelectedEntry; + + return DialogResult.OK; } } - return result; + return DialogResult.None; } } } diff --git a/Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs b/Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs index 9d9039715a..eaf8d2690f 100644 --- a/Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs +++ b/Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs @@ -11,91 +11,91 @@ namespace ImGuiNET /// public class FolderPicker { - private const string FilePickerID = "###FilePicker"; - private static readonly Dictionary s_folderPickers + private const string FolderPickerID = "###FolderPicker"; + private static readonly Dictionary FolderPickers = new Dictionary(); private static readonly Vector2 DefaultFilePickerSize = new Vector2(600, 400); public string CurrentFolder { get; set; } - public string SelectedFile { get; set; } + public string SelectedDirectory { get; set; } - public static FolderPicker GetFolderPicker(object o, string startingPath) + public static FolderPicker GetFolderPicker(object Id, string StartingPath) { - if (File.Exists(startingPath)) + if (File.Exists(StartingPath)) { - startingPath = new FileInfo(startingPath).DirectoryName; + StartingPath = new FileInfo(StartingPath).DirectoryName; } - else if (string.IsNullOrEmpty(startingPath) || !Directory.Exists(startingPath)) + else if (string.IsNullOrEmpty(StartingPath) || !Directory.Exists(StartingPath)) { - startingPath = Environment.CurrentDirectory; - if (string.IsNullOrEmpty(startingPath)) + StartingPath = Environment.CurrentDirectory; + if (string.IsNullOrEmpty(StartingPath)) { - startingPath = AppContext.BaseDirectory; + StartingPath = AppContext.BaseDirectory; } } - if (!s_folderPickers.TryGetValue(o, out FolderPicker fp)) + if (!FolderPickers.TryGetValue(Id, out FolderPicker FolderPicker)) { - fp = new FolderPicker(); - fp.CurrentFolder = startingPath; - s_folderPickers.Add(o, fp); + FolderPicker = new FolderPicker + { + CurrentFolder = StartingPath + }; + + FolderPickers.Add(Id, FolderPicker); } - return fp; + return FolderPicker; } - public bool Draw(ref string selected, bool returnOnSelection) + public DialogResult Draw(ref string Selected, bool ReturnOnSelection) { - bool result = false; - result = DrawFolder(ref selected, returnOnSelection); - return result; + return DrawFolder(ref Selected, ReturnOnSelection); } - private bool DrawFolder(ref string selected, bool returnOnSelection = false) + private DialogResult DrawFolder(ref string Selected, bool ReturnOnSelection = false) { ImGui.Text("Current Folder: " + CurrentFolder); - bool result = false; if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable() - new Vector2(20, Values.ButtonHeight), WindowFlags.Default)) { - DirectoryInfo di = new DirectoryInfo(CurrentFolder); - if (di.Exists) + DirectoryInfo CurrentDirectory = new DirectoryInfo(CurrentFolder); + if (CurrentDirectory.Exists) { - if (di.Parent != null) + if (CurrentDirectory.Parent != null) { ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow); if (ImGui.Selectable("../", false, SelectableFlags.DontClosePopups , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) { - CurrentFolder = di.Parent.FullName; + CurrentFolder = CurrentDirectory.Parent.FullName; } ImGui.PopStyleColor(); } - foreach (var dir in Directory.EnumerateFileSystemEntries(di.FullName)) + foreach (var Dir in Directory.EnumerateFileSystemEntries(CurrentDirectory.FullName)) { - if (Directory.Exists(dir)) + if (Directory.Exists(Dir)) { - string name = Path.GetFileName(dir); - bool isSelected = SelectedFile == dir; + string Name = Path.GetFileName(Dir); + bool IsSelected = SelectedDirectory == Dir; ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow); - if (ImGui.Selectable(name + "/", isSelected, SelectableFlags.DontClosePopups + if (ImGui.Selectable(Name + "/", IsSelected, SelectableFlags.DontClosePopups , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) { - SelectedFile = dir; - selected = SelectedFile; + SelectedDirectory = Dir; + Selected = SelectedDirectory; } - if (SelectedFile != null) - if (ImGui.IsMouseDoubleClicked(0) && SelectedFile.Equals(dir)) + if (SelectedDirectory != null) + if (ImGui.IsMouseDoubleClicked(0) && SelectedDirectory.Equals(Dir)) { - SelectedFile = null; - selected = null; - CurrentFolder = dir; + SelectedDirectory = null; + Selected = null; + CurrentFolder = Dir; } ImGui.PopStyleColor(); @@ -108,20 +108,59 @@ namespace ImGuiNET if (ImGui.Button("Cancel", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { - result = false; + return DialogResult.Cancel; } - if (SelectedFile != null) + if (SelectedDirectory != null) { ImGui.SameLine(); if (ImGui.Button("Open", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { - result = true; - selected = SelectedFile; + Selected = SelectedDirectory; + + return DialogResult.OK; + } + else if(ReturnOnSelection) + { + Selected = SelectedDirectory; + + return DialogResult.OK; } } - return result; + return DialogResult.None; + } + + public DialogResult GetFolder(ref string CurrentPath) + { + ImGui.SetNextWindowSize(new Vector2(500, 500), Condition.FirstUseEver); + if (ImGui.BeginPopupModal("OpenFolder", WindowFlags.NoResize)) + { + try + { + string Output = CurrentPath; + DialogResult DialogResult = Draw(ref Output, false); + + 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; } } } diff --git a/Ryujinx.ImGui/GUI/Widgets/GameList.cs b/Ryujinx.ImGui/GUI/Widgets/GameList.cs index d4a3ce4530..51ebf895d0 100644 --- a/Ryujinx.ImGui/GUI/Widgets/GameList.cs +++ b/Ryujinx.ImGui/GUI/Widgets/GameList.cs @@ -1,102 +1,101 @@ -using System; -using System.IO; -using System.Drawing; -using System.Drawing.Imaging; -using System.Collections.Generic; -using System.Text; -using ImGuiNET; -using System.Numerics; +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 List GameItems = new List(); - static GameItem SelectedGame; - static bool OpenFolderPicker; - static FolderPicker FolderPicker; - static string CurrentPath; + static bool OpenFolderPicker; + static string GameDirectory; + static List GameItems; + static GameItem SelectedGame; + static FolderPicker FolderPicker; static GameList() { - Refresh(Config.DefaultGameDirectory); - FolderPicker = FolderPicker.GetFolderPicker("FolderDialog", Config.DefaultGameDirectory); + GameDirectory = Config.DefaultGameDirectory; + FolderPicker = FolderPicker.GetFolderPicker("FolderDialog", Config.DefaultGameDirectory); + + Refresh(GameDirectory); } public unsafe static void Refresh(string Path) { GameItems = new List(); + 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); + NanoJpeg.NJImage image = new NJImage(); image.Decode(GameItem.GetIconData()); - GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, image.Width, image.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgb, + 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); } } - else if (Directory.Exists(Path)) - { - - } - } } - public unsafe static void DrawList() + public unsafe static Tuple 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("OpenFolder"); - ImGui.SetNextWindowSize(new Vector2(500, 500), Condition.FirstUseEver); - if (ImGui.BeginPopupModal("OpenFolder", WindowFlags.NoResize)) + DialogResult DialogResult = FolderPicker.GetFolder(ref GameDirectory); + if (DialogResult == DialogResult.OK) { - string output = CurrentPath; - if (FolderPicker.Draw(ref output, false)) - { - if (!string.IsNullOrWhiteSpace(output)) - { - Config.DefaultGameDirectory = output; - Refresh(output); - } - ImGui.CloseCurrentPopup(); - OpenFolderPicker = false; - } - ImGui.EndPopup(); + 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)) { @@ -113,45 +112,52 @@ namespace Ryujinx.UI.Widgets ImGui.Text(Path.GetFileName(GameItem.Path)); } + ImGui.SameLine(); ImGuiNative.igBeginGroup(); - if (GameItem.IsNro) + if (GameItem.IsNro) + { + if (GameItem.Nro.ControlArchive != null) { - if (GameItem.Nro.ControlArchive != null) - { - ImGui.Text(GameItem.Nro.ControlArchive.LanguageEntries[0].AplicationName); - ImGui.Text(GameItem.Nro.ControlArchive.LanguageEntries[0].DeveloperName); - } - + 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 new Tuple(true, GameItem.Path); } else if (ImGui.IsMouseClicked(0) && ImGui.IsItemHovered(HoveredFlags.AllowWhenOverlapped | HoveredFlags.RootAndChildWindows)) { SelectedGame = GameItem; - } + } + ImGui.EndChildFrame(); } } ImGui.EndChildFrame(); } + + return new Tuple(false,string.Empty); } } class GameItem { - public AppletType AppletType; - public string Path; - public Nro Nro; - public bool IsNro; + 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 int TextureID; public GameItem(string Path) { @@ -163,22 +169,12 @@ namespace Ryujinx.UI.Widgets FileInfo Package = new FileInfo(Path); if (Package.Extension.ToLower() == ".nro") { - IsNro = true; Nro = new Nro(File.Open(Path, FileMode.Open), new FileInfo(Path).Name); } } else AppletType = AppletType.Cartridge; - } - - public Bitmap GetBitmap() - { - if (IsNro) - { - return new Bitmap(new Bitmap(new MemoryStream(Nro.IconData)),new Size(50,50)); - } - else return null; - } + } public byte[] GetIconData() { diff --git a/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs b/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs index c53dfb2732..819f3e2372 100644 --- a/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs +++ b/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs @@ -48,7 +48,7 @@ namespace Ryujinx.UI { case Page.PackageLoader: string output = CurrentPath; - if (FileDialog.Draw(ref output, false)) + if (FileDialog.Draw(ref output, false) == DialogResult.OK) { if (!string.IsNullOrWhiteSpace(output)) { @@ -61,7 +61,11 @@ namespace Ryujinx.UI Widgets.ConfigurationWidget.Draw(); break; case Page.GameList: - Widgets.GameList.DrawList(); + var SelectedPath = Widgets.GameList.DrawList(); + if (SelectedPath.Item1) + { + LoadPackage(SelectedPath.Item2); + } break; } ImGui.EndChildFrame(); diff --git a/Ryujinx.ImGui/GUI/Widgets/InputPage.cs b/Ryujinx.ImGui/GUI/Widgets/InputPage.cs index 8aabcb348b..d8218f11ae 100644 --- a/Ryujinx.ImGui/GUI/Widgets/InputPage.cs +++ b/Ryujinx.ImGui/GUI/Widgets/InputPage.cs @@ -1,43 +1,49 @@ -using System; -using ImGuiNET; -using System.Numerics; -using Ryujinx.HLE.Input; +using ImGuiNET; using OpenTK.Input; +using System; using System.Linq; +using System.Numerics; namespace Ryujinx.UI.Widgets { public partial class ConfigurationWidget { - static bool[] Toggles = new bool[50]; - static float ContentWidth; + static bool[] Toggles = new bool[50]; + + static float ContentWidth; static Vector2 GroupSize; - static Key pressedKey; - static bool RequestPopup = false; + static Key pressedKey; + static bool RequestPopup; public static void DrawInputPage() { Vector2 AvailableSpace = ImGui.GetContentRegionAvailable(); + GroupSize = new Vector2(AvailableSpace.X / 2, AvailableSpace.Y / 3); if (ImGui.BeginChildFrame(11, GroupSize, WindowFlags.AlwaysAutoResize)) { ContentWidth = (ImGui.GetContentRegionAvailableWidth() - 10) / 2; - GroupSize = ImGui.GetContentRegionMax(); + GroupSize = ImGui.GetContentRegionMax(); + DrawLeftAnalog(); + ImGui.EndChildFrame(); } + ImGui.SameLine(); if (ImGui.BeginChildFrame(12, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawRightAnalog(); + ImGui.EndChildFrame(); } if (ImGui.BeginChildFrame(13, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawDpad(); + ImGui.EndChildFrame(); } @@ -45,12 +51,14 @@ namespace Ryujinx.UI.Widgets if (ImGui.BeginChildFrame(14, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawActionKeys(); + ImGui.EndChildFrame(); } if (ImGui.BeginChildFrame(15, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawTriggers(); + ImGui.EndChildFrame(); } @@ -58,6 +66,7 @@ namespace Ryujinx.UI.Widgets if (ImGui.BeginChildFrame(16, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawExtras(); + ImGui.EndChildFrame(); } @@ -73,8 +82,10 @@ namespace Ryujinx.UI.Widgets | WindowFlags.NoResize)) { ImGui.Text("Please enter a key"); + if (!RequestPopup) ImGui.CloseCurrentPopup(); + ImGui.EndPopup(); } } @@ -87,11 +98,13 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGuiNative.igBeginGroup(); ImGui.Text("Up"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickUp).ToString(), new Vector2(ContentWidth, 50))) { Toggles[0] = true; } + if (Toggles[0]) { if (GetKey(ref pressedKey)) @@ -100,16 +113,19 @@ namespace Ryujinx.UI.Widgets Toggles[0] = false; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); ImGuiNative.igBeginGroup(); ImGui.Text("Down"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickDown).ToString(), new Vector2(ContentWidth, 50))) { Toggles[1] = true; } + if (Toggles[1]) { if (GetKey(ref pressedKey)) @@ -118,15 +134,18 @@ namespace Ryujinx.UI.Widgets Toggles[1] = false; } } + ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); ImGui.Text("Left"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickLeft).ToString(), new Vector2(ContentWidth, 50))) { Toggles[2] = true; } + if (Toggles[2]) { if (GetKey(ref pressedKey)) @@ -140,11 +159,13 @@ namespace Ryujinx.UI.Widgets ImGui.SameLine(); ImGuiNative.igBeginGroup(); ImGui.Text("Right"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickRight).ToString(), new Vector2(ContentWidth, 50))) { Toggles[3] = true; } + if (Toggles[3]) { if (GetKey(ref pressedKey)) @@ -167,16 +188,19 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Up"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickUp).ToString(), new Vector2(ContentWidth, 50))) { Toggles[4] = true; } + if (Toggles[4]) { if (GetKey(ref pressedKey)) { CurrentJoyConLayout.Right.StickUp = (int)pressedKey; + Toggles[4] = false; } } @@ -185,11 +209,13 @@ namespace Ryujinx.UI.Widgets ImGui.SameLine(); ImGuiNative.igBeginGroup(); ImGui.Text("Down"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickDown).ToString(), new Vector2(ContentWidth, 50))) { Toggles[5] = true; } + if (Toggles[5]) { if (GetKey(ref pressedKey)) @@ -202,11 +228,13 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Left"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickLeft).ToString(), new Vector2(ContentWidth, 50))) { Toggles[6] = true; } + if (Toggles[6]) { if (GetKey(ref pressedKey)) @@ -220,11 +248,13 @@ namespace Ryujinx.UI.Widgets ImGui.SameLine(); ImGuiNative.igBeginGroup(); ImGui.Text("Right"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickRight).ToString(), new Vector2(ContentWidth, 50))) { Toggles[7] = true; } + if (Toggles[7]) { if (GetKey(ref pressedKey)) @@ -246,11 +276,13 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Up"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadUp).ToString(), new Vector2(ContentWidth, 50))) { Toggles[8] = true; } + if (Toggles[8]) { if (GetKey(ref pressedKey)) @@ -264,11 +296,13 @@ namespace Ryujinx.UI.Widgets ImGui.SameLine(); ImGuiNative.igBeginGroup(); ImGui.Text("Down"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadDown).ToString(), new Vector2(ContentWidth, 50))) { Toggles[9] = true; } + if (Toggles[9]) { if (GetKey(ref pressedKey)) @@ -281,11 +315,13 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Left"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadLeft).ToString(), new Vector2(ContentWidth, 50))) { Toggles[10] = true; } + if (Toggles[10]) { if (GetKey(ref pressedKey)) @@ -299,11 +335,13 @@ namespace Ryujinx.UI.Widgets ImGui.SameLine(); ImGuiNative.igBeginGroup(); ImGui.Text("Right"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadRight).ToString(), new Vector2(ContentWidth, 50))) { Toggles[11] = true; } + if (Toggles[11]) { if (GetKey(ref pressedKey)) @@ -325,11 +363,13 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("A"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonA).ToString(), new Vector2(ContentWidth, 50))) { Toggles[12] = true; } + if (Toggles[12]) { if (GetKey(ref pressedKey)) @@ -343,11 +383,13 @@ namespace Ryujinx.UI.Widgets ImGui.SameLine(); ImGuiNative.igBeginGroup(); ImGui.Text("B"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonB).ToString(), new Vector2(ContentWidth, 50))) { Toggles[13] = true; } + if (Toggles[13]) { if (GetKey(ref pressedKey)) @@ -360,11 +402,13 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("X"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonX).ToString(), new Vector2(ContentWidth, 50))) { Toggles[14] = true; } + if (Toggles[14]) { if (GetKey(ref pressedKey)) @@ -378,11 +422,13 @@ namespace Ryujinx.UI.Widgets ImGui.SameLine(); ImGuiNative.igBeginGroup(); ImGui.Text("Y"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonY).ToString(), new Vector2(ContentWidth, 50))) { Toggles[15] = true; } + if (Toggles[15]) { if (GetKey(ref pressedKey)) @@ -391,6 +437,7 @@ namespace Ryujinx.UI.Widgets Toggles[15] = false; } } + ImGuiNative.igEndGroup(); ImGuiNative.igEndGroup(); @@ -405,11 +452,13 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("L"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.ButtonL).ToString(), new Vector2(ContentWidth, 50))) { Toggles[17] = true; } + if (Toggles[17]) { if (GetKey(ref pressedKey)) @@ -418,16 +467,19 @@ namespace Ryujinx.UI.Widgets Toggles[17] = false; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); ImGuiNative.igBeginGroup(); ImGui.Text("R"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonR).ToString(), new Vector2(ContentWidth, 50))) { Toggles[16] = true; } + if (Toggles[16]) { if (GetKey(ref pressedKey)) @@ -440,11 +492,13 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("ZL"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.ButtonZL).ToString(), new Vector2(ContentWidth, 50))) { Toggles[19] = true; } + if (Toggles[19]) { if (GetKey(ref pressedKey)) @@ -458,11 +512,13 @@ namespace Ryujinx.UI.Widgets ImGui.SameLine(); ImGuiNative.igBeginGroup(); ImGui.Text("ZR"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonZR).ToString(), new Vector2(ContentWidth, 50))) { Toggles[18] = true; } + if (Toggles[18]) { if (GetKey(ref pressedKey)) @@ -481,13 +537,16 @@ namespace Ryujinx.UI.Widgets //Draw Extra ImGuiNative.igBeginGroup(); ImGui.Text("Extra Keys"); + ImGuiNative.igBeginGroup(); ImGui.Text("-"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Left.ButtonMinus).ToString(), new Vector2(ContentWidth, 50))) { Toggles[20] = true; } + if (Toggles[20]) { if (GetKey(ref pressedKey)) @@ -500,11 +559,13 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("+"); + if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonPlus).ToString(), new Vector2(ContentWidth, 50))) { Toggles[21] = true; } + if (Toggles[21]) { if (GetKey(ref pressedKey)) @@ -521,11 +582,11 @@ namespace Ryujinx.UI.Widgets static bool GetKey(ref Key pressedKey) { IO IO = ImGui.GetIO(); - foreach (Key key in Enum.GetValues(typeof(Key))) + foreach (Key Key in Enum.GetValues(typeof(Key))) { - if (IO.KeysDown[(int)key]) + if (IO.KeysDown[(int)Key]) { - pressedKey = key; + pressedKey = Key; return true; } } diff --git a/Ryujinx.ImGui/GUI/Widgets/PauseUI.cs b/Ryujinx.ImGui/GUI/Widgets/PauseUI.cs index d5d7926d91..1a990b13a7 100644 --- a/Ryujinx.ImGui/GUI/Widgets/PauseUI.cs +++ b/Ryujinx.ImGui/GUI/Widgets/PauseUI.cs @@ -1,5 +1,4 @@ -using System; -using ImGuiNET; +using ImGuiNET; namespace Ryujinx.UI { partial class EmulationWindow @@ -8,6 +7,7 @@ namespace Ryujinx.UI { 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)) @@ -51,13 +51,14 @@ namespace Ryujinx.UI Values.ButtonHeight))) { ShowPauseUI = false; - EmulationController.Resume(); EmulationController.ShutDown(); ShowMainUI = true; } + break; case Page.Configuration: Widgets.ConfigurationWidget.Draw(); + break; } ImGui.EndChildFrame(); diff --git a/Ryujinx.ImGui/GUI/WindowHelper.cs b/Ryujinx.ImGui/GUI/WindowHelper.cs index 15d4d88321..593f3364db 100644 --- a/Ryujinx.ImGui/GUI/WindowHelper.cs +++ b/Ryujinx.ImGui/GUI/WindowHelper.cs @@ -1,39 +1,46 @@ -using System; -using System.Collections.Generic; -using System.Text; +using ImGuiNET; using OpenTK; -using OpenTK.Input; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; -using ImGuiNET; +using OpenTK.Input; +using System; namespace Ryujinx.UI { class WindowHelper : GameWindow { - protected float _deltaTime; - bool IsWindowOpened = false; - int s_fontTexture; - float _wheelPosition; + protected float DeltaTime; protected GraphicsContext MainContext; protected GraphicsContext UIContext; protected bool UIActive; - public WindowHelper(string title) : base(1280, 720, GraphicsMode.Default, title, GameWindowFlags.Default + private bool IsWindowOpened = false; + private int FontTexture; + private float WheelPosition; + + protected KeyboardState? Keyboard = null; + + protected MouseState? Mouse = null; + + public WindowHelper(string Title) : base(1280, 720, GraphicsMode.Default, Title, GameWindowFlags.Default , DisplayDevice.Default, 3, 3, GraphicsContextFlags.ForwardCompatible) { - Title = title; + base.Title = Title; + IsWindowOpened = true; Location = new Point( (DisplayDevice.Default.Width / 2) - (Width / 2), (DisplayDevice.Default.Height / 2) - (Height / 2)); - MainContext = (GraphicsContext)Context; + MainContext = new GraphicsContext(GraphicsMode.Default, + WindowInfo, 3, 3, GraphicsContextFlags.ForwardCompatible); UIContext = new GraphicsContext(GraphicsMode.Default, - WindowInfo,4,5,GraphicsContextFlags.ForwardCompatible); + WindowInfo, 3, 3, GraphicsContextFlags.ForwardCompatible); + UIContext.MakeCurrent(WindowInfo); + UIActive = true; } @@ -45,35 +52,39 @@ namespace Ryujinx.UI 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; + + 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); + + HandleInput(IO); } public unsafe void EndFrame() { ImGui.Render(); + DrawData* data = ImGui.GetDrawData(); RenderImDrawData(data); - MainContext.MakeCurrent(WindowInfo); + MainContext?.MakeCurrent(WindowInfo); } protected unsafe void PrepareTexture() { ImGui.GetIO().FontAtlas.AddDefaultFont(); - IO io = ImGui.GetIO(); + IO IO = ImGui.GetIO(); // Build texture atlas - FontTextureData texData = io.FontAtlas.GetTexDataAsAlpha8(); + FontTextureData texData = IO.FontAtlas.GetTexDataAsAlpha8(); // Create OpenGL texture - s_fontTexture = GL.GenTexture(); - GL.BindTexture(TextureTarget.Texture2D, s_fontTexture); + 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( @@ -88,11 +99,11 @@ namespace Ryujinx.UI new IntPtr(texData.Pixels)); // Store the texture identifier in the ImFontAtlas substructure. - io.FontAtlas.SetTexID(s_fontTexture); + IO.FontAtlas.SetTexID(FontTexture); // Cleanup (don't clear the input data if you want to append new fonts later) //io.Fonts->ClearInputData(); - io.FontAtlas.ClearTexData(); + IO.FontAtlas.ClearTexData(); GL.BindTexture(TextureTarget.Texture2D, 0); } @@ -101,69 +112,79 @@ namespace Ryujinx.UI PrepareTexture(); } - unsafe void HandleInput(IO io) + unsafe void HandleInput(IO IO) { - MouseState cursorState = Mouse.GetCursorState(); - MouseState mouseState = Mouse.GetState(); + 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) { - Point windowPoint = PointToClient(new Point(cursorState.X, cursorState.Y)); - io.MousePosition = new System.Numerics.Vector2(windowPoint.X / io.DisplayFramebufferScale.X, - windowPoint.Y / io.DisplayFramebufferScale.Y); - - foreach (Key key in Enum.GetValues(typeof(Key))) + if (Mouse.HasValue) { - io.KeysDown[(int)key] = Keyboard[key]; - if (Keyboard[key]) - continue; - ImGuiNative.igGetIO()->KeyAlt = (byte)((Keyboard[Key.AltLeft] - || Keyboard[Key.AltRight]) ? 1 : 0); - ImGuiNative.igGetIO()->KeyCtrl = (byte)((Keyboard[Key.ControlLeft] - || Keyboard[Key.ControlRight]) ? 1 : 0); - ImGuiNative.igGetIO()->KeyShift = (byte)((Keyboard[Key.ShiftLeft] - || Keyboard[Key.ShiftRight]) ? 1 : 0); - ImGuiNative.igGetIO()->KeySuper = (byte)((Keyboard[Key.WinLeft] - || Keyboard[Key.WinRight]) ? 1 : 0); + 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); + IO.MousePosition = new System.Numerics.Vector2(-1f, -1f); for (int i = 0; i <= 512; i++) { - io.KeysDown[i] = false; + IO.KeysDown[i] = false; } } - io.MouseDown[0] = mouseState.LeftButton == ButtonState.Pressed; - io.MouseDown[1] = mouseState.RightButton == ButtonState.Pressed; - io.MouseDown[2] = mouseState.MiddleButton == ButtonState.Pressed; + 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; + float NewWheelPos = MouseState.WheelPrecise; + float Delta = NewWheelPos - WheelPosition; + WheelPosition = NewWheelPos; + IO.MouseWheel = Delta; + } } - private unsafe void RenderImDrawData(DrawData* draw_data) + private unsafe void RenderImDrawData(DrawData* DrawData) { - // Rendering - int display_w, display_h; - display_w = Width; - display_h = Height; - - Vector4 clear_color = new Vector4(114f / 255f, 144f / 255f, 154f / 255f, 1.0f); - GL.Viewport(0, 0, display_w, display_h); - GL.ClearColor(clear_color.X, clear_color.Y, clear_color.Z, clear_color.W); + 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); // We are using the OpenGL fixed pipeline to make the example code simpler to read! // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. - int last_texture; - GL.GetInteger(GetPName.TextureBinding2D, out last_texture); + GL.GetInteger(GetPName.TextureBinding2D, out int last_texture); GL.PushAttrib(AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.TransformBit); GL.Enable(EnableCap.Blend); - GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.Disable(EnableCap.CullFace); GL.Disable(EnableCap.DepthTest); GL.Enable(EnableCap.ScissorTest); @@ -175,8 +196,8 @@ namespace Ryujinx.UI GL.UseProgram(0); // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) - IO io = ImGui.GetIO(); - ImGui.ScaleClipRects(draw_data, io.DisplayFramebufferScale); + IO IO = ImGui.GetIO(); + ImGui.ScaleClipRects(DrawData, IO.DisplayFramebufferScale); // Setup orthographic projection matrix GL.MatrixMode(MatrixMode.Projection); @@ -184,8 +205,8 @@ namespace Ryujinx.UI GL.LoadIdentity(); GL.Ortho( 0.0f, - io.DisplaySize.X / io.DisplayFramebufferScale.X, - io.DisplaySize.Y / io.DisplayFramebufferScale.Y, + IO.DisplaySize.X / IO.DisplayFramebufferScale.X, + IO.DisplaySize.Y / IO.DisplayFramebufferScale.Y, 0.0f, -1.0f, 1.0f); @@ -194,40 +215,37 @@ namespace Ryujinx.UI GL.LoadIdentity(); // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (int n = 0; n < DrawData->CmdListsCount; n++) { - NativeDrawList* cmd_list = draw_data->CmdLists[n]; - byte* vtx_buffer = (byte*)cmd_list->VtxBuffer.Data; - ushort* idx_buffer = (ushort*)cmd_list->IdxBuffer.Data; + NativeDrawList* CmdList = DrawData->CmdLists[n]; + byte* VtxBuffer = (byte*)CmdList->VtxBuffer.Data; + ushort* IdxBuffer = (ushort*)CmdList->IdxBuffer.Data; - DrawVert vert0 = *((DrawVert*)vtx_buffer); - DrawVert vert1 = *(((DrawVert*)vtx_buffer) + 1); - DrawVert vert2 = *(((DrawVert*)vtx_buffer) + 2); + 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)); - GL.VertexPointer(2, VertexPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.PosOffset)); - GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.UVOffset)); - GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.ColOffset)); - - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + for (int Cmd = 0; Cmd < CmdList->CmdBuffer.Size; Cmd++) { - DrawCmd* pcmd = &(((DrawCmd*)cmd_list->CmdBuffer.Data)[cmd_i]); - if (pcmd->UserCallback != IntPtr.Zero) + DrawCmd* PCmd = &(((DrawCmd*)CmdList->CmdBuffer.Data)[Cmd]); + if (PCmd->UserCallback != IntPtr.Zero) { throw new NotImplementedException(); } else { - GL.BindTexture(TextureTarget.Texture2D, pcmd->TextureId.ToInt32()); + 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] = idx_buffer[i]; } - GL.DrawElements(PrimitiveType.Triangles, (int)pcmd->ElemCount, DrawElementsType.UnsignedShort, new IntPtr(idx_buffer)); + (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)); } - idx_buffer += pcmd->ElemCount; + IdxBuffer += PCmd->ElemCount; } } @@ -244,5 +262,30 @@ namespace Ryujinx.UI SwapBuffers(); } + + 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; + } } } diff --git a/Ryujinx.ImGui/Program.cs b/Ryujinx.ImGui/Program.cs index 4830567316..cdb4b21755 100644 --- a/Ryujinx.ImGui/Program.cs +++ b/Ryujinx.ImGui/Program.cs @@ -7,6 +7,7 @@ namespace Ryujinx.UI static void Main(string[] args) { EmulationWindow mainUI = new EmulationWindow(); + mainUI.Run(60.0, 60.0); Environment.Exit(0); diff --git a/Ryujinx.ImGui/Ryujinx.UI.csproj b/Ryujinx.ImGui/Ryujinx.UI.csproj index 28669ca7b9..cb2235767d 100644 --- a/Ryujinx.ImGui/Ryujinx.UI.csproj +++ b/Ryujinx.ImGui/Ryujinx.UI.csproj @@ -16,7 +16,7 @@ - + diff --git a/Ryujinx/Properties/launchSettings.json b/Ryujinx/Properties/launchSettings.json deleted file mode 100644 index e59dd2a51e..0000000000 --- a/Ryujinx/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "Ryujinx": { - "commandName": "Project", - "commandLineArgs": "\"C:\\Users\\Emmanuel Hansen\\AppData\\Roaming\\RyuFs\\sdmc\\switch\\fruity\\fruity.nro\"" - } - } -} \ No newline at end of file From 32a9b10491c7869c93e3e9e3a4a921847e02a767 Mon Sep 17 00:00:00 2001 From: emmaus Date: Wed, 27 Jun 2018 10:23:20 +0000 Subject: [PATCH 04/11] Extended file picker to support drives --- .../GUI/Widgets/ConfigurationWidget.cs | 16 +- Ryujinx.ImGui/GUI/Widgets/FilePicker.cs | 105 ++++++++--- Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs | 166 ------------------ Ryujinx.ImGui/GUI/Widgets/GameList.cs | 6 +- 4 files changed, 93 insertions(+), 200 deletions(-) delete mode 100644 Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs diff --git a/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs b/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs index b2c758c1e3..7280267f16 100644 --- a/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs +++ b/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs @@ -6,19 +6,19 @@ namespace Ryujinx.UI.Widgets { public partial class ConfigurationWidget { - static bool ConfigIntialized = false; - static bool OpenFolderPicker; + static bool ConfigIntialized = false; + static bool OpenFolderPicker; static string CurrentPath; - static IniParser IniParser; - static FolderPicker FolderPicker; - static JoyCon CurrentJoyConLayout; - static Page CurrentPage = Page.General; + static IniParser IniParser; + static FilePicker FolderPicker; + static JoyCon CurrentJoyConLayout; + static Page CurrentPage = Page.General; static ConfigurationWidget() { IniParser = new IniParser(Config.IniPath); - FolderPicker = FolderPicker.GetFolderPicker("FolderDialog",Config.DefaultGameDirectory); + FolderPicker = FilePicker.GetFilePicker("FolderDialog",Config.DefaultGameDirectory); CurrentPath = Config.DefaultGameDirectory.ToString(); } @@ -65,7 +65,7 @@ namespace Ryujinx.UI.Widgets OpenFolderPicker = true; } if (OpenFolderPicker) - ImGui.OpenPopup("OpenFolder"); + ImGui.OpenPopup("Open Folder"); DialogResult DialogResult = FolderPicker.GetFolder(ref CurrentPath); if (DialogResult == DialogResult.OK) diff --git a/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs b/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs index 9653b02e0a..db76997636 100644 --- a/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs +++ b/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs @@ -17,6 +17,7 @@ namespace ImGuiNET public string CurrentFolder { get; set; } public string SelectedEntry { get; set; } + public string CurrentDrive { get; set; } public static FilePicker GetFilePicker(object Id, string StartingPath) { @@ -46,16 +47,40 @@ namespace ImGuiNET return FilePicker; } - public DialogResult Draw(ref string SelectedPath, bool ReturnOnSelection) + public DialogResult Draw(ref string SelectedPath, bool ReturnOnSelection, bool FoldersOnly = false) { - return DrawFolder(ref SelectedPath, ReturnOnSelection); + return DrawFolder(ref SelectedPath, ReturnOnSelection, FoldersOnly); } - private DialogResult DrawFolder(ref string SelectedPath, bool ReturnOnSelection = false) + private DialogResult DrawFolder(ref string SelectedPath, bool ReturnOnSelection = false, bool FoldersOnly = false) { ImGui.Text("Current Folder: " + CurrentFolder); - if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable() - new Vector2(20, Values.ButtonHeight), + 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); @@ -87,41 +112,43 @@ namespace ImGuiNET , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) { SelectedEntry = Dir; - SelectedPath = SelectedEntry; + SelectedPath = SelectedEntry; } if (SelectedEntry != null) if (ImGui.IsMouseDoubleClicked(0) && SelectedEntry.Equals(Dir)) { SelectedEntry = null; - SelectedPath = null; + SelectedPath = null; CurrentFolder = Dir; } ImGui.PopStyleColor(); } } - 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))) + if (!FoldersOnly) + foreach (string File in Directory.EnumerateFiles(CurrentDirectory.FullName)) { - SelectedEntry = File; - if (ReturnOnSelection) - { - SelectedPath = SelectedEntry; - } - } + string Name = Path.GetFileName(File); + bool IsSelected = SelectedEntry == File; - if (SelectedEntry != null) - if (ImGui.IsMouseDoubleClicked(0) && SelectedEntry.Equals(File)) + if (ImGui.Selectable(Name, IsSelected, SelectableFlags.DontClosePopups + , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) { - SelectedPath = File; + SelectedEntry = File; + if (ReturnOnSelection) + { + SelectedPath = SelectedEntry; + } } - } + + if (SelectedEntry != null) + if (ImGui.IsMouseDoubleClicked(0) && SelectedEntry.Equals(File)) + { + SelectedPath = File; + } + } } } ImGui.EndChildFrame(); @@ -135,7 +162,7 @@ namespace ImGuiNET if (SelectedEntry != null) { ImGui.SameLine(); - if (ImGui.Button("Load", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) + if (ImGui.Button("Open", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { SelectedPath = SelectedEntry; @@ -151,5 +178,37 @@ namespace ImGuiNET 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; + } } } diff --git a/Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs b/Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs deleted file mode 100644 index eaf8d2690f..0000000000 --- a/Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs +++ /dev/null @@ -1,166 +0,0 @@ -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 FolderPicker - { - private const string FolderPickerID = "###FolderPicker"; - private static readonly Dictionary FolderPickers - = new Dictionary(); - private static readonly Vector2 DefaultFilePickerSize = new Vector2(600, 400); - - public string CurrentFolder { get; set; } - public string SelectedDirectory { get; set; } - - public static FolderPicker GetFolderPicker(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 (!FolderPickers.TryGetValue(Id, out FolderPicker FolderPicker)) - { - FolderPicker = new FolderPicker - { - CurrentFolder = StartingPath - }; - - FolderPickers.Add(Id, FolderPicker); - } - - return FolderPicker; - } - - public DialogResult Draw(ref string Selected, bool ReturnOnSelection) - { - return DrawFolder(ref Selected, ReturnOnSelection); - } - - private DialogResult DrawFolder(ref string Selected, bool ReturnOnSelection = false) - { - ImGui.Text("Current Folder: " + CurrentFolder); - - if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable() - new Vector2(20, Values.ButtonHeight), - 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 (var Dir in Directory.EnumerateFileSystemEntries(CurrentDirectory.FullName)) - { - if (Directory.Exists(Dir)) - { - string Name = Path.GetFileName(Dir); - bool IsSelected = SelectedDirectory == Dir; - - ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow); - - if (ImGui.Selectable(Name + "/", IsSelected, SelectableFlags.DontClosePopups - , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) - { - SelectedDirectory = Dir; - Selected = SelectedDirectory; - } - - if (SelectedDirectory != null) - if (ImGui.IsMouseDoubleClicked(0) && SelectedDirectory.Equals(Dir)) - { - SelectedDirectory = null; - Selected = null; - CurrentFolder = Dir; - } - - ImGui.PopStyleColor(); - } - } - } - } - ImGui.EndChildFrame(); - - - if (ImGui.Button("Cancel", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) - { - return DialogResult.Cancel; - } - - if (SelectedDirectory != null) - { - ImGui.SameLine(); - if (ImGui.Button("Open", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) - { - Selected = SelectedDirectory; - - return DialogResult.OK; - } - else if(ReturnOnSelection) - { - Selected = SelectedDirectory; - - return DialogResult.OK; - } - } - - return DialogResult.None; - } - - public DialogResult GetFolder(ref string CurrentPath) - { - ImGui.SetNextWindowSize(new Vector2(500, 500), Condition.FirstUseEver); - if (ImGui.BeginPopupModal("OpenFolder", WindowFlags.NoResize)) - { - try - { - string Output = CurrentPath; - DialogResult DialogResult = Draw(ref Output, false); - - 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; - } - } -} diff --git a/Ryujinx.ImGui/GUI/Widgets/GameList.cs b/Ryujinx.ImGui/GUI/Widgets/GameList.cs index 51ebf895d0..b58d179521 100644 --- a/Ryujinx.ImGui/GUI/Widgets/GameList.cs +++ b/Ryujinx.ImGui/GUI/Widgets/GameList.cs @@ -14,12 +14,12 @@ namespace Ryujinx.UI.Widgets static string GameDirectory; static List GameItems; static GameItem SelectedGame; - static FolderPicker FolderPicker; + static FilePicker FolderPicker; static GameList() { GameDirectory = Config.DefaultGameDirectory; - FolderPicker = FolderPicker.GetFolderPicker("FolderDialog", Config.DefaultGameDirectory); + FolderPicker = FilePicker.GetFilePicker("FolderDialog", Config.DefaultGameDirectory); Refresh(GameDirectory); } @@ -75,7 +75,7 @@ namespace Ryujinx.UI.Widgets } if (OpenFolderPicker) - ImGui.OpenPopup("OpenFolder"); + ImGui.OpenPopup("Open Folder"); DialogResult DialogResult = FolderPicker.GetFolder(ref GameDirectory); if (DialogResult == DialogResult.OK) From 8ee7370c8fa62b29ba74c418654afba19be3f464 Mon Sep 17 00:00:00 2001 From: emmaus Date: Wed, 27 Jun 2018 10:32:39 +0000 Subject: [PATCH 05/11] renamed ImGui folder to UI --- {Ryujinx.ImGui => Ryujinx.UI}/Config.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/ConsoleLog.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/EmulationController.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/Extensions/ControlArchive.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/Extensions/DialogResult.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/Extensions/Nro.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/GUI/EmulationWindow.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/GUI/Values.cs | 0 .../GUI/Widgets/ConfigurationWidget.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/FilePicker.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/GameList.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/HomeUI.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/InputPage.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/NanoJpeg.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/PauseUI.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/GUI/WindowHelper.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/Program.cs | 0 {Ryujinx.ImGui => Ryujinx.UI}/Ryujinx.UI.csproj | 0 {Ryujinx.ImGui => Ryujinx.UI}/RyujinxUI.conf | 0 Ryujinx.sln | 2 +- 20 files changed, 1 insertion(+), 1 deletion(-) rename {Ryujinx.ImGui => Ryujinx.UI}/Config.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/ConsoleLog.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/EmulationController.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/Extensions/ControlArchive.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/Extensions/DialogResult.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/Extensions/Nro.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/GUI/EmulationWindow.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/GUI/Values.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/ConfigurationWidget.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/FilePicker.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/GameList.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/HomeUI.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/InputPage.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/NanoJpeg.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/GUI/Widgets/PauseUI.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/GUI/WindowHelper.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/Program.cs (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/Ryujinx.UI.csproj (100%) rename {Ryujinx.ImGui => Ryujinx.UI}/RyujinxUI.conf (100%) diff --git a/Ryujinx.ImGui/Config.cs b/Ryujinx.UI/Config.cs similarity index 100% rename from Ryujinx.ImGui/Config.cs rename to Ryujinx.UI/Config.cs diff --git a/Ryujinx.ImGui/ConsoleLog.cs b/Ryujinx.UI/ConsoleLog.cs similarity index 100% rename from Ryujinx.ImGui/ConsoleLog.cs rename to Ryujinx.UI/ConsoleLog.cs diff --git a/Ryujinx.ImGui/EmulationController.cs b/Ryujinx.UI/EmulationController.cs similarity index 100% rename from Ryujinx.ImGui/EmulationController.cs rename to Ryujinx.UI/EmulationController.cs diff --git a/Ryujinx.ImGui/Extensions/ControlArchive.cs b/Ryujinx.UI/Extensions/ControlArchive.cs similarity index 100% rename from Ryujinx.ImGui/Extensions/ControlArchive.cs rename to Ryujinx.UI/Extensions/ControlArchive.cs diff --git a/Ryujinx.ImGui/Extensions/DialogResult.cs b/Ryujinx.UI/Extensions/DialogResult.cs similarity index 100% rename from Ryujinx.ImGui/Extensions/DialogResult.cs rename to Ryujinx.UI/Extensions/DialogResult.cs diff --git a/Ryujinx.ImGui/Extensions/Nro.cs b/Ryujinx.UI/Extensions/Nro.cs similarity index 100% rename from Ryujinx.ImGui/Extensions/Nro.cs rename to Ryujinx.UI/Extensions/Nro.cs diff --git a/Ryujinx.ImGui/GUI/EmulationWindow.cs b/Ryujinx.UI/GUI/EmulationWindow.cs similarity index 100% rename from Ryujinx.ImGui/GUI/EmulationWindow.cs rename to Ryujinx.UI/GUI/EmulationWindow.cs diff --git a/Ryujinx.ImGui/GUI/Values.cs b/Ryujinx.UI/GUI/Values.cs similarity index 100% rename from Ryujinx.ImGui/GUI/Values.cs rename to Ryujinx.UI/GUI/Values.cs diff --git a/Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs b/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs similarity index 100% rename from Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs rename to Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs diff --git a/Ryujinx.ImGui/GUI/Widgets/FilePicker.cs b/Ryujinx.UI/GUI/Widgets/FilePicker.cs similarity index 100% rename from Ryujinx.ImGui/GUI/Widgets/FilePicker.cs rename to Ryujinx.UI/GUI/Widgets/FilePicker.cs diff --git a/Ryujinx.ImGui/GUI/Widgets/GameList.cs b/Ryujinx.UI/GUI/Widgets/GameList.cs similarity index 100% rename from Ryujinx.ImGui/GUI/Widgets/GameList.cs rename to Ryujinx.UI/GUI/Widgets/GameList.cs diff --git a/Ryujinx.ImGui/GUI/Widgets/HomeUI.cs b/Ryujinx.UI/GUI/Widgets/HomeUI.cs similarity index 100% rename from Ryujinx.ImGui/GUI/Widgets/HomeUI.cs rename to Ryujinx.UI/GUI/Widgets/HomeUI.cs diff --git a/Ryujinx.ImGui/GUI/Widgets/InputPage.cs b/Ryujinx.UI/GUI/Widgets/InputPage.cs similarity index 100% rename from Ryujinx.ImGui/GUI/Widgets/InputPage.cs rename to Ryujinx.UI/GUI/Widgets/InputPage.cs diff --git a/Ryujinx.ImGui/GUI/Widgets/NanoJpeg.cs b/Ryujinx.UI/GUI/Widgets/NanoJpeg.cs similarity index 100% rename from Ryujinx.ImGui/GUI/Widgets/NanoJpeg.cs rename to Ryujinx.UI/GUI/Widgets/NanoJpeg.cs diff --git a/Ryujinx.ImGui/GUI/Widgets/PauseUI.cs b/Ryujinx.UI/GUI/Widgets/PauseUI.cs similarity index 100% rename from Ryujinx.ImGui/GUI/Widgets/PauseUI.cs rename to Ryujinx.UI/GUI/Widgets/PauseUI.cs diff --git a/Ryujinx.ImGui/GUI/WindowHelper.cs b/Ryujinx.UI/GUI/WindowHelper.cs similarity index 100% rename from Ryujinx.ImGui/GUI/WindowHelper.cs rename to Ryujinx.UI/GUI/WindowHelper.cs diff --git a/Ryujinx.ImGui/Program.cs b/Ryujinx.UI/Program.cs similarity index 100% rename from Ryujinx.ImGui/Program.cs rename to Ryujinx.UI/Program.cs diff --git a/Ryujinx.ImGui/Ryujinx.UI.csproj b/Ryujinx.UI/Ryujinx.UI.csproj similarity index 100% rename from Ryujinx.ImGui/Ryujinx.UI.csproj rename to Ryujinx.UI/Ryujinx.UI.csproj diff --git a/Ryujinx.ImGui/RyujinxUI.conf b/Ryujinx.UI/RyujinxUI.conf similarity index 100% rename from Ryujinx.ImGui/RyujinxUI.conf rename to Ryujinx.UI/RyujinxUI.conf diff --git a/Ryujinx.sln b/Ryujinx.sln index 97fe49d623..da0dbcd463 100644 --- a/Ryujinx.sln +++ b/Ryujinx.sln @@ -19,7 +19,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.ShaderTools", "Ryuj EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luea", "Ryujinx.LLE\Luea.csproj", "{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.UI", "Ryujinx.ImGui\Ryujinx.UI.csproj", "{00117502-1661-4C8B-8C07-177C1A8AA455}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.UI", "Ryujinx.UI\Ryujinx.UI.csproj", "{00117502-1661-4C8B-8C07-177C1A8AA455}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 7404d09c2c87abeb9addf0f59eac8427dd9a57b7 Mon Sep 17 00:00:00 2001 From: emmaus Date: Fri, 29 Jun 2018 21:04:49 +0000 Subject: [PATCH 06/11] addressed comments --- ChocolArm64/ATranslator.cs | 14 ++++++++++++-- Ryujinx.Graphics/Gal/IGalRenderer.cs | 2 +- Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs | 2 +- Ryujinx.HLE/Loaders/Executables/Nro.cs | 15 ++++++--------- Ryujinx.HLE/OsHle/Horizon.cs | 10 +--------- Ryujinx.HLE/OsHle/Process.cs | 8 ++++---- Ryujinx.UI/EmulationController.cs | 13 ++++++------- Ryujinx.UI/Extensions/ControlArchive.cs | 3 +-- Ryujinx.UI/Extensions/Nro.cs | 1 - Ryujinx.UI/GUI/Widgets/FilePicker.cs | 6 ++---- Ryujinx.UI/GUI/Widgets/GameList.cs | 14 +++++--------- Ryujinx.UI/GUI/Widgets/HomeUI.cs | 17 +++++++++-------- Ryujinx.UI/GUI/WindowHelper.cs | 2 -- 13 files changed, 48 insertions(+), 59 deletions(-) diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs index 7937aaf7fd..a83eb08ea3 100644 --- a/ChocolArm64/ATranslator.cs +++ b/ChocolArm64/ATranslator.cs @@ -22,7 +22,7 @@ namespace ChocolArm64 public bool EnableCpuTrace { get; set; } - public static ManualResetEvent PauseResetEvent = new ManualResetEvent(true); + private ManualResetEvent PauseResetEvent = new ManualResetEvent(true); public ATranslator(IReadOnlyDictionary SymbolTable = null) { @@ -64,7 +64,7 @@ namespace ChocolArm64 OpCode.Interpreter(State, Memory, OpCode); - PauseResetEvent.WaitOne(1000); + PauseResetEvent.WaitOne(); } while (State.R15 != 0 && State.Running); } @@ -209,5 +209,15 @@ namespace ChocolArm64 } } } + + public void Pause() + { + PauseResetEvent.Reset(); + } + + public void Resume() + { + PauseResetEvent.Set(); + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs index 61d42dfa3b..48db59b11e 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderer.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs @@ -2,7 +2,7 @@ using System; namespace Ryujinx.Graphics.Gal { - public unsafe interface IGalRenderer : IDisposable + public interface IGalRenderer : IDisposable { void QueueAction(Action ActionMthd); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index 8837f49b92..cd52762c79 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs @@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - public class FrameBuffer + private class FrameBuffer { public int Width { get; set; } public int Height { get; set; } diff --git a/Ryujinx.HLE/Loaders/Executables/Nro.cs b/Ryujinx.HLE/Loaders/Executables/Nro.cs index 4861920c7f..21e3dba9d0 100644 --- a/Ryujinx.HLE/Loaders/Executables/Nro.cs +++ b/Ryujinx.HLE/Loaders/Executables/Nro.cs @@ -1,7 +1,4 @@ -using System; -using System.Drawing; using System.IO; -using System.Text; namespace Ryujinx.HLE.Loaders.Executables { @@ -43,12 +40,12 @@ namespace Ryujinx.HLE.Loaders.Executables int DataSize = Reader.ReadInt32(); int BssSize = Reader.ReadInt32(); - this.Mod0Offset = Mod0Offset; - this.TextOffset = TextOffset; - this.ROOffset = ROOffset; - this.DataOffset = DataOffset; - this.BssSize = BssSize; - this.FileSize = FileSize; + this.Mod0Offset = Mod0Offset; + this.TextOffset = TextOffset; + this.ROOffset = ROOffset; + this.DataOffset = DataOffset; + this.BssSize = BssSize; + this.FileSize = FileSize; byte[] Read(long Position, int Size) { diff --git a/Ryujinx.HLE/OsHle/Horizon.cs b/Ryujinx.HLE/OsHle/Horizon.cs index 7b8b4b40c4..0e3f0eb076 100644 --- a/Ryujinx.HLE/OsHle/Horizon.cs +++ b/Ryujinx.HLE/OsHle/Horizon.cs @@ -195,15 +195,7 @@ namespace Ryujinx.HLE.OsHle if (Processes.TryRemove(ProcessId, out Process)) { - try - { - Process.StopAllThreadsAsync(); - Process.Dispose(); - } - catch (ObjectDisposedException Ex) - { - - } + Process.StopAllThreadsAsync(); if (Processes.Count == 0) { diff --git a/Ryujinx.HLE/OsHle/Process.cs b/Ryujinx.HLE/OsHle/Process.cs index f0619111ee..a7cf026a76 100644 --- a/Ryujinx.HLE/OsHle/Process.cs +++ b/Ryujinx.HLE/OsHle/Process.cs @@ -176,7 +176,7 @@ namespace Ryujinx.HLE.OsHle throw new ObjectDisposedException(nameof(Process)); } - ATranslator.PauseResetEvent.Reset(); + Translator.Pause(); } public void Resume() @@ -186,7 +186,7 @@ namespace Ryujinx.HLE.OsHle throw new ObjectDisposedException(nameof(Process)); } - ATranslator.PauseResetEvent.Set(); + Translator.Resume(); } private void MapRWMemRegion(long Position, long Size, MemoryType Type) @@ -198,7 +198,7 @@ namespace Ryujinx.HLE.OsHle { if (Disposed) { - throw new ObjectDisposedException(nameof(Process)); + return; } if (MainThread != null) @@ -423,7 +423,7 @@ namespace Ryujinx.HLE.OsHle { if (Disposing && !Disposed) { - ATranslator.PauseResetEvent.Set(); + 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 diff --git a/Ryujinx.UI/EmulationController.cs b/Ryujinx.UI/EmulationController.cs index b965d27652..c4985d809d 100644 --- a/Ryujinx.UI/EmulationController.cs +++ b/Ryujinx.UI/EmulationController.cs @@ -19,22 +19,21 @@ namespace Ryujinx.UI public void Resume() { - lock (Ns) - Ns.Os.ResumeAllProcesses(); + Ns.Os.ResumeAllProcesses(); } public void Pause() { - lock (Ns) - Ns.Os.PauseAllProcesses(); + Ns.Os.PauseAllProcesses(); } public void ShutDown() { - lock (Ns) - Ns.Dispose(); - Ns = null; + Ns.Dispose(); + + Ns = null; IsLoaded = false; + IsShutDown.Invoke(null,null); } diff --git a/Ryujinx.UI/Extensions/ControlArchive.cs b/Ryujinx.UI/Extensions/ControlArchive.cs index c85ef04302..4e7cbdec4a 100644 --- a/Ryujinx.UI/Extensions/ControlArchive.cs +++ b/Ryujinx.UI/Extensions/ControlArchive.cs @@ -45,10 +45,9 @@ namespace Ryujinx.UI } } - public struct LanguageEntry { public string AplicationName; public string DeveloperName; } -} +} \ No newline at end of file diff --git a/Ryujinx.UI/Extensions/Nro.cs b/Ryujinx.UI/Extensions/Nro.cs index c94d6b6c17..167cc7e8ff 100644 --- a/Ryujinx.UI/Extensions/Nro.cs +++ b/Ryujinx.UI/Extensions/Nro.cs @@ -15,7 +15,6 @@ namespace Ryujinx.UI public ControlArchive ControlArchive { get; set; } - public Nro(Stream Input, string Name) : base(Input, Name) { BinaryReader Reader = new BinaryReader(Input); diff --git a/Ryujinx.UI/GUI/Widgets/FilePicker.cs b/Ryujinx.UI/GUI/Widgets/FilePicker.cs index db76997636..0eeac2ad7c 100644 --- a/Ryujinx.UI/GUI/Widgets/FilePicker.cs +++ b/Ryujinx.UI/GUI/Widgets/FilePicker.cs @@ -5,10 +5,8 @@ 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 - /// + // 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"; diff --git a/Ryujinx.UI/GUI/Widgets/GameList.cs b/Ryujinx.UI/GUI/Widgets/GameList.cs index b58d179521..59746f1f3f 100644 --- a/Ryujinx.UI/GUI/Widgets/GameList.cs +++ b/Ryujinx.UI/GUI/Widgets/GameList.cs @@ -61,7 +61,7 @@ namespace Ryujinx.UI.Widgets } } - public unsafe static Tuple DrawList() + public unsafe static (bool,string) DrawList() { uint id = 100; @@ -131,7 +131,7 @@ namespace Ryujinx.UI.Widgets if (ImGui.IsMouseDoubleClicked(0) && ImGui.IsItemHovered(HoveredFlags.AllowWhenOverlapped) && GameItem == SelectedGame) { - return new Tuple(true, GameItem.Path); + return (true, GameItem.Path); } else if (ImGui.IsMouseClicked(0) && ImGui.IsItemHovered(HoveredFlags.AllowWhenOverlapped | HoveredFlags.RootAndChildWindows)) { @@ -145,7 +145,7 @@ namespace Ryujinx.UI.Widgets ImGui.EndChildFrame(); } - return new Tuple(false,string.Empty); + return (false, string.Empty); } } @@ -174,15 +174,11 @@ namespace Ryujinx.UI.Widgets } else AppletType = AppletType.Cartridge; - } + } public byte[] GetIconData() { - if (IsNro) - { - return Nro.IconData; - } - else return null; + return IsNro ? Nro.IconData : null; } } diff --git a/Ryujinx.UI/GUI/Widgets/HomeUI.cs b/Ryujinx.UI/GUI/Widgets/HomeUI.cs index 819f3e2372..188306e0bf 100644 --- a/Ryujinx.UI/GUI/Widgets/HomeUI.cs +++ b/Ryujinx.UI/GUI/Widgets/HomeUI.cs @@ -1,5 +1,6 @@ using ImGuiNET; using System; +using System.Numerics; namespace Ryujinx.UI { @@ -7,30 +8,30 @@ namespace Ryujinx.UI { void RenderMainUI() { - ImGui.SetNextWindowPos(System.Numerics.Vector2.Zero, Condition.Always, - System.Numerics.Vector2.Zero); - ImGui.SetNextWindowSize(new System.Numerics.Vector2(Width, Height), Condition.Always); + 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 System.Numerics.Vector2(-1, -1), + if (ImGui.BeginChildFrame(0, new Vector2(-1, -1), WindowFlags.AlwaysAutoResize)) { ImGuiNative.igBeginGroup(); - if (ImGui.Button("Load Package", new System.Numerics.Vector2(Values.ButtonWidth, + if (ImGui.Button("Load Package", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { CurrentPage = Page.PackageLoader; } - if (ImGui.Button("Game List", new System.Numerics.Vector2(Values.ButtonWidth, + if (ImGui.Button("Game List", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { CurrentPage = Page.GameList; } - if (ImGui.Button("Settings", new System.Numerics.Vector2(Values.ButtonWidth, + if (ImGui.Button("Settings", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { CurrentPage = Page.Configuration; @@ -78,7 +79,7 @@ namespace Ryujinx.UI void DrawQuitButton() { - if (ImGui.Button("Quit Ryujinx", new System.Numerics.Vector2(Values.ButtonWidth, + if (ImGui.Button("Quit Ryujinx", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { ImGui.OpenPopup("Quit"); diff --git a/Ryujinx.UI/GUI/WindowHelper.cs b/Ryujinx.UI/GUI/WindowHelper.cs index 593f3364db..ca93d2782c 100644 --- a/Ryujinx.UI/GUI/WindowHelper.cs +++ b/Ryujinx.UI/GUI/WindowHelper.cs @@ -179,8 +179,6 @@ namespace Ryujinx.UI GL.ClearColor(ClearColor.X, ClearColor.Y, ClearColor.Z, ClearColor.W); GL.Clear(ClearBufferMask.ColorBufferBit); - // We are using the OpenGL fixed pipeline to make the example code simpler to read! - // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. GL.GetInteger(GetPName.TextureBinding2D, out int last_texture); GL.PushAttrib(AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.TransformBit); GL.Enable(EnableCap.Blend); From dd9ea4bba6b0c645900536773816832809989821 Mon Sep 17 00:00:00 2001 From: emmaus Date: Tue, 3 Jul 2018 15:17:42 +0000 Subject: [PATCH 07/11] moved common ui code to comon project --- {Ryujinx.UI => Ryujinx.Common}/ConsoleLog.cs | 2 +- .../Input}/JoyConController.cs | 6 +-- .../Input}/JoyConKeyboard.cs | 2 +- Ryujinx.Common/Ryujinx.Common.csproj | 11 ++++ Ryujinx.UI/Ryujinx.UI.csproj | 1 + Ryujinx.sln | 8 ++- Ryujinx/Config.cs | 2 +- Ryujinx/Ryujinx.csproj | 1 + Ryujinx/Ui/ConsoleLog.cs | 51 ------------------- 9 files changed, 24 insertions(+), 60 deletions(-) rename {Ryujinx.UI => Ryujinx.Common}/ConsoleLog.cs (97%) rename {Ryujinx/Ui => Ryujinx.Common/Input}/JoyConController.cs (89%) rename {Ryujinx/Ui => Ryujinx.Common/Input}/JoyConKeyboard.cs (96%) create mode 100644 Ryujinx.Common/Ryujinx.Common.csproj delete mode 100644 Ryujinx/Ui/ConsoleLog.cs diff --git a/Ryujinx.UI/ConsoleLog.cs b/Ryujinx.Common/ConsoleLog.cs similarity index 97% rename from Ryujinx.UI/ConsoleLog.cs rename to Ryujinx.Common/ConsoleLog.cs index 1a2899946b..98edf1e716 100644 --- a/Ryujinx.UI/ConsoleLog.cs +++ b/Ryujinx.Common/ConsoleLog.cs @@ -5,7 +5,7 @@ using System.Threading; namespace Ryujinx { - static class ConsoleLog + public static class ConsoleLog { private static Dictionary LogColors; diff --git a/Ryujinx/Ui/JoyConController.cs b/Ryujinx.Common/Input/JoyConController.cs similarity index 89% rename from Ryujinx/Ui/JoyConController.cs rename to Ryujinx.Common/Input/JoyConController.cs index e525017d3e..b7754e6a09 100644 --- a/Ryujinx/Ui/JoyConController.cs +++ b/Ryujinx.Common/Input/JoyConController.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Ryujinx.UI.Input +namespace Ryujinx.Common.Input { public struct JoyConControllerLeft { diff --git a/Ryujinx/Ui/JoyConKeyboard.cs b/Ryujinx.Common/Input/JoyConKeyboard.cs similarity index 96% rename from Ryujinx/Ui/JoyConKeyboard.cs rename to Ryujinx.Common/Input/JoyConKeyboard.cs index b329d9ecd1..c79aaae21f 100644 --- a/Ryujinx/Ui/JoyConKeyboard.cs +++ b/Ryujinx.Common/Input/JoyConKeyboard.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.UI.Input +namespace Ryujinx.Common.Input { public struct JoyConKeyboardLeft { diff --git a/Ryujinx.Common/Ryujinx.Common.csproj b/Ryujinx.Common/Ryujinx.Common.csproj new file mode 100644 index 0000000000..ed85311fbf --- /dev/null +++ b/Ryujinx.Common/Ryujinx.Common.csproj @@ -0,0 +1,11 @@ + + + + netcoreapp2.1 + + + + + + + diff --git a/Ryujinx.UI/Ryujinx.UI.csproj b/Ryujinx.UI/Ryujinx.UI.csproj index cb2235767d..7484d13841 100644 --- a/Ryujinx.UI/Ryujinx.UI.csproj +++ b/Ryujinx.UI/Ryujinx.UI.csproj @@ -23,6 +23,7 @@ + diff --git a/Ryujinx.sln b/Ryujinx.sln index da0dbcd463..af558035b7 100644 --- a/Ryujinx.sln +++ b/Ryujinx.sln @@ -19,7 +19,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.ShaderTools", "Ryuj EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luea", "Ryujinx.LLE\Luea.csproj", "{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.UI", "Ryujinx.UI\Ryujinx.UI.csproj", "{00117502-1661-4C8B-8C07-177C1A8AA455}" +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 @@ -63,6 +65,10 @@ Global {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 diff --git a/Ryujinx/Config.cs b/Ryujinx/Config.cs index 0f346122af..7a78d6c6f6 100644 --- a/Ryujinx/Config.cs +++ b/Ryujinx/Config.cs @@ -1,4 +1,4 @@ -using Ryujinx.UI.Input; +using Ryujinx.Common.Input; using Ryujinx.HLE.Logging; using System; using System.Globalization; diff --git a/Ryujinx/Ryujinx.csproj b/Ryujinx/Ryujinx.csproj index 443e7bbad8..4762bf9b70 100644 --- a/Ryujinx/Ryujinx.csproj +++ b/Ryujinx/Ryujinx.csproj @@ -12,6 +12,7 @@ + diff --git a/Ryujinx/Ui/ConsoleLog.cs b/Ryujinx/Ui/ConsoleLog.cs deleted file mode 100644 index 1a2899946b..0000000000 --- a/Ryujinx/Ui/ConsoleLog.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Ryujinx.HLE.Logging; -using System; -using System.Collections.Generic; -using System.Threading; - -namespace Ryujinx -{ - static class ConsoleLog - { - private static Dictionary LogColors; - - private static object ConsoleLock; - - static ConsoleLog() - { - LogColors = new Dictionary() - { - { LogLevel.Stub, ConsoleColor.DarkGray }, - { LogLevel.Info, ConsoleColor.White }, - { LogLevel.Warning, ConsoleColor.Yellow }, - { LogLevel.Error, ConsoleColor.Red } - }; - - ConsoleLock = new object(); - } - - public static void PrintLog(object sender, LogEventArgs e) - { - string FormattedTime = e.Time.ToString(@"hh\:mm\:ss\.fff"); - - string CurrentThread = Thread.CurrentThread.ManagedThreadId.ToString("d4"); - - string Message = FormattedTime + " | " + CurrentThread + " " + e.Message; - - if (LogColors.TryGetValue(e.Level, out ConsoleColor Color)) - { - lock (ConsoleLock) - { - Console.ForegroundColor = Color; - - Console.WriteLine(Message); - Console.ResetColor(); - } - } - else - { - Console.WriteLine(Message); - } - } - } -} \ No newline at end of file From e72bee5f4224faa82d2e774198451becd96e93de Mon Sep 17 00:00:00 2001 From: emmaus Date: Tue, 3 Jul 2018 16:39:32 +0000 Subject: [PATCH 08/11] support new input binding in ui config --- Ryujinx.UI/Config.cs | 174 ++++++++++++------ Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs | 15 +- Ryujinx.UI/GUI/Widgets/InputPage.cs | 88 ++++----- 3 files changed, 172 insertions(+), 105 deletions(-) diff --git a/Ryujinx.UI/Config.cs b/Ryujinx.UI/Config.cs index c2f3dadd13..949541f5f5 100644 --- a/Ryujinx.UI/Config.cs +++ b/Ryujinx.UI/Config.cs @@ -1,8 +1,9 @@ -using Ryujinx.HLE; -using Ryujinx.HLE.Input; +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; @@ -11,7 +12,13 @@ namespace Ryujinx { public static class Config { - public static JoyCon FakeJoyCon { get; internal set; } + public static JoyConKeyboard JoyConKeyboard { get; set; } + public static JoyConController JoyConController { get; set; } + + public static float GamePadDeadzone { get; private set; } + public static bool GamePadEnable { get; private set; } + public static int GamePadIndex { get; private set; } + public static float GamePadTriggerThreshold { get; private set; } public static string IniPath { get; set; } @@ -33,6 +40,11 @@ namespace Ryujinx 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 @@ -61,38 +73,67 @@ namespace Ryujinx } } - FakeJoyCon = new JoyCon + JoyConKeyboard = new JoyConKeyboard { - Left = new JoyConLeft + Left = new JoyConKeyboardLeft { - StickUp = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Stick_Up")), - StickDown = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Stick_Down")), - StickLeft = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Stick_Left")), - StickRight = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Stick_Right")), - StickButton = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Stick_Button")), - DPadUp = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_DPad_Up")), - DPadDown = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_DPad_Down")), - DPadLeft = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_DPad_Left")), - DPadRight = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_DPad_Right")), - ButtonMinus = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Button_Minus")), - ButtonL = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Button_L")), - ButtonZL = Convert.ToInt16(Parser.GetValue("Controls_Left_FakeJoycon_Button_ZL")) + 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 JoyConRight + Right = new JoyConKeyboardRight { - StickUp = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Stick_Up")), - StickDown = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Stick_Down")), - StickLeft = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Stick_Left")), - StickRight = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Stick_Right")), - StickButton = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Stick_Button")), - ButtonA = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_A")), - ButtonB = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_B")), - ButtonX = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_X")), - ButtonY = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_Y")), - ButtonPlus = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_Plus")), - ButtonR = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_R")), - ButtonZR = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_ZR")) + 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 = Parser.GetValue("Controls_Left_JoyConController_Stick"), + StickButton = Parser.GetValue("Controls_Left_JoyConController_Stick_Button"), + DPadUp = Parser.GetValue("Controls_Left_JoyConController_DPad_Up"), + DPadDown = Parser.GetValue("Controls_Left_JoyConController_DPad_Down"), + DPadLeft = Parser.GetValue("Controls_Left_JoyConController_DPad_Left"), + DPadRight = Parser.GetValue("Controls_Left_JoyConController_DPad_Right"), + ButtonMinus = Parser.GetValue("Controls_Left_JoyConController_Button_Minus"), + ButtonL = Parser.GetValue("Controls_Left_JoyConController_Button_L"), + ButtonZL = Parser.GetValue("Controls_Left_JoyConController_Button_ZL") + }, + + Right = new JoyConControllerRight + { + Stick = Parser.GetValue("Controls_Right_JoyConController_Stick"), + StickButton = Parser.GetValue("Controls_Right_JoyConController_Stick_Button"), + ButtonA = Parser.GetValue("Controls_Right_JoyConController_Button_A"), + ButtonB = Parser.GetValue("Controls_Right_JoyConController_Button_B"), + ButtonX = Parser.GetValue("Controls_Right_JoyConController_Button_X"), + ButtonY = Parser.GetValue("Controls_Right_JoyConController_Button_Y"), + ButtonPlus = Parser.GetValue("Controls_Right_JoyConController_Button_Plus"), + ButtonR = Parser.GetValue("Controls_Right_JoyConController_Button_R"), + ButtonZR = Parser.GetValue("Controls_Right_JoyConController_Button_ZR") } }; @@ -138,31 +179,56 @@ namespace Ryujinx Parser.SetValue("Logging_Filtered_Classes", string.Join(',', FilteredClasses)); - Parser.SetValue("Controls_Left_FakeJoycon_Stick_Up", FakeJoyCon.Left.StickUp.ToString()); - Parser.SetValue("Controls_Left_FakeJoycon_Stick_Down", FakeJoyCon.Left.StickDown.ToString()); - Parser.SetValue("Controls_Left_FakeJoycon_Stick_Left", FakeJoyCon.Left.StickLeft.ToString()); - Parser.SetValue("Controls_Left_FakeJoycon_Stick_Right", FakeJoyCon.Left.StickRight.ToString()); - Parser.SetValue("Controls_Left_FakeJoycon_Stick_Button", FakeJoyCon.Left.StickButton.ToString()); - Parser.SetValue("Controls_Left_FakeJoycon_DPad_Up", FakeJoyCon.Left.DPadUp.ToString()); - Parser.SetValue("Controls_Left_FakeJoycon_DPad_Down", FakeJoyCon.Left.DPadDown.ToString()); - Parser.SetValue("Controls_Left_FakeJoycon_DPad_Left", FakeJoyCon.Left.DPadLeft.ToString()); - Parser.SetValue("Controls_Left_FakeJoycon_DPad_Right", FakeJoyCon.Left.DPadRight.ToString()); - Parser.SetValue("Controls_Left_FakeJoycon_Button_Minus", FakeJoyCon.Left.ButtonMinus.ToString()); - Parser.SetValue("Controls_Left_FakeJoycon_Button_L", FakeJoyCon.Left.ButtonL.ToString()); - Parser.SetValue("Controls_Left_FakeJoycon_Button_ZL", FakeJoyCon.Left.ButtonZL.ToString()); + 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_FakeJoycon_Stick_Up", FakeJoyCon.Right.StickUp.ToString()); - Parser.SetValue("Controls_Right_FakeJoycon_Stick_Down", FakeJoyCon.Right.StickDown.ToString()); - Parser.SetValue("Controls_Right_FakeJoycon_Stick_Left", FakeJoyCon.Right.StickLeft.ToString()); - Parser.SetValue("Controls_Right_FakeJoycon_Stick_Right", FakeJoyCon.Right.StickRight.ToString()); - Parser.SetValue("Controls_Right_FakeJoycon_Stick_Button", FakeJoyCon.Right.StickButton.ToString()); - Parser.SetValue("Controls_Right_FakeJoycon_Button_A", FakeJoyCon.Right.StickUp.ToString()); - Parser.SetValue("Controls_Right_FakeJoycon_Button_B", FakeJoyCon.Right.StickUp.ToString()); - Parser.SetValue("Controls_Right_FakeJoycon_Button_X", FakeJoyCon.Right.StickUp.ToString()); - Parser.SetValue("Controls_Right_FakeJoycon_Button_Y", FakeJoyCon.Right.StickUp.ToString()); - Parser.SetValue("Controls_Right_FakeJoycon_Button_Plus", FakeJoyCon.Right.StickUp.ToString()); - Parser.SetValue("Controls_Right_FakeJoycon_Button_R", FakeJoyCon.Right.StickUp.ToString()); - Parser.SetValue("Controls_Right_FakeJoycon_Button_ZR", FakeJoyCon.Right.StickUp.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); diff --git a/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs b/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs index 7280267f16..7d116d7b55 100644 --- a/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs +++ b/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs @@ -1,5 +1,5 @@ using ImGuiNET; -using Ryujinx.HLE.Input; +using Ryujinx.Common.Input; using System.Numerics; namespace Ryujinx.UI.Widgets @@ -10,10 +10,11 @@ namespace Ryujinx.UI.Widgets static bool OpenFolderPicker; static string CurrentPath; - static IniParser IniParser; - static FilePicker FolderPicker; - static JoyCon CurrentJoyConLayout; - static Page CurrentPage = Page.General; + static IniParser IniParser; + static FilePicker FolderPicker; + static JoyConKeyboard KeyboardInputLayout; + static JoyConController ControllerInputLayout; + static Page CurrentPage = Page.General; static ConfigurationWidget() { @@ -26,7 +27,7 @@ namespace Ryujinx.UI.Widgets { if(!ConfigIntialized) { - CurrentJoyConLayout = Config.FakeJoyCon; + KeyboardInputLayout = Config.JoyConKeyboard; ConfigIntialized = true; } @@ -103,7 +104,7 @@ namespace Ryujinx.UI.Widgets { if (ImGui.Button("Apply", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { - Config.FakeJoyCon = CurrentJoyConLayout; + Config.JoyConKeyboard = KeyboardInputLayout; } ImGui.SameLine(); } diff --git a/Ryujinx.UI/GUI/Widgets/InputPage.cs b/Ryujinx.UI/GUI/Widgets/InputPage.cs index d8218f11ae..24b33e9a1d 100644 --- a/Ryujinx.UI/GUI/Widgets/InputPage.cs +++ b/Ryujinx.UI/GUI/Widgets/InputPage.cs @@ -99,7 +99,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Up"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickUp).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickUp).ToString(), new Vector2(ContentWidth, 50))) { Toggles[0] = true; @@ -109,7 +109,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Left.StickUp = (int)pressedKey; + KeyboardInputLayout.Left.StickUp = (int)pressedKey; Toggles[0] = false; } } @@ -120,7 +120,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Down"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickDown).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickDown).ToString(), new Vector2(ContentWidth, 50))) { Toggles[1] = true; @@ -130,7 +130,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Left.StickDown = (int)pressedKey; + KeyboardInputLayout.Left.StickDown = (int)pressedKey; Toggles[1] = false; } } @@ -140,7 +140,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Left"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickLeft).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickLeft).ToString(), new Vector2(ContentWidth, 50))) { Toggles[2] = true; @@ -150,7 +150,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Left.StickLeft = (int)pressedKey; + KeyboardInputLayout.Left.StickLeft = (int)pressedKey; Toggles[2] = false; } } @@ -160,7 +160,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Right"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Left.StickRight).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickRight).ToString(), new Vector2(ContentWidth, 50))) { Toggles[3] = true; @@ -170,7 +170,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Left.StickRight = (int)pressedKey; + KeyboardInputLayout.Left.StickRight = (int)pressedKey; Toggles[3] = false; } } @@ -189,7 +189,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Up"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickUp).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickUp).ToString(), new Vector2(ContentWidth, 50))) { Toggles[4] = true; @@ -199,7 +199,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Right.StickUp = (int)pressedKey; + KeyboardInputLayout.Right.StickUp = (int)pressedKey; Toggles[4] = false; } @@ -210,7 +210,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Down"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickDown).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickDown).ToString(), new Vector2(ContentWidth, 50))) { Toggles[5] = true; @@ -220,7 +220,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Right.StickDown = (int)pressedKey; + KeyboardInputLayout.Right.StickDown = (int)pressedKey; Toggles[5] = false; } } @@ -229,7 +229,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Left"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickLeft).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickLeft).ToString(), new Vector2(ContentWidth, 50))) { Toggles[6] = true; @@ -239,7 +239,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Right.StickLeft = (int)pressedKey; + KeyboardInputLayout.Right.StickLeft = (int)pressedKey; Toggles[6] = false; } } @@ -249,7 +249,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Right"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Right.StickRight).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickRight).ToString(), new Vector2(ContentWidth, 50))) { Toggles[7] = true; @@ -259,7 +259,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Right.StickRight = (int)pressedKey; + KeyboardInputLayout.Right.StickRight = (int)pressedKey; Toggles[7] = false; } } @@ -277,7 +277,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Up"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadUp).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Left.DPadUp).ToString(), new Vector2(ContentWidth, 50))) { Toggles[8] = true; @@ -287,7 +287,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Left.DPadUp = (int)pressedKey; + KeyboardInputLayout.Left.DPadUp = (int)pressedKey; Toggles[8] = false; } } @@ -297,7 +297,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Down"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadDown).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Left.DPadDown).ToString(), new Vector2(ContentWidth, 50))) { Toggles[9] = true; @@ -307,7 +307,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Left.DPadDown = (int)pressedKey; + KeyboardInputLayout.Left.DPadDown = (int)pressedKey; Toggles[9] = false; } } @@ -316,7 +316,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Left"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadLeft).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Left.DPadLeft).ToString(), new Vector2(ContentWidth, 50))) { Toggles[10] = true; @@ -326,7 +326,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Left.DPadLeft = (int)pressedKey; + KeyboardInputLayout.Left.DPadLeft = (int)pressedKey; Toggles[10] = false; } } @@ -336,7 +336,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Right"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Left.DPadRight).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Left.DPadRight).ToString(), new Vector2(ContentWidth, 50))) { Toggles[11] = true; @@ -346,7 +346,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Left.DPadRight = (int)pressedKey; + KeyboardInputLayout.Left.DPadRight = (int)pressedKey; Toggles[11] = false; } } @@ -364,7 +364,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("A"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonA).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonA).ToString(), new Vector2(ContentWidth, 50))) { Toggles[12] = true; @@ -374,7 +374,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Right.ButtonA = (int)pressedKey; + KeyboardInputLayout.Right.ButtonA = (int)pressedKey; Toggles[12] = false; } } @@ -384,7 +384,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("B"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonB).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonB).ToString(), new Vector2(ContentWidth, 50))) { Toggles[13] = true; @@ -394,7 +394,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Right.ButtonB = (int)pressedKey; + KeyboardInputLayout.Right.ButtonB = (int)pressedKey; Toggles[13] = false; } } @@ -403,7 +403,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("X"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonX).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonX).ToString(), new Vector2(ContentWidth, 50))) { Toggles[14] = true; @@ -413,7 +413,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Right.ButtonX = (int)pressedKey; + KeyboardInputLayout.Right.ButtonX = (int)pressedKey; Toggles[14] = false; } } @@ -423,7 +423,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("Y"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonY).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonY).ToString(), new Vector2(ContentWidth, 50))) { Toggles[15] = true; @@ -433,7 +433,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Right.ButtonY = (int)pressedKey; + KeyboardInputLayout.Right.ButtonY = (int)pressedKey; Toggles[15] = false; } } @@ -453,7 +453,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("L"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Left.ButtonL).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Left.ButtonL).ToString(), new Vector2(ContentWidth, 50))) { Toggles[17] = true; @@ -463,7 +463,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Left.ButtonL = (int)pressedKey; + KeyboardInputLayout.Left.ButtonL = (int)pressedKey; Toggles[17] = false; } } @@ -474,7 +474,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("R"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonR).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonR).ToString(), new Vector2(ContentWidth, 50))) { Toggles[16] = true; @@ -484,7 +484,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Right.ButtonR = (int)pressedKey; + KeyboardInputLayout.Right.ButtonR = (int)pressedKey; Toggles[16] = false; } } @@ -493,7 +493,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("ZL"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Left.ButtonZL).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Left.ButtonZL).ToString(), new Vector2(ContentWidth, 50))) { Toggles[19] = true; @@ -503,7 +503,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Left.ButtonZL = (int)pressedKey; + KeyboardInputLayout.Left.ButtonZL = (int)pressedKey; Toggles[19] = false; } } @@ -513,7 +513,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("ZR"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonZR).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonZR).ToString(), new Vector2(ContentWidth, 50))) { Toggles[18] = true; @@ -523,7 +523,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Right.ButtonZR = (int)pressedKey; + KeyboardInputLayout.Right.ButtonZR = (int)pressedKey; Toggles[18] = false; } } @@ -541,7 +541,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("-"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Left.ButtonMinus).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Left.ButtonMinus).ToString(), new Vector2(ContentWidth, 50))) { Toggles[20] = true; @@ -551,7 +551,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Left.ButtonMinus = (int)pressedKey; + KeyboardInputLayout.Left.ButtonMinus = (int)pressedKey; Toggles[20] = false; } } @@ -560,7 +560,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igBeginGroup(); ImGui.Text("+"); - if (ImGui.Button(((Key)CurrentJoyConLayout.Right.ButtonPlus).ToString(), + if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonPlus).ToString(), new Vector2(ContentWidth, 50))) { Toggles[21] = true; @@ -570,7 +570,7 @@ namespace Ryujinx.UI.Widgets { if (GetKey(ref pressedKey)) { - CurrentJoyConLayout.Right.ButtonPlus = (int)pressedKey; + KeyboardInputLayout.Right.ButtonPlus = (int)pressedKey; Toggles[21] = false; } } From 941bc58063351c8a97bd4e231f9fcf9a9008d73b Mon Sep 17 00:00:00 2001 From: emmaus Date: Sun, 8 Jul 2018 09:38:51 +0000 Subject: [PATCH 09/11] added input page --- Ryujinx.Common/Input/GamePadButton.cs | 28 + Ryujinx.Common/Input/JoyConController.cs | 36 +- Ryujinx.UI/Config.cs | 44 +- Ryujinx.UI/Extensions/ControlArchive.cs | 16 +- Ryujinx.UI/Extensions/DialogResult.cs | 6 +- Ryujinx.UI/Extensions/Nro.cs | 26 +- Ryujinx.UI/GUI/EmulationWindow.cs | 104 +- Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs | 33 +- Ryujinx.UI/GUI/Widgets/InputPage.cs | 1531 +++++++++++------ Ryujinx.UI/GUI/WindowHelper.cs | 57 + Ryujinx.UI/InputDevice.cs | 21 + Ryujinx.UI/RyujinxUI.conf | 85 +- Ryujinx/Config.cs | 36 +- Ryujinx/Ui/GLScreen.cs | 95 +- 14 files changed, 1413 insertions(+), 705 deletions(-) create mode 100644 Ryujinx.Common/Input/GamePadButton.cs create mode 100644 Ryujinx.UI/InputDevice.cs diff --git a/Ryujinx.Common/Input/GamePadButton.cs b/Ryujinx.Common/Input/GamePadButton.cs new file mode 100644 index 0000000000..5d78eb0de5 --- /dev/null +++ b/Ryujinx.Common/Input/GamePadButton.cs @@ -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 + } +} diff --git a/Ryujinx.Common/Input/JoyConController.cs b/Ryujinx.Common/Input/JoyConController.cs index b7754e6a09..a22a52d352 100644 --- a/Ryujinx.Common/Input/JoyConController.cs +++ b/Ryujinx.Common/Input/JoyConController.cs @@ -2,28 +2,28 @@ { 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 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 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 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 diff --git a/Ryujinx.UI/Config.cs b/Ryujinx.UI/Config.cs index 949541f5f5..66e2ff301f 100644 --- a/Ryujinx.UI/Config.cs +++ b/Ryujinx.UI/Config.cs @@ -15,10 +15,10 @@ namespace Ryujinx public static JoyConKeyboard JoyConKeyboard { get; set; } public static JoyConController JoyConController { get; set; } - public static float GamePadDeadzone { get; private set; } - public static bool GamePadEnable { get; private set; } - public static int GamePadIndex { get; private set; } - public static float GamePadTriggerThreshold { get; private 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; } @@ -112,28 +112,28 @@ namespace Ryujinx { Left = new JoyConControllerLeft { - Stick = Parser.GetValue("Controls_Left_JoyConController_Stick"), - StickButton = Parser.GetValue("Controls_Left_JoyConController_Stick_Button"), - DPadUp = Parser.GetValue("Controls_Left_JoyConController_DPad_Up"), - DPadDown = Parser.GetValue("Controls_Left_JoyConController_DPad_Down"), - DPadLeft = Parser.GetValue("Controls_Left_JoyConController_DPad_Left"), - DPadRight = Parser.GetValue("Controls_Left_JoyConController_DPad_Right"), - ButtonMinus = Parser.GetValue("Controls_Left_JoyConController_Button_Minus"), - ButtonL = Parser.GetValue("Controls_Left_JoyConController_Button_L"), - ButtonZL = Parser.GetValue("Controls_Left_JoyConController_Button_ZL") + Stick = Enum.Parse(Parser.GetValue("Controls_Left_JoyConController_Stick")), + StickButton = Enum.Parse(Parser.GetValue("Controls_Left_JoyConController_Stick_Button")), + DPadUp = Enum.Parse(Parser.GetValue("Controls_Left_JoyConController_DPad_Up")), + DPadDown = Enum.Parse(Parser.GetValue("Controls_Left_JoyConController_DPad_Down")), + DPadLeft = Enum.Parse(Parser.GetValue("Controls_Left_JoyConController_DPad_Left")), + DPadRight = Enum.Parse(Parser.GetValue("Controls_Left_JoyConController_DPad_Right")), + ButtonMinus = Enum.Parse(Parser.GetValue("Controls_Left_JoyConController_Button_Minus")), + ButtonL = Enum.Parse(Parser.GetValue("Controls_Left_JoyConController_Button_L")), + ButtonZL = Enum.Parse(Parser.GetValue("Controls_Left_JoyConController_Button_ZL")) }, Right = new JoyConControllerRight { - Stick = Parser.GetValue("Controls_Right_JoyConController_Stick"), - StickButton = Parser.GetValue("Controls_Right_JoyConController_Stick_Button"), - ButtonA = Parser.GetValue("Controls_Right_JoyConController_Button_A"), - ButtonB = Parser.GetValue("Controls_Right_JoyConController_Button_B"), - ButtonX = Parser.GetValue("Controls_Right_JoyConController_Button_X"), - ButtonY = Parser.GetValue("Controls_Right_JoyConController_Button_Y"), - ButtonPlus = Parser.GetValue("Controls_Right_JoyConController_Button_Plus"), - ButtonR = Parser.GetValue("Controls_Right_JoyConController_Button_R"), - ButtonZR = Parser.GetValue("Controls_Right_JoyConController_Button_ZR") + Stick = Enum.Parse(Parser.GetValue("Controls_Right_JoyConController_Stick")), + StickButton = Enum.Parse(Parser.GetValue("Controls_Right_JoyConController_Stick_Button")), + ButtonA = Enum.Parse(Parser.GetValue("Controls_Right_JoyConController_Button_A")), + ButtonB = Enum.Parse(Parser.GetValue("Controls_Right_JoyConController_Button_B")), + ButtonX = Enum.Parse(Parser.GetValue("Controls_Right_JoyConController_Button_X")), + ButtonY = Enum.Parse(Parser.GetValue("Controls_Right_JoyConController_Button_Y")), + ButtonPlus = Enum.Parse(Parser.GetValue("Controls_Right_JoyConController_Button_Plus")), + ButtonR = Enum.Parse(Parser.GetValue("Controls_Right_JoyConController_Button_R")), + ButtonZR = Enum.Parse(Parser.GetValue("Controls_Right_JoyConController_Button_ZR")) } }; diff --git a/Ryujinx.UI/Extensions/ControlArchive.cs b/Ryujinx.UI/Extensions/ControlArchive.cs index 4e7cbdec4a..e478383716 100644 --- a/Ryujinx.UI/Extensions/ControlArchive.cs +++ b/Ryujinx.UI/Extensions/ControlArchive.cs @@ -1,17 +1,15 @@ -using System; -using System.Collections.Generic; +using System.IO; using System.Text; -using System.IO; 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 long ApplicationTitleID { get; set; } + public long BaseTitleID { get; set; } + public long ProductCode { get; set; } + public string ApplicationVersion { get; set; } public ControlArchive(Stream Input) { @@ -22,7 +20,7 @@ namespace Ryujinx.UI Input.Seek(0x3060, SeekOrigin.Begin); ApplicationVersion = Encoding.ASCII.GetString(Reader.ReadBytes(0x10)); - BaseTitleID = Reader.ReadInt64(); + BaseTitleID = Reader.ReadInt64(); ApplicationTitleID = Reader.ReadInt64(); Input.Seek(0x30a8, SeekOrigin.Begin); @@ -38,7 +36,7 @@ namespace Ryujinx.UI LanguageEntries[index] = new LanguageEntry() { AplicationName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x200)).Trim('\0'), - DeveloperName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x100)).Trim('\0') + DeveloperName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x100)).Trim('\0') }; } } diff --git a/Ryujinx.UI/Extensions/DialogResult.cs b/Ryujinx.UI/Extensions/DialogResult.cs index 515cbb1a5a..17827c9f9f 100644 --- a/Ryujinx.UI/Extensions/DialogResult.cs +++ b/Ryujinx.UI/Extensions/DialogResult.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -public enum DialogResult +public enum DialogResult { OK, Cancel, diff --git a/Ryujinx.UI/Extensions/Nro.cs b/Ryujinx.UI/Extensions/Nro.cs index 167cc7e8ff..e37ce87d3f 100644 --- a/Ryujinx.UI/Extensions/Nro.cs +++ b/Ryujinx.UI/Extensions/Nro.cs @@ -1,17 +1,15 @@ using System; -using System.Collections.Generic; -using System.Text; using System.IO; -using Ryujinx.HLE.Loaders; +using System.Text; namespace Ryujinx.UI { class Nro : HLE.Loaders.Executables.Nro { - public byte[] AssetRomfData { get; set; } - public byte[] IconData { get; set; } - private byte[] NACPData { get; set; } - public int AssetOffset { get; set; } + public byte[] AssetRomfData { get; set; } + public byte[] IconData { get; set; } + private byte[] NACPData { get; set; } + public int AssetOffset { get; set; } public ControlArchive ControlArchive { get; set; } @@ -36,18 +34,18 @@ namespace Ryujinx.UI { Input.Seek(AssetOffset, SeekOrigin.Begin); - int AssetMagic0 = Reader.ReadInt32(); - int AssetFormat = Reader.ReadInt32(); - byte[] IconSectionInfo = Reader.ReadBytes(0x10); - byte[] NACPSectionInfo = Reader.ReadBytes(0x10); + 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 IconSize = BitConverter.ToInt64(IconSectionInfo, 8); long NACPOffset = BitConverter.ToInt64(NACPSectionInfo, 0); - long NACPSize = BitConverter.ToInt64(NACPSectionInfo, 8); + long NACPSize = BitConverter.ToInt64(NACPSectionInfo, 8); long RomfOffset = BitConverter.ToInt64(AssetRomfSectionInfo, 0); - long RomfSize = BitConverter.ToInt64(AssetRomfSectionInfo, 8); + long RomfSize = BitConverter.ToInt64(AssetRomfSectionInfo, 8); Input.Seek(AssetOffset + IconOffset, SeekOrigin.Begin); IconData = Reader.ReadBytes((int)IconSize); diff --git a/Ryujinx.UI/GUI/EmulationWindow.cs b/Ryujinx.UI/GUI/EmulationWindow.cs index 89bc47dcc0..5dc1f75b72 100644 --- a/Ryujinx.UI/GUI/EmulationWindow.cs +++ b/Ryujinx.UI/GUI/EmulationWindow.cs @@ -153,7 +153,7 @@ namespace Ryujinx.UI protected override void OnUpdateFrame(FrameEventArgs e) { - KeyboardState Keyboard = this.Keyboard.HasValue ? this.Keyboard.Value : new KeyboardState(); + KeyboardState Keyboard = this.Keyboard ?? new KeyboardState(); if (!UIActive) { @@ -181,42 +181,86 @@ namespace Ryujinx.UI HidJoystickPosition LeftJoystick; HidJoystickPosition RightJoystick; - int LeftJoystickDX = 0; - int LeftJoystickDY = 0; - int RightJoystickDX = 0; - int RightJoystickDY = 0; + int LeftJoystickDX = 0; + int LeftJoystickDY = 0; + int RightJoystickDX = 0; + int RightJoystickDY = 0; + float AnalogStickDeadzone = Config.GamePadDeadzone; - //RightJoystick - if (Keyboard[(Key)Config.FakeJoyCon.Left.StickUp]) LeftJoystickDY = short.MaxValue; - if (Keyboard[(Key)Config.FakeJoyCon.Left.StickDown]) LeftJoystickDY = -short.MaxValue; - if (Keyboard[(Key)Config.FakeJoyCon.Left.StickLeft]) LeftJoystickDX = -short.MaxValue; - if (Keyboard[(Key)Config.FakeJoyCon.Left.StickRight]) LeftJoystickDX = short.MaxValue; + //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.FakeJoyCon.Left.StickButton]) CurrentButton |= HidControllerButtons.KEY_LSTICK; - if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadUp]) CurrentButton |= HidControllerButtons.KEY_DUP; - if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadDown]) CurrentButton |= HidControllerButtons.KEY_DDOWN; - if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadLeft]) CurrentButton |= HidControllerButtons.KEY_DLEFT; - if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadRight]) CurrentButton |= HidControllerButtons.KEY_DRIGHT; - if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonMinus]) CurrentButton |= HidControllerButtons.KEY_MINUS; - if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonL]) CurrentButton |= HidControllerButtons.KEY_L; - if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonZL]) CurrentButton |= HidControllerButtons.KEY_ZL; + 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.FakeJoyCon.Right.StickUp]) RightJoystickDY = short.MaxValue; - if (Keyboard[(Key)Config.FakeJoyCon.Right.StickDown]) RightJoystickDY = -short.MaxValue; - if (Keyboard[(Key)Config.FakeJoyCon.Right.StickLeft]) RightJoystickDX = -short.MaxValue; - if (Keyboard[(Key)Config.FakeJoyCon.Right.StickRight]) RightJoystickDX = short.MaxValue; + 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.FakeJoyCon.Right.StickButton]) CurrentButton |= HidControllerButtons.KEY_RSTICK; - if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonA]) CurrentButton |= HidControllerButtons.KEY_A; - if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonB]) CurrentButton |= HidControllerButtons.KEY_B; - if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonX]) CurrentButton |= HidControllerButtons.KEY_X; - if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonY]) CurrentButton |= HidControllerButtons.KEY_Y; - if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonPlus]) CurrentButton |= HidControllerButtons.KEY_PLUS; - if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonR]) CurrentButton |= HidControllerButtons.KEY_R; - if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonZR]) CurrentButton |= HidControllerButtons.KEY_ZR; + 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 { diff --git a/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs b/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs index 7d116d7b55..4141728e68 100644 --- a/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs +++ b/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs @@ -9,12 +9,16 @@ namespace Ryujinx.UI.Widgets 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 Page CurrentPage = Page.General; static ConfigurationWidget() { @@ -23,11 +27,32 @@ namespace Ryujinx.UI.Widgets 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) { - KeyboardInputLayout = Config.JoyConKeyboard; + Reset(); + ConfigIntialized = true; } @@ -104,12 +129,14 @@ namespace Ryujinx.UI.Widgets { if (ImGui.Button("Apply", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { - Config.JoyConKeyboard = KeyboardInputLayout; + Apply(); } ImGui.SameLine(); } if (ImGui.Button("Save", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { + Apply(); + Config.Save(EmulationWindow.Ns.Log); } ImGui.SameLine(); diff --git a/Ryujinx.UI/GUI/Widgets/InputPage.cs b/Ryujinx.UI/GUI/Widgets/InputPage.cs index 24b33e9a1d..56eaf46871 100644 --- a/Ryujinx.UI/GUI/Widgets/InputPage.cs +++ b/Ryujinx.UI/GUI/Widgets/InputPage.cs @@ -1,8 +1,12 @@ using ImGuiNET; using OpenTK.Input; +using OpenTK.Platform; +using OpenTK.Platform.Windows; using System; +using System.Collections.Generic; using System.Linq; using System.Numerics; +using Ryujinx.Common.Input; namespace Ryujinx.UI.Widgets @@ -13,19 +17,978 @@ namespace Ryujinx.UI.Widgets static float ContentWidth; static Vector2 GroupSize; - static Key pressedKey; + static Key PressedKey; + static string PressedButton; + static string Axis; static bool RequestPopup; + static InputDevice CurrentSelectedDevice = default(InputDevice); + + static Dictionary ConnectedHIDs; + public static void DrawInputPage() { Vector2 AvailableSpace = ImGui.GetContentRegionAvailable(); + if (ConnectedHIDs == null) + RefreshDevices(); + + if (string.IsNullOrWhiteSpace(CurrentSelectedDevice.Name)) + CurrentSelectedDevice = ConnectedHIDs.First().Value; + + ImGui.Text("Connected Devices"); + + if (ImGui.BeginCombo(string.Empty, CurrentSelectedDevice.Name, + ComboFlags.HeightSmall)) + { + foreach(InputDevice Device in ConnectedHIDs.Values) + { + bool IsSelected = (CurrentSelectedDevice.Index == Device.Index); + if(ImGui.Selectable(Device.Name,IsSelected)) + { + CurrentSelectedDevice = Device; + } + } + + ImGui.EndCombo(); + } + + ImGui.SameLine(); + + if (ImGui.Button("Refresh")) + RefreshDevices(); + + if (CurrentSelectedDevice.DeviceType == DeviceType.GamePad) + { + ImGui.Checkbox("Enable GamePad", ref CurrentGamePadEnable); + + ImGuiNative.igBeginGroup(); + + ImGui.Text("Game Pad Deadzone"); + + ImGui.SliderFloat(string.Empty, ref CurrentGamePadDeadzone, 0, 1, CurrentGamePadDeadzone.ToString(), 1f); + + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + + ImGuiNative.igBeginGroup(); + + ImGui.Text("Game Pad Trigger Threshold"); + + ImGui.SliderFloat(string.Empty, ref CurrentGamePadTriggerThreshold, 0, 1, CurrentGamePadTriggerThreshold.ToString(), 1f); + + ImGuiNative.igEndGroup(); + } + GroupSize = new Vector2(AvailableSpace.X / 2, AvailableSpace.Y / 3); + if (CurrentSelectedDevice.DeviceType == DeviceType.Keyboard) + DrawKeyboardInputLayout(); + else + DrawControllerInputLayout(); + + if (Toggles.Contains(true)) + { + ImGui.OpenPopup("Enter Key"); + RequestPopup = true; + } + else + RequestPopup = false; + + if (ImGui.BeginPopupModal("Enter Key", WindowFlags.AlwaysAutoResize| + WindowFlags.NoMove + | WindowFlags.NoResize)) + { + ImGui.Text("Please enter a key"); + + if (!RequestPopup) + ImGui.CloseCurrentPopup(); + + ImGui.EndPopup(); + } + + if (ImGui.Button("Reset", new Vector2(ContentWidth, 50))) + { + Reset(); + } + + } + + static void DrawLeftAnalog() + { + // Show the Left Analog bindings + ImGui.Text("Left Analog"); + ImGuiNative.igBeginGroup(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); + + if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickUp).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[0] = true; + } + + if (Toggles[0]) + { + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Left.StickUp = (int)PressedKey; + Toggles[0] = false; + } + } + + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); + + if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickDown).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[1] = true; + } + + if (Toggles[1]) + { + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Left.StickDown = (int)PressedKey; + Toggles[1] = false; + } + } + + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); + + if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickLeft).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[2] = true; + } + + if (Toggles[2]) + { + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Left.StickLeft = (int)PressedKey; + Toggles[2] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); + + if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickRight).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[3] = true; + } + + if (Toggles[3]) + { + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Left.StickRight = (int)PressedKey; + Toggles[3] = false; + } + } + + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawRightAnalog() + { + //Show Right Analog Bindings + ImGui.Text("Right Analog"); + ImGuiNative.igBeginGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); + + if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickUp).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[4] = true; + } + + if (Toggles[4]) + { + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Right.StickUp = (int)PressedKey; + + Toggles[4] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); + + if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickDown).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[5] = true; + } + + if (Toggles[5]) + { + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Right.StickDown = (int)PressedKey; + Toggles[5] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); + + if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickLeft).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[6] = true; + } + + if (Toggles[6]) + { + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Right.StickLeft = (int)PressedKey; + Toggles[6] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); + + if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickRight).ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[7] = true; + } + + if (Toggles[7]) + { + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Right.StickRight = (int)PressedKey; + Toggles[7] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawControllerLeftAnalog() + { + // Show the Left Analog bindings + ImGui.Text("Left Analog"); + + ImGuiNative.igBeginGroup(); + ImGuiNative.igBeginGroup(); + + ImGui.Text("Stick"); + + if (ImGui.Button(ControllerInputLayout.Left.Stick.ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[0] = true; + } + + if (Toggles[0]) + { + if (GetAxis(ref Axis)) + { + ControllerInputLayout.Left.Stick = + (GamePadStick)Enum.Parse(typeof(GamePadStick), Axis); + Toggles[0] = false; + } + } + + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + + ImGuiNative.igBeginGroup(); + + ImGui.Text("Button"); + + if (ImGui.Button(ControllerInputLayout.Left.StickButton.ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[3] = true; + } + + if (Toggles[3]) + { + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Left.StickButton = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[3] = false; + } + } + + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawControllerRightAnalog() + { + //Show Right Analog Bindings + ImGui.Text("Right Analog"); + ImGuiNative.igBeginGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("Stick"); + + if (ImGui.Button(ControllerInputLayout.Right.Stick.ToString() + , new Vector2(ContentWidth, 50))) + { + Toggles[4] = true; + } + + if (Toggles[4]) + { + if (GetAxis(ref Axis)) + { + ControllerInputLayout.Right.Stick = + (GamePadStick)Enum.Parse(typeof(GamePadStick), Axis); + + Toggles[4] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Button"); + + if (ImGui.Button(ControllerInputLayout.Right.StickButton.ToString(), + new Vector2(ContentWidth, 50))) + { + Toggles[7] = true; + } + + if (Toggles[7]) + { + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Right.StickButton = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[7] = false; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawDpad() + { + string ButtonHeader = string.Empty; + + //Show DPad Bindings + ImGui.Text("D-Pad"); + ImGuiNative.igBeginGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Left.DPadUp).ToString() + : ControllerInputLayout.Left.DPadUp.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[8] = true; + } + + if (Toggles[8]) + { + switch(CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Left.DPadUp = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[8] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Left.DPadUp = (int)PressedKey; + Toggles[8] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Left.DPadDown).ToString() + : ControllerInputLayout.Left.DPadDown.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[9] = true; + } + + if (Toggles[9]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Left.DPadDown = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[9] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Left.DPadDown = (int)PressedKey; + Toggles[9] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Left.DPadLeft).ToString() + : ControllerInputLayout.Left.DPadLeft.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[10] = true; + } + + if (Toggles[10]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Left.DPadLeft = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[10] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Left.DPadLeft = (int)PressedKey; + Toggles[10] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Left.DPadRight).ToString() + : ControllerInputLayout.Left.DPadRight.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[11] = true; + } + + if (Toggles[11]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Left.DPadRight = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[11] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Left.DPadRight = (int)PressedKey; + Toggles[11] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawActionKeys() + { + string ButtonHeader = string.Empty; + //Show Action Key Bindings + ImGui.Text("Action Keys"); + ImGuiNative.igBeginGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("A"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Right.ButtonA).ToString() + : ControllerInputLayout.Right.ButtonA.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[12] = true; + } + + if (Toggles[12]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Right.ButtonA = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[12] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Right.ButtonA = (int)PressedKey; + Toggles[12] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("B"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Right.ButtonB).ToString() + : ControllerInputLayout.Right.ButtonB.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[13] = true; + } + + if (Toggles[13]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Right.ButtonB = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[13] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Right.ButtonB = (int)PressedKey; + Toggles[13] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("X"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Right.ButtonX).ToString() + : ControllerInputLayout.Right.ButtonX.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[14] = true; + } + + if (Toggles[14]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Right.ButtonX = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[14] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Right.ButtonX = (int)PressedKey; + Toggles[14] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Y"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Right.ButtonY).ToString() + : ControllerInputLayout.Right.ButtonY.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[15] = true; + } + + if (Toggles[15]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Right.ButtonY = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[15] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Right.ButtonY = (int)PressedKey; + Toggles[15] = false; + } + break; + } + } + + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawTriggers() + { + string ButtonHeader = string.Empty; + //Draw Triggers + ImGuiNative.igBeginGroup(); + + ImGui.Text("Triggers"); + + ImGuiNative.igBeginGroup(); + ImGui.Text("L"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Left.ButtonL).ToString() + : ControllerInputLayout.Left.ButtonL.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[17] = true; + } + + if (Toggles[17]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Left.ButtonL = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[17] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Left.ButtonL = (int)PressedKey; + Toggles[17] = false; + } + break; + } + } + + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("R"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Right.ButtonR).ToString() + : ControllerInputLayout.Right.ButtonR.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[16] = true; + } + + if (Toggles[16]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Right.ButtonR = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[16] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Right.ButtonR = (int)PressedKey; + Toggles[16] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("ZL"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Left.ButtonZL).ToString() + : ControllerInputLayout.Left.ButtonZL.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[19] = true; + } + + if (Toggles[19]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Left.ButtonZL = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[19] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Left.ButtonZL = (int)PressedKey; + Toggles[19] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("ZR"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Right.ButtonZR).ToString() + : ControllerInputLayout.Right.ButtonZR.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[18] = true; + } + + if (Toggles[18]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Right.ButtonZR = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[18] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Right.ButtonZR = (int)PressedKey; + Toggles[18] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static void DrawExtras() + { + string ButtonHeader = string.Empty; + + //Draw Extra + ImGuiNative.igBeginGroup(); + ImGui.Text("Extra Keys"); + + ImGuiNative.igBeginGroup(); + ImGui.Text("-"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Left.ButtonMinus).ToString() + : ControllerInputLayout.Left.ButtonMinus.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[20] = true; + } + + if (Toggles[20]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Left.ButtonMinus = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[20] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Left.ButtonMinus = (int)PressedKey; + Toggles[20] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igBeginGroup(); + ImGui.Text("+"); + + ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? + ((Key)KeyboardInputLayout.Right.ButtonPlus).ToString() + : ControllerInputLayout.Right.ButtonPlus.ToString(); + + if (ImGui.Button(ButtonHeader, new Vector2(ContentWidth, 50))) + { + Toggles[21] = true; + } + + if (Toggles[21]) + { + switch (CurrentSelectedDevice.DeviceType) + { + case DeviceType.GamePad: + if (GetButton(ref PressedButton)) + { + ControllerInputLayout.Right.ButtonPlus = + (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[21] = false; + } + break; + case DeviceType.Keyboard: + if (GetKey(ref PressedKey)) + { + KeyboardInputLayout.Right.ButtonPlus = (int)PressedKey; + Toggles[21] = false; + } + break; + } + } + ImGuiNative.igEndGroup(); + + ImGuiNative.igEndGroup(); + } + + static bool GetKey(ref Key PressedKey) + { + IO IO = ImGui.GetIO(); + foreach (Key Key in Enum.GetValues(typeof(Key))) + { + if (IO.KeysDown[(int)Key]) + { + PressedKey = Key; + return true; + } + } + return false; + } + + static bool GetButton(ref string PressedButton) + { + IO IO = ImGui.GetIO(); + GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex); + foreach (GamePadButton Button in Enum.GetValues(typeof(GamePadButton))) + { + if (WindowHelper.IsGamePadButtonPressed(GamePad, Button)) + { + PressedButton = Button.ToString(); + return true; + } + } + return false; + } + + static bool GetAxis(ref string Axis) + { + IO IO = ImGui.GetIO(); + GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex); + foreach (GamePadStick Stick in Enum.GetValues(typeof(GamePadStick))) + { + if (WindowHelper.GetJoystickAxis(GamePad,Stick).Length > 0) + { + Axis = Stick.ToString(); + return true; + } + } + return false; + } + + static void DrawKeyboardInputLayout() + { if (ImGui.BeginChildFrame(11, GroupSize, WindowFlags.AlwaysAutoResize)) { ContentWidth = (ImGui.GetContentRegionAvailableWidth() - 10) / 2; - GroupSize = ImGui.GetContentRegionMax(); + GroupSize = ImGui.GetContentRegionMax(); DrawLeftAnalog(); @@ -40,6 +1003,34 @@ namespace Ryujinx.UI.Widgets ImGui.EndChildFrame(); } + DrawMainLayout(); + } + + static void DrawControllerInputLayout() + { + if (ImGui.BeginChildFrame(11, GroupSize, WindowFlags.AlwaysAutoResize)) + { + ContentWidth = (ImGui.GetContentRegionAvailableWidth() - 10) / 2; + GroupSize = ImGui.GetContentRegionMax(); + + DrawControllerLeftAnalog(); + + ImGui.EndChildFrame(); + } + + ImGui.SameLine(); + if (ImGui.BeginChildFrame(12, GroupSize, WindowFlags.AlwaysAutoResize)) + { + DrawControllerRightAnalog(); + + ImGui.EndChildFrame(); + } + + DrawMainLayout(); + } + + static void DrawMainLayout() + { if (ImGui.BeginChildFrame(13, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawDpad(); @@ -69,528 +1060,40 @@ namespace Ryujinx.UI.Widgets ImGui.EndChildFrame(); } - - if (Toggles.Contains(true)) - { - ImGui.OpenPopup("Enter Key"); - RequestPopup = true; - } - else - RequestPopup = false; - - if (ImGui.BeginPopupModal("Enter Key", WindowFlags.AlwaysAutoResize| WindowFlags.NoMove - | WindowFlags.NoResize)) - { - ImGui.Text("Please enter a key"); - - if (!RequestPopup) - ImGui.CloseCurrentPopup(); - - ImGui.EndPopup(); - } } - - static void DrawLeftAnalog() + static void RefreshDevices() { - // Show the Left Analog bindings - ImGui.Text("Left Analog"); - ImGuiNative.igBeginGroup(); - ImGuiNative.igBeginGroup(); - ImGui.Text("Up"); + ConnectedHIDs = new Dictionary(); - if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickUp).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[0] = true; - } + int GamePadIndex = 0; - if (Toggles[0]) - { - if (GetKey(ref pressedKey)) + InputDevice KeyboardInputDevice = new InputDevice() { - KeyboardInputLayout.Left.StickUp = (int)pressedKey; - Toggles[0] = false; - } - } - - ImGuiNative.igEndGroup(); - - ImGui.SameLine(); - ImGuiNative.igBeginGroup(); - ImGui.Text("Down"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickDown).ToString(), - new Vector2(ContentWidth, 50))) + Index = short.MaxValue, + DeviceType = DeviceType.Keyboard, + Name = "Keyboard" + }; + ConnectedHIDs.Add(short.MaxValue, KeyboardInputDevice); + + // Scans for connected joysticks + while (true) { - Toggles[1] = true; - } - - if (Toggles[1]) - { - if (GetKey(ref pressedKey)) + JoystickState GamePad = Joystick.GetState(GamePadIndex); + if (GamePad.IsConnected) { - KeyboardInputLayout.Left.StickDown = (int)pressedKey; - Toggles[1] = false; + InputDevice GamePadDevice = new InputDevice() + { + Index = GamePadIndex, + DeviceType = DeviceType.GamePad, + Name = "GamePad " + GamePadIndex + }; + ConnectedHIDs.Add(GamePadIndex, GamePadDevice); } + else + break; + GamePadIndex++; } - - ImGuiNative.igEndGroup(); - - ImGuiNative.igBeginGroup(); - ImGui.Text("Left"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickLeft).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[2] = true; - } - - if (Toggles[2]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Left.StickLeft = (int)pressedKey; - Toggles[2] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGui.SameLine(); - ImGuiNative.igBeginGroup(); - ImGui.Text("Right"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickRight).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[3] = true; - } - - if (Toggles[3]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Left.StickRight = (int)pressedKey; - Toggles[3] = false; - } - } - - ImGuiNative.igEndGroup(); - - ImGuiNative.igEndGroup(); - } - - static void DrawRightAnalog() - { - //Show Right Analog Bindings - ImGui.Text("Right Analog"); - ImGuiNative.igBeginGroup(); - - ImGuiNative.igBeginGroup(); - ImGui.Text("Up"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickUp).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[4] = true; - } - - if (Toggles[4]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Right.StickUp = (int)pressedKey; - - Toggles[4] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGui.SameLine(); - ImGuiNative.igBeginGroup(); - ImGui.Text("Down"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickDown).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[5] = true; - } - - if (Toggles[5]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Right.StickDown = (int)pressedKey; - Toggles[5] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGuiNative.igBeginGroup(); - ImGui.Text("Left"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickLeft).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[6] = true; - } - - if (Toggles[6]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Right.StickLeft = (int)pressedKey; - Toggles[6] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGui.SameLine(); - ImGuiNative.igBeginGroup(); - ImGui.Text("Right"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickRight).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[7] = true; - } - - if (Toggles[7]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Right.StickRight = (int)pressedKey; - Toggles[7] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGuiNative.igEndGroup(); - } - - static void DrawDpad() - { - //Show DPad Bindings - ImGui.Text("D-Pad"); - ImGuiNative.igBeginGroup(); - - ImGuiNative.igBeginGroup(); - ImGui.Text("Up"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Left.DPadUp).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[8] = true; - } - - if (Toggles[8]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Left.DPadUp = (int)pressedKey; - Toggles[8] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGui.SameLine(); - ImGuiNative.igBeginGroup(); - ImGui.Text("Down"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Left.DPadDown).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[9] = true; - } - - if (Toggles[9]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Left.DPadDown = (int)pressedKey; - Toggles[9] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGuiNative.igBeginGroup(); - ImGui.Text("Left"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Left.DPadLeft).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[10] = true; - } - - if (Toggles[10]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Left.DPadLeft = (int)pressedKey; - Toggles[10] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGui.SameLine(); - ImGuiNative.igBeginGroup(); - ImGui.Text("Right"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Left.DPadRight).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[11] = true; - } - - if (Toggles[11]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Left.DPadRight = (int)pressedKey; - Toggles[11] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGuiNative.igEndGroup(); - } - - static void DrawActionKeys() - { - //Show Action Key Bindings - ImGui.Text("Action Keys"); - ImGuiNative.igBeginGroup(); - - ImGuiNative.igBeginGroup(); - ImGui.Text("A"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonA).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[12] = true; - } - - if (Toggles[12]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Right.ButtonA = (int)pressedKey; - Toggles[12] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGui.SameLine(); - ImGuiNative.igBeginGroup(); - ImGui.Text("B"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonB).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[13] = true; - } - - if (Toggles[13]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Right.ButtonB = (int)pressedKey; - Toggles[13] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGuiNative.igBeginGroup(); - ImGui.Text("X"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonX).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[14] = true; - } - - if (Toggles[14]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Right.ButtonX = (int)pressedKey; - Toggles[14] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGui.SameLine(); - ImGuiNative.igBeginGroup(); - ImGui.Text("Y"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonY).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[15] = true; - } - - if (Toggles[15]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Right.ButtonY = (int)pressedKey; - Toggles[15] = false; - } - } - - ImGuiNative.igEndGroup(); - - ImGuiNative.igEndGroup(); - } - - static void DrawTriggers() - { - //Draw Triggers - ImGuiNative.igBeginGroup(); - - ImGui.Text("Triggers"); - - ImGuiNative.igBeginGroup(); - ImGui.Text("L"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Left.ButtonL).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[17] = true; - } - - if (Toggles[17]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Left.ButtonL = (int)pressedKey; - Toggles[17] = false; - } - } - - ImGuiNative.igEndGroup(); - - ImGui.SameLine(); - ImGuiNative.igBeginGroup(); - ImGui.Text("R"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonR).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[16] = true; - } - - if (Toggles[16]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Right.ButtonR = (int)pressedKey; - Toggles[16] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGuiNative.igBeginGroup(); - ImGui.Text("ZL"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Left.ButtonZL).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[19] = true; - } - - if (Toggles[19]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Left.ButtonZL = (int)pressedKey; - Toggles[19] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGui.SameLine(); - ImGuiNative.igBeginGroup(); - ImGui.Text("ZR"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonZR).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[18] = true; - } - - if (Toggles[18]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Right.ButtonZR = (int)pressedKey; - Toggles[18] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGuiNative.igEndGroup(); - } - - static void DrawExtras() - { - //Draw Extra - ImGuiNative.igBeginGroup(); - ImGui.Text("Extra Keys"); - - ImGuiNative.igBeginGroup(); - ImGui.Text("-"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Left.ButtonMinus).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[20] = true; - } - - if (Toggles[20]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Left.ButtonMinus = (int)pressedKey; - Toggles[20] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGuiNative.igBeginGroup(); - ImGui.Text("+"); - - if (ImGui.Button(((Key)KeyboardInputLayout.Right.ButtonPlus).ToString(), - new Vector2(ContentWidth, 50))) - { - Toggles[21] = true; - } - - if (Toggles[21]) - { - if (GetKey(ref pressedKey)) - { - KeyboardInputLayout.Right.ButtonPlus = (int)pressedKey; - Toggles[21] = false; - } - } - ImGuiNative.igEndGroup(); - - ImGuiNative.igEndGroup(); - } - - static bool GetKey(ref Key pressedKey) - { - IO IO = ImGui.GetIO(); - foreach (Key Key in Enum.GetValues(typeof(Key))) - { - if (IO.KeysDown[(int)Key]) - { - pressedKey = Key; - return true; - } - } - return false; } } } \ No newline at end of file diff --git a/Ryujinx.UI/GUI/WindowHelper.cs b/Ryujinx.UI/GUI/WindowHelper.cs index ca93d2782c..b803f47c0b 100644 --- a/Ryujinx.UI/GUI/WindowHelper.cs +++ b/Ryujinx.UI/GUI/WindowHelper.cs @@ -4,6 +4,7 @@ using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; using OpenTK.Input; using System; +using Ryujinx.Common.Input; namespace Ryujinx.UI { @@ -22,6 +23,8 @@ namespace Ryujinx.UI 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) { @@ -261,6 +264,60 @@ namespace Ryujinx.UI 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; diff --git a/Ryujinx.UI/InputDevice.cs b/Ryujinx.UI/InputDevice.cs new file mode 100644 index 0000000000..013f51b1ef --- /dev/null +++ b/Ryujinx.UI/InputDevice.cs @@ -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 IInputDevice Device; + public DeviceType DeviceType; + public string Name; + } + + public enum DeviceType + { + GamePad, + Keyboard + } +} diff --git a/Ryujinx.UI/RyujinxUI.conf b/Ryujinx.UI/RyujinxUI.conf index 611f320717..59f7f859e7 100644 --- a/Ryujinx.UI/RyujinxUI.conf +++ b/Ryujinx.UI/RyujinxUI.conf @@ -19,29 +19,64 @@ Logging_Enable_Error = true #Filtered log classes, seperated by ", ", eg. `Logging_Filtered_Classes = Loader, ServiceFS` Logging_Filtered_Classes = -#https://github.com/opentk/opentk/blob/develop/src/OpenTK/Input/Key.cs -Controls_Left_FakeJoycon_Stick_Up = 105 -Controls_Left_FakeJoycon_Stick_Down = 101 -Controls_Left_FakeJoycon_Stick_Left = 83 -Controls_Left_FakeJoycon_Stick_Right = 86 -Controls_Left_FakeJoycon_Stick_Button = 88 -Controls_Left_FakeJoycon_DPad_Up = 45 -Controls_Left_FakeJoycon_DPad_Down = 46 -Controls_Left_FakeJoycon_DPad_Left = 47 -Controls_Left_FakeJoycon_DPad_Right = 48 -Controls_Left_FakeJoycon_Button_Minus = 120 -Controls_Left_FakeJoycon_Button_L = 87 -Controls_Left_FakeJoycon_Button_ZL = 99 +#Controller Device Index +GamePad_Index = 0 -Controls_Right_FakeJoycon_Stick_Up = 91 -Controls_Right_FakeJoycon_Stick_Down = 93 -Controls_Right_FakeJoycon_Stick_Left = 92 -Controls_Right_FakeJoycon_Stick_Right = 94 -Controls_Right_FakeJoycon_Stick_Button = 90 -Controls_Right_FakeJoycon_Button_A = 108 -Controls_Right_FakeJoycon_Button_B = 106 -Controls_Right_FakeJoycon_Button_X = 85 -Controls_Right_FakeJoycon_Button_Y = 104 -Controls_Right_FakeJoycon_Button_Plus = 121 -Controls_Right_FakeJoycon_Button_R = 103 -Controls_Right_FakeJoycon_Button_ZR = 97 \ No newline at end of file +#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 \ No newline at end of file diff --git a/Ryujinx/Config.cs b/Ryujinx/Config.cs index 7a78d6c6f6..7c890bfd9f 100644 --- a/Ryujinx/Config.cs +++ b/Ryujinx/Config.cs @@ -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(Parser.Value("Controls_Left_JoyConController_Stick")), + StickButton = Enum.Parse(Parser.Value("Controls_Left_JoyConController_Stick_Button")), + DPadUp = Enum.Parse(Parser.Value("Controls_Left_JoyConController_DPad_Up")), + DPadDown = Enum.Parse(Parser.Value("Controls_Left_JoyConController_DPad_Down")), + DPadLeft = Enum.Parse(Parser.Value("Controls_Left_JoyConController_DPad_Left")), + DPadRight = Enum.Parse(Parser.Value("Controls_Left_JoyConController_DPad_Right")), + ButtonMinus = Enum.Parse(Parser.Value("Controls_Left_JoyConController_Button_Minus")), + ButtonL = Enum.Parse(Parser.Value("Controls_Left_JoyConController_Button_L")), + ButtonZL = Enum.Parse(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(Parser.Value("Controls_Right_JoyConController_Stick")), + StickButton = Enum.Parse(Parser.Value("Controls_Right_JoyConController_Stick_Button")), + ButtonA = Enum.Parse(Parser.Value("Controls_Right_JoyConController_Button_A")), + ButtonB = Enum.Parse(Parser.Value("Controls_Right_JoyConController_Button_B")), + ButtonX = Enum.Parse(Parser.Value("Controls_Right_JoyConController_Button_X")), + ButtonY = Enum.Parse(Parser.Value("Controls_Right_JoyConController_Button_Y")), + ButtonPlus = Enum.Parse(Parser.Value("Controls_Right_JoyConController_Button_Plus")), + ButtonR = Enum.Parse(Parser.Value("Controls_Right_JoyConController_Button_R")), + ButtonZR = Enum.Parse(Parser.Value("Controls_Right_JoyConController_Button_ZR")) } }; } diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index 9b5dda4f0c..e7a74bbe8a 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -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 From 2084c9356961f5ffcff5c7ace553e735469cec76 Mon Sep 17 00:00:00 2001 From: emmaus Date: Sun, 15 Jul 2018 16:53:28 +0000 Subject: [PATCH 10/11] cleanup, changed rendering style --- Ryujinx.UI/Extensions/ControlArchive.cs | 17 +- Ryujinx.UI/Extensions/Nro.cs | 24 +-- .../{Extensions => GUI}/DialogResult.cs | 0 Ryujinx.UI/GUI/EmulationWindow.cs | 152 +++++++++++++++--- Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs | 12 ++ Ryujinx.UI/GUI/Widgets/FilePicker.cs | 14 +- Ryujinx.UI/GUI/Widgets/GameList.cs | 29 ++-- Ryujinx.UI/GUI/Widgets/HomeUI.cs | 11 ++ Ryujinx.UI/GUI/Widgets/InputPage.cs | 127 ++++++++++++++- Ryujinx.UI/GUI/Widgets/PauseUI.cs | 10 +- Ryujinx.UI/GUI/WindowHelper.cs | 88 +++++++--- Ryujinx.UI/InputDevice.cs | 6 +- Ryujinx.UI/Program.cs | 4 +- 13 files changed, 403 insertions(+), 91 deletions(-) rename Ryujinx.UI/{Extensions => GUI}/DialogResult.cs (100%) diff --git a/Ryujinx.UI/Extensions/ControlArchive.cs b/Ryujinx.UI/Extensions/ControlArchive.cs index e478383716..07e988daf0 100644 --- a/Ryujinx.UI/Extensions/ControlArchive.cs +++ b/Ryujinx.UI/Extensions/ControlArchive.cs @@ -6,9 +6,10 @@ 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 long ApplicationTitleID { get; set; } + public long BaseTitleID { get; set; } + public long ProductCode { get; set; } public string ApplicationVersion { get; set; } public ControlArchive(Stream Input) @@ -20,10 +21,11 @@ namespace Ryujinx.UI Input.Seek(0x3060, SeekOrigin.Begin); ApplicationVersion = Encoding.ASCII.GetString(Reader.ReadBytes(0x10)); - BaseTitleID = Reader.ReadInt64(); + BaseTitleID = Reader.ReadInt64(); ApplicationTitleID = Reader.ReadInt64(); Input.Seek(0x30a8, SeekOrigin.Begin); + ProductCode = Reader.ReadInt64(); LanguageEntries = new LanguageEntry[16]; @@ -31,12 +33,13 @@ namespace Ryujinx.UI using (MemoryStream LanguageStream = new MemoryStream(LanguageEntryData)) { BinaryReader LanguageReader = new BinaryReader(LanguageStream); - for (int index = 0; index < 16; index++) + + for (int Index = 0; Index < 16; Index++) { - LanguageEntries[index] = new LanguageEntry() + LanguageEntries[Index] = new LanguageEntry() { AplicationName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x200)).Trim('\0'), - DeveloperName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x100)).Trim('\0') + DeveloperName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x100)).Trim('\0') }; } } diff --git a/Ryujinx.UI/Extensions/Nro.cs b/Ryujinx.UI/Extensions/Nro.cs index e37ce87d3f..7bedc3e9ee 100644 --- a/Ryujinx.UI/Extensions/Nro.cs +++ b/Ryujinx.UI/Extensions/Nro.cs @@ -7,12 +7,13 @@ namespace Ryujinx.UI class Nro : HLE.Loaders.Executables.Nro { public byte[] AssetRomfData { get; set; } - public byte[] IconData { get; set; } - private byte[] NACPData { get; set; } - public int AssetOffset { 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); @@ -34,26 +35,29 @@ namespace Ryujinx.UI { Input.Seek(AssetOffset, SeekOrigin.Begin); - int AssetMagic0 = Reader.ReadInt32(); - int AssetFormat = Reader.ReadInt32(); - byte[] IconSectionInfo = Reader.ReadBytes(0x10); - byte[] NACPSectionInfo = Reader.ReadBytes(0x10); + 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 IconSize = BitConverter.ToInt64(IconSectionInfo, 8); long NACPOffset = BitConverter.ToInt64(NACPSectionInfo, 0); - long NACPSize = BitConverter.ToInt64(NACPSectionInfo, 8); + long NACPSize = BitConverter.ToInt64(NACPSectionInfo, 8); long RomfOffset = BitConverter.ToInt64(AssetRomfSectionInfo, 0); - long RomfSize = BitConverter.ToInt64(AssetRomfSectionInfo, 8); + 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); } } diff --git a/Ryujinx.UI/Extensions/DialogResult.cs b/Ryujinx.UI/GUI/DialogResult.cs similarity index 100% rename from Ryujinx.UI/Extensions/DialogResult.cs rename to Ryujinx.UI/GUI/DialogResult.cs diff --git a/Ryujinx.UI/GUI/EmulationWindow.cs b/Ryujinx.UI/GUI/EmulationWindow.cs index 5dc1f75b72..7582757e8a 100644 --- a/Ryujinx.UI/GUI/EmulationWindow.cs +++ b/Ryujinx.UI/GUI/EmulationWindow.cs @@ -9,15 +9,17 @@ 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 showMainUI = true; - private bool showPauseUI; + + //toggles private bool isRunning = false; private bool IsRunning { @@ -29,6 +31,7 @@ namespace Ryujinx.UI } } + private bool showMainUI = true; private bool ShowMainUI { get => showMainUI; @@ -45,6 +48,7 @@ namespace Ryujinx.UI } } + private bool showPauseUI; private bool ShowPauseUI { get => showPauseUI; @@ -63,10 +67,9 @@ namespace Ryujinx.UI private Page CurrentPage = Page.GameList; - private bool EscapePressed; - - private string CurrentPath = Environment.CurrentDirectory; - private string PackagePath = string.Empty; + private bool EscapePressed; + private string CurrentPath; + private string PackagePath; private const int TouchScreenWidth = 1280; private const int TouchScreenHeight = 720; @@ -74,17 +77,33 @@ namespace Ryujinx.UI 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") { - FileDialog = FilePicker.GetFilePicker("rom",null); + CurrentPath = Environment.CurrentDirectory; + PackagePath = string.Empty; + FileDialog = FilePicker.GetFilePicker("rom",null); InitializeSwitch(); + + ResizeEvent = false; + + TitleEvent = false; } protected override void OnLoad(EventArgs e) @@ -94,10 +113,87 @@ namespace Ryujinx.UI VSync = VSyncMode.On; } - protected override void OnRenderFrame(FrameEventArgs e) + private void RenderLoop() { - DeltaTime = (float)e.Time; + 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(); @@ -107,11 +203,13 @@ namespace Ryujinx.UI if (ShowMainUI) { showPauseUI = false; + RenderMainUI(); } else if (ShowPauseUI) { showMainUI = false; + RenderPauseUI(); } @@ -126,7 +224,9 @@ namespace Ryujinx.UI double HostFps = Ns.Statistics.GetSystemFrameRate(); double GameFps = Ns.Statistics.GetGameFrameRate(); - Title = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}"; + NewTitle = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}"; + + TitleEvent = true; SwapBuffers(); @@ -151,7 +251,7 @@ namespace Ryujinx.UI Ns.Log.Updated += ConsoleLog.PrintLog; } - protected override void OnUpdateFrame(FrameEventArgs e) + private new void UpdateFrame() { KeyboardState Keyboard = this.Keyboard ?? new KeyboardState(); @@ -178,8 +278,8 @@ namespace Ryujinx.UI EscapePressed = false; HidControllerButtons CurrentButton = 0; - HidJoystickPosition LeftJoystick; - HidJoystickPosition RightJoystick; + HidJoystickPosition LeftJoystick; + HidJoystickPosition RightJoystick; int LeftJoystickDX = 0; int LeftJoystickDY = 0; @@ -282,7 +382,7 @@ namespace Ryujinx.UI { MouseState Mouse = this.Mouse.Value; - int ScrnWidth = Width; + int ScrnWidth = Width; int ScrnHeight = Height; if (Width > Height * TouchScreenRatioX) @@ -319,7 +419,7 @@ namespace Ryujinx.UI //Placeholder values till more data is acquired DiameterX = 10, DiameterY = 10, - Angle = 90 + Angle = 90 }; HasTouch = true; @@ -346,10 +446,6 @@ namespace Ryujinx.UI CurrentButton, LeftJoystick, RightJoystick); - - Ns.ProcessFrame(); - - Renderer.RunActions(); } else if (EmulationController != null) if (EmulationController.IsLoaded) @@ -373,13 +469,25 @@ namespace Ryujinx.UI } } + 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 (Ns == null) + InitializeSwitch(); if (EmulationController == null) EmulationController = new EmulationController(Ns); diff --git a/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs b/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs index 4141728e68..9a7a657cb1 100644 --- a/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs +++ b/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs @@ -67,6 +67,7 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + if (ImGui.Button("Input", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { CurrentPage = Page.Input; @@ -90,6 +91,7 @@ namespace Ryujinx.UI.Widgets { OpenFolderPicker = true; } + if (OpenFolderPicker) ImGui.OpenPopup("Open Folder"); @@ -101,22 +103,28 @@ namespace Ryujinx.UI.Widgets 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; } @@ -131,15 +139,19 @@ namespace Ryujinx.UI.Widgets { 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); diff --git a/Ryujinx.UI/GUI/Widgets/FilePicker.cs b/Ryujinx.UI/GUI/Widgets/FilePicker.cs index 0eeac2ad7c..77ab3fa66e 100644 --- a/Ryujinx.UI/GUI/Widgets/FilePicker.cs +++ b/Ryujinx.UI/GUI/Widgets/FilePicker.cs @@ -10,7 +10,9 @@ namespace ImGuiNET public class FilePicker { private const string FilePickerID = "###FilePicker"; + private static readonly Dictionary FilePickers = new Dictionary(); + private static readonly Vector2 DefaultFilePickerSize = new Vector2(600, 400); public string CurrentFolder { get; set; } @@ -26,6 +28,7 @@ namespace ImGuiNET else if (string.IsNullOrEmpty(StartingPath) || !Directory.Exists(StartingPath)) { StartingPath = Environment.CurrentDirectory; + if (string.IsNullOrEmpty(StartingPath)) { StartingPath = AppContext.BaseDirectory; @@ -68,9 +71,10 @@ namespace ImGuiNET if (ImGui.Selectable(Drive.Name + "/", IsSelected, SelectableFlags.DontClosePopups , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) { - CurrentDrive = Drive.Name; + CurrentDrive = Drive.Name; CurrentFolder = Drive.Name; } + ImGui.PopStyleColor(); } @@ -128,8 +132,8 @@ namespace ImGuiNET if (!FoldersOnly) foreach (string File in Directory.EnumerateFiles(CurrentDirectory.FullName)) { - string Name = Path.GetFileName(File); - bool IsSelected = SelectedEntry == File; + string Name = Path.GetFileName(File); + bool IsSelected = SelectedEntry == File; if (ImGui.Selectable(Name, IsSelected, SelectableFlags.DontClosePopups , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) @@ -149,8 +153,8 @@ namespace ImGuiNET } } } - ImGui.EndChildFrame(); + ImGui.EndChildFrame(); if (ImGui.Button("Cancel", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { @@ -180,11 +184,13 @@ namespace ImGuiNET 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) diff --git a/Ryujinx.UI/GUI/Widgets/GameList.cs b/Ryujinx.UI/GUI/Widgets/GameList.cs index 59746f1f3f..38ae21bd3c 100644 --- a/Ryujinx.UI/GUI/Widgets/GameList.cs +++ b/Ryujinx.UI/GUI/Widgets/GameList.cs @@ -47,11 +47,15 @@ namespace Ryujinx.UI.Widgets GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); - NanoJpeg.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(); + 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); } @@ -63,12 +67,13 @@ namespace Ryujinx.UI.Widgets public unsafe static (bool,string) DrawList() { - uint id = 100; + uint Id = 100; if (ImGui.Button("Refresh GameList")) Refresh(Config.DefaultGameDirectory); ImGui.SameLine(); + if(ImGui.Button("Select Game Directory")) { OpenFolderPicker = true; @@ -78,6 +83,7 @@ namespace Ryujinx.UI.Widgets ImGui.OpenPopup("Open Folder"); DialogResult DialogResult = FolderPicker.GetFolder(ref GameDirectory); + if (DialogResult == DialogResult.OK) { Config.DefaultGameDirectory = GameDirectory; @@ -91,12 +97,12 @@ namespace Ryujinx.UI.Widgets { foreach (GameItem GameItem in GameItems) { - id++; + Id++; if (GameItem == SelectedGame) ImGui.PushStyleColor(ColorTarget.FrameBg, Values.Color.Yellow); - if (ImGui.BeginChildFrame(id, new Vector2(ImGui.GetContentRegionAvailableWidth(), 60) + if (ImGui.BeginChildFrame(Id, new Vector2(ImGui.GetContentRegionAvailableWidth(), 60) , WindowFlags.AlwaysAutoResize)) { if (GameItem.IsNro && GameItem.HasIcon) @@ -106,7 +112,7 @@ namespace Ryujinx.UI.Widgets } else { - ImGui.BeginChildFrame(id + 500, new Vector2(50, 50), WindowFlags.NoResize); + ImGui.BeginChildFrame(Id + 500, new Vector2(50, 50), WindowFlags.NoResize); ImGui.EndChildFrame(); ImGui.SameLine(); ImGui.Text(Path.GetFileName(GameItem.Path)); @@ -114,7 +120,9 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + if (GameItem.IsNro) { if (GameItem.Nro.ControlArchive != null) @@ -124,6 +132,7 @@ namespace Ryujinx.UI.Widgets } } + ImGuiNative.igEndGroup(); if (GameItem == SelectedGame) @@ -166,7 +175,9 @@ namespace Ryujinx.UI.Widgets 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); diff --git a/Ryujinx.UI/GUI/Widgets/HomeUI.cs b/Ryujinx.UI/GUI/Widgets/HomeUI.cs index 188306e0bf..4cde8154a9 100644 --- a/Ryujinx.UI/GUI/Widgets/HomeUI.cs +++ b/Ryujinx.UI/GUI/Widgets/HomeUI.cs @@ -10,7 +10,9 @@ namespace Ryujinx.UI { 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)) { @@ -42,6 +44,7 @@ namespace Ryujinx.UI ImGuiNative.igEndGroup(); ImGui.SameLine(); + if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable(), WindowFlags.AlwaysAutoResize)) { @@ -49,30 +52,38 @@ namespace Ryujinx.UI { 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(); } } diff --git a/Ryujinx.UI/GUI/Widgets/InputPage.cs b/Ryujinx.UI/GUI/Widgets/InputPage.cs index 56eaf46871..230eef50ab 100644 --- a/Ryujinx.UI/GUI/Widgets/InputPage.cs +++ b/Ryujinx.UI/GUI/Widgets/InputPage.cs @@ -68,7 +68,7 @@ namespace Ryujinx.UI.Widgets ImGui.SliderFloat(string.Empty, ref CurrentGamePadDeadzone, 0, 1, CurrentGamePadDeadzone.ToString(), 1f); - ImGuiNative.igEndGroup(); + ImGuiNative.igEndGroup(); ImGui.SameLine(); @@ -119,8 +119,10 @@ namespace Ryujinx.UI.Widgets { // Show the Left Analog bindings ImGui.Text("Left Analog"); + ImGuiNative.igBeginGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickUp).ToString(), @@ -134,6 +136,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.StickUp = (int)PressedKey; + Toggles[0] = false; } } @@ -141,7 +144,9 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickDown).ToString(), @@ -155,6 +160,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.StickDown = (int)PressedKey; + Toggles[1] = false; } } @@ -162,6 +168,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickLeft).ToString(), @@ -175,13 +182,17 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.StickLeft = (int)PressedKey; + Toggles[2] = false; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickRight).ToString(), @@ -195,6 +206,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.StickRight = (int)PressedKey; + Toggles[3] = false; } } @@ -208,9 +220,11 @@ namespace Ryujinx.UI.Widgets { //Show Right Analog Bindings ImGui.Text("Right Analog"); + ImGuiNative.igBeginGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickUp).ToString(), @@ -231,7 +245,9 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickDown).ToString(), @@ -245,12 +261,15 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.StickDown = (int)PressedKey; + Toggles[5] = false; } } + ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickLeft).ToString(), @@ -264,13 +283,16 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.StickLeft = (int)PressedKey; + Toggles[6] = false; } } ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickRight).ToString(), @@ -284,6 +306,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.StickRight = (int)PressedKey; + Toggles[7] = false; } } @@ -298,6 +321,7 @@ namespace Ryujinx.UI.Widgets ImGui.Text("Left Analog"); ImGuiNative.igBeginGroup(); + ImGuiNative.igBeginGroup(); ImGui.Text("Stick"); @@ -314,6 +338,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.Stick = (GamePadStick)Enum.Parse(typeof(GamePadStick), Axis); + Toggles[0] = false; } } @@ -338,6 +363,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.StickButton = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[3] = false; } } @@ -351,9 +377,11 @@ namespace Ryujinx.UI.Widgets { //Show Right Analog Bindings ImGui.Text("Right Analog"); + ImGuiNative.igBeginGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Stick"); if (ImGui.Button(ControllerInputLayout.Right.Stick.ToString() @@ -372,10 +400,13 @@ namespace Ryujinx.UI.Widgets Toggles[4] = false; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Button"); if (ImGui.Button(ControllerInputLayout.Right.StickButton.ToString(), @@ -390,6 +421,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.StickButton = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[7] = false; } } @@ -404,9 +436,11 @@ namespace Ryujinx.UI.Widgets //Show DPad Bindings ImGui.Text("D-Pad"); + ImGuiNative.igBeginGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -427,6 +461,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.DPadUp = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[8] = false; } break; @@ -434,15 +469,19 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.DPadUp = (int)PressedKey; + Toggles[8] = false; } break; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -475,9 +514,11 @@ namespace Ryujinx.UI.Widgets break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -498,6 +539,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.DPadLeft = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[10] = false; } break; @@ -505,15 +547,19 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.DPadLeft = (int)PressedKey; + Toggles[10] = false; } break; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -534,6 +580,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.DPadRight = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[11] = false; } break; @@ -541,11 +588,13 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.DPadRight = (int)PressedKey; + Toggles[11] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igEndGroup(); @@ -554,11 +603,14 @@ namespace Ryujinx.UI.Widgets static void DrawActionKeys() { string ButtonHeader = string.Empty; + //Show Action Key Bindings ImGui.Text("Action Keys"); + ImGuiNative.igBeginGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("A"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -579,6 +631,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonA = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[12] = false; } break; @@ -586,15 +639,19 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonA = (int)PressedKey; + Toggles[12] = false; } break; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("B"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -615,6 +672,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonB = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[13] = false; } break; @@ -622,14 +680,17 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonB = (int)PressedKey; + Toggles[13] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("X"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -650,6 +711,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonX = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[14] = false; } break; @@ -657,15 +719,19 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonX = (int)PressedKey; + Toggles[14] = false; } break; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Y"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -686,6 +752,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonY = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[15] = false; } break; @@ -693,6 +760,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonY = (int)PressedKey; + Toggles[15] = false; } break; @@ -707,12 +775,14 @@ namespace Ryujinx.UI.Widgets static void DrawTriggers() { string ButtonHeader = string.Empty; + //Draw Triggers ImGuiNative.igBeginGroup(); ImGui.Text("Triggers"); ImGuiNative.igBeginGroup(); + ImGui.Text("L"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -733,6 +803,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.ButtonL = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[17] = false; } break; @@ -740,6 +811,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.ButtonL = (int)PressedKey; + Toggles[17] = false; } break; @@ -749,7 +821,9 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("R"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -770,6 +844,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonR = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[16] = false; } break; @@ -777,14 +852,17 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonR = (int)PressedKey; + Toggles[16] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("ZL"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -805,6 +883,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.ButtonZL = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[19] = false; } break; @@ -812,15 +891,19 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.ButtonZL = (int)PressedKey; + Toggles[19] = false; } break; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("ZR"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -841,6 +924,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonZR = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[18] = false; } break; @@ -848,11 +932,13 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonZR = (int)PressedKey; + Toggles[18] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igEndGroup(); @@ -864,9 +950,11 @@ namespace Ryujinx.UI.Widgets //Draw Extra ImGuiNative.igBeginGroup(); + ImGui.Text("Extra Keys"); ImGuiNative.igBeginGroup(); + ImGui.Text("-"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -887,6 +975,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.ButtonMinus = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[20] = false; } break; @@ -894,14 +983,17 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.ButtonMinus = (int)PressedKey; + Toggles[20] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("+"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -922,6 +1014,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonPlus = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[21] = false; } break; @@ -929,11 +1022,13 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonPlus = (int)PressedKey; + Toggles[21] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igEndGroup(); @@ -942,11 +1037,13 @@ namespace Ryujinx.UI.Widgets static bool GetKey(ref Key PressedKey) { IO IO = ImGui.GetIO(); + foreach (Key Key in Enum.GetValues(typeof(Key))) { if (IO.KeysDown[(int)Key]) { PressedKey = Key; + return true; } } @@ -956,12 +1053,15 @@ namespace Ryujinx.UI.Widgets static bool GetButton(ref string PressedButton) { IO IO = ImGui.GetIO(); + GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex); + foreach (GamePadButton Button in Enum.GetValues(typeof(GamePadButton))) { if (WindowHelper.IsGamePadButtonPressed(GamePad, Button)) { PressedButton = Button.ToString(); + return true; } } @@ -971,12 +1071,15 @@ namespace Ryujinx.UI.Widgets static bool GetAxis(ref string Axis) { IO IO = ImGui.GetIO(); + GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex); + foreach (GamePadStick Stick in Enum.GetValues(typeof(GamePadStick))) { if (WindowHelper.GetJoystickAxis(GamePad,Stick).Length > 0) { Axis = Stick.ToString(); + return true; } } @@ -988,7 +1091,7 @@ namespace Ryujinx.UI.Widgets if (ImGui.BeginChildFrame(11, GroupSize, WindowFlags.AlwaysAutoResize)) { ContentWidth = (ImGui.GetContentRegionAvailableWidth() - 10) / 2; - GroupSize = ImGui.GetContentRegionMax(); + GroupSize = ImGui.GetContentRegionMax(); DrawLeftAnalog(); @@ -996,6 +1099,7 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + if (ImGui.BeginChildFrame(12, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawRightAnalog(); @@ -1011,7 +1115,7 @@ namespace Ryujinx.UI.Widgets if (ImGui.BeginChildFrame(11, GroupSize, WindowFlags.AlwaysAutoResize)) { ContentWidth = (ImGui.GetContentRegionAvailableWidth() - 10) / 2; - GroupSize = ImGui.GetContentRegionMax(); + GroupSize = ImGui.GetContentRegionMax(); DrawControllerLeftAnalog(); @@ -1019,6 +1123,7 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + if (ImGui.BeginChildFrame(12, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawControllerRightAnalog(); @@ -1039,6 +1144,7 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + if (ImGui.BeginChildFrame(14, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawActionKeys(); @@ -1054,6 +1160,7 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + if (ImGui.BeginChildFrame(16, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawExtras(); @@ -1070,28 +1177,32 @@ namespace Ryujinx.UI.Widgets InputDevice KeyboardInputDevice = new InputDevice() { - Index = short.MaxValue, + Index = short.MaxValue, DeviceType = DeviceType.Keyboard, - Name = "Keyboard" + Name = "Keyboard" }; - ConnectedHIDs.Add(short.MaxValue, KeyboardInputDevice); + + ConnectedHIDs.Add(short.MaxValue, KeyboardInputDevice); // Scans for connected joysticks while (true) { JoystickState GamePad = Joystick.GetState(GamePadIndex); + if (GamePad.IsConnected) { InputDevice GamePadDevice = new InputDevice() { - Index = GamePadIndex, + Index = GamePadIndex, DeviceType = DeviceType.GamePad, - Name = "GamePad " + GamePadIndex + Name = "GamePad " + GamePadIndex }; + ConnectedHIDs.Add(GamePadIndex, GamePadDevice); } else break; + GamePadIndex++; } } diff --git a/Ryujinx.UI/GUI/Widgets/PauseUI.cs b/Ryujinx.UI/GUI/Widgets/PauseUI.cs index 1a990b13a7..a85994d89f 100644 --- a/Ryujinx.UI/GUI/Widgets/PauseUI.cs +++ b/Ryujinx.UI/GUI/Widgets/PauseUI.cs @@ -9,6 +9,7 @@ namespace Ryujinx.UI 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)) { @@ -34,6 +35,7 @@ namespace Ryujinx.UI ImGuiNative.igEndGroup(); ImGui.SameLine(); + if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable(), WindowFlags.AlwaysAutoResize)) { @@ -44,6 +46,7 @@ namespace Ryujinx.UI Values.ButtonHeight))) { ShowPauseUI = false; + EmulationController.Resume(); } @@ -51,7 +54,9 @@ namespace Ryujinx.UI Values.ButtonHeight))) { ShowPauseUI = false; + EmulationController.ShutDown(); + ShowMainUI = true; } @@ -61,12 +66,15 @@ namespace Ryujinx.UI break; } + ImGui.EndChildFrame(); } + ImGui.EndChildFrame(); } + ImGui.EndWindow(); } } } -} +} \ No newline at end of file diff --git a/Ryujinx.UI/GUI/WindowHelper.cs b/Ryujinx.UI/GUI/WindowHelper.cs index b803f47c0b..227e5ddc22 100644 --- a/Ryujinx.UI/GUI/WindowHelper.cs +++ b/Ryujinx.UI/GUI/WindowHelper.cs @@ -11,11 +11,12 @@ namespace Ryujinx.UI class WindowHelper : GameWindow { protected float DeltaTime; + protected bool UIActive; + protected GraphicsContext MainContext; protected GraphicsContext UIContext; - protected bool UIActive; - private bool IsWindowOpened = false; + private bool IsWindowOpened; private int FontTexture; private float WheelPosition; @@ -47,19 +48,15 @@ namespace Ryujinx.UI UIActive = true; } - public void ShowDemo() - { - ImGuiNative.igShowDemoWindow(ref IsWindowOpened); - } - public void StartFrame() { UIContext.MakeCurrent(WindowInfo); IO IO = ImGui.GetIO(); - IO.DisplaySize = new System.Numerics.Vector2(Width, Height); + + IO.DisplaySize = new System.Numerics.Vector2(Width, Height); IO.DisplayFramebufferScale = new System.Numerics.Vector2(Values.CurrentWindowScale); - IO.DeltaTime = DeltaTime; + IO.DeltaTime = DeltaTime; ImGui.NewFrame(); @@ -71,6 +68,7 @@ namespace Ryujinx.UI ImGui.Render(); DrawData* data = ImGui.GetDrawData(); + RenderImDrawData(data); MainContext?.MakeCurrent(WindowInfo); @@ -87,9 +85,13 @@ namespace Ryujinx.UI // 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, @@ -104,25 +106,21 @@ namespace Ryujinx.UI // Store the texture identifier in the ImFontAtlas substructure. IO.FontAtlas.SetTexID(FontTexture); - // Cleanup (don't clear the input data if you want to append new fonts later) - //io.Fonts->ClearInputData(); IO.FontAtlas.ClearTexData(); - GL.BindTexture(TextureTarget.Texture2D, 0); - } - protected unsafe override void OnLoad(EventArgs e) - { - PrepareTexture(); + 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; @@ -132,6 +130,7 @@ namespace Ryujinx.UI if (Mouse.HasValue) { Point WindowPoint = new Point(MouseState.X, MouseState.Y); + IO.MousePosition = new System.Numerics.Vector2(WindowPoint.X, WindowPoint.Y); } @@ -143,12 +142,16 @@ namespace Ryujinx.UI 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); } @@ -156,6 +159,7 @@ namespace Ryujinx.UI else { IO.MousePosition = new System.Numerics.Vector2(-1f, -1f); + for (int i = 0; i <= 512; i++) { IO.KeysDown[i] = false; @@ -164,8 +168,8 @@ namespace Ryujinx.UI if (Mouse.HasValue) { - IO.MouseDown[0] = MouseState.LeftButton == ButtonState.Pressed; - IO.MouseDown[1] = MouseState.RightButton == ButtonState.Pressed; + 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; @@ -178,32 +182,47 @@ namespace Ryujinx.UI 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); - - // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) + IO IO = ImGui.GetIO(); - ImGui.ScaleClipRects(DrawData, IO.DisplayFramebufferScale); - // Setup orthographic projection matrix + ImGui.ScaleClipRects(DrawData, IO.DisplayFramebufferScale); + GL.MatrixMode(MatrixMode.Projection); + GL.PushMatrix(); + GL.LoadIdentity(); + GL.Ortho( 0.0f, IO.DisplaySize.X / IO.DisplayFramebufferScale.X, @@ -211,24 +230,30 @@ namespace Ryujinx.UI 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; + 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(); @@ -236,29 +261,42 @@ namespace Ryujinx.UI 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(); diff --git a/Ryujinx.UI/InputDevice.cs b/Ryujinx.UI/InputDevice.cs index 013f51b1ef..62fd600f78 100644 --- a/Ryujinx.UI/InputDevice.cs +++ b/Ryujinx.UI/InputDevice.cs @@ -7,10 +7,10 @@ namespace Ryujinx.UI { public struct InputDevice { - public int Index; + public int Index; + public string Name; public IInputDevice Device; - public DeviceType DeviceType; - public string Name; + public DeviceType DeviceType; } public enum DeviceType diff --git a/Ryujinx.UI/Program.cs b/Ryujinx.UI/Program.cs index cdb4b21755..bdf2f57dc8 100644 --- a/Ryujinx.UI/Program.cs +++ b/Ryujinx.UI/Program.cs @@ -6,9 +6,9 @@ namespace Ryujinx.UI { static void Main(string[] args) { - EmulationWindow mainUI = new EmulationWindow(); + EmulationWindow MainUI = new EmulationWindow(); - mainUI.Run(60.0, 60.0); + MainUI.MainLoop(); Environment.Exit(0); } From 13d94afd39cf2607b58a364543c7c7dc1b956702 Mon Sep 17 00:00:00 2001 From: emmaus Date: Mon, 23 Jul 2018 09:34:34 +0000 Subject: [PATCH 11/11] changed build directory of ui --- Ryujinx.UI/Ryujinx.UI.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Ryujinx.UI/Ryujinx.UI.csproj b/Ryujinx.UI/Ryujinx.UI.csproj index 7484d13841..1979a4b089 100644 --- a/Ryujinx.UI/Ryujinx.UI.csproj +++ b/Ryujinx.UI/Ryujinx.UI.csproj @@ -7,11 +7,13 @@ true + ..\Ryujinx\bin\Release\ true false + ..\Ryujinx\bin\Debug\