minimal gui
This commit is contained in:
parent
ed075ae3cd
commit
71e1f0bda6
25 changed files with 2034 additions and 6 deletions
|
@ -8,6 +8,7 @@ using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace ChocolArm64
|
namespace ChocolArm64
|
||||||
{
|
{
|
||||||
|
@ -21,6 +22,12 @@ namespace ChocolArm64
|
||||||
|
|
||||||
public bool EnableCpuTrace { get; set; }
|
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<long, string> SymbolTable = null)
|
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
|
||||||
{
|
{
|
||||||
CachedSubs = new ConcurrentDictionary<long, ATranslatedSub>();
|
CachedSubs = new ConcurrentDictionary<long, ATranslatedSub>();
|
||||||
|
@ -60,6 +67,11 @@ namespace ChocolArm64
|
||||||
AOpCode OpCode = ADecoder.DecodeOpCode(State, Memory, State.R15);
|
AOpCode OpCode = ADecoder.DecodeOpCode(State, Memory, State.R15);
|
||||||
|
|
||||||
OpCode.Interpreter(State, Memory, OpCode);
|
OpCode.Interpreter(State, Memory, OpCode);
|
||||||
|
|
||||||
|
CyclesExecuted++;
|
||||||
|
|
||||||
|
while (Pause)
|
||||||
|
PauseResetEvent.WaitOne(1000);
|
||||||
}
|
}
|
||||||
while (State.R15 != 0 && State.Running);
|
while (State.R15 != 0 && State.Running);
|
||||||
}
|
}
|
||||||
|
@ -89,6 +101,11 @@ namespace ChocolArm64
|
||||||
}
|
}
|
||||||
|
|
||||||
Position = Sub.Execute(State, Memory);
|
Position = Sub.Execute(State, Memory);
|
||||||
|
|
||||||
|
CyclesExecuted++;
|
||||||
|
|
||||||
|
while (Pause)
|
||||||
|
PauseResetEvent.WaitOne(1000);
|
||||||
}
|
}
|
||||||
while (Position != 0 && State.Running);
|
while (Position != 0 && State.Running);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Audio
|
namespace Ryujinx.Audio
|
||||||
{
|
{
|
||||||
public interface IAalOutput
|
public interface IAalOutput : IDisposable
|
||||||
{
|
{
|
||||||
int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback);
|
int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback);
|
||||||
|
|
||||||
|
|
|
@ -341,5 +341,30 @@ namespace Ryujinx.Audio.OpenAL
|
||||||
|
|
||||||
return PlaybackState.Stopped;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal
|
namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public interface IGalRenderer
|
public unsafe interface IGalRenderer : IDisposable
|
||||||
{
|
{
|
||||||
void QueueAction(Action ActionMthd);
|
void QueueAction(Action ActionMthd);
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FrameBuffer
|
public class FrameBuffer
|
||||||
{
|
{
|
||||||
public int Width { get; set; }
|
public int Width { get; set; }
|
||||||
public int Height { get; set; }
|
public int Height { get; set; }
|
||||||
|
|
|
@ -46,5 +46,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
RenderAction();
|
RenderAction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool Disposing)
|
||||||
|
{
|
||||||
|
if (Disposing)
|
||||||
|
{
|
||||||
|
ActionsQueue.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.HLE.Gpu.Engines;
|
using Ryujinx.HLE.Gpu.Engines;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu
|
||||||
{
|
{
|
||||||
class NvGpu
|
class NvGpu : IDisposable
|
||||||
{
|
{
|
||||||
public IGalRenderer Renderer { get; private set; }
|
public IGalRenderer Renderer { get; private set; }
|
||||||
|
|
||||||
|
@ -23,5 +24,10 @@ namespace Ryujinx.HLE.Gpu
|
||||||
Engine3d = new NvGpuEngine3d(this);
|
Engine3d = new NvGpuEngine3d(this);
|
||||||
EngineDma = new NvGpuEngineDma(this);
|
EngineDma = new NvGpuEngineDma(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Renderer.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -147,6 +147,22 @@ namespace Ryujinx.HLE.OsHle
|
||||||
return Process;
|
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)
|
private void InitializeProcess(Process Process)
|
||||||
{
|
{
|
||||||
Process.AppletState.SetFocus(true);
|
Process.AppletState.SetFocus(true);
|
||||||
|
|
|
@ -169,6 +169,27 @@ namespace Ryujinx.HLE.OsHle
|
||||||
return true;
|
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)
|
private void MapRWMemRegion(long Position, long Size, MemoryType Type)
|
||||||
{
|
{
|
||||||
Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW);
|
Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW);
|
||||||
|
|
|
@ -98,6 +98,7 @@ namespace Ryujinx.HLE
|
||||||
{
|
{
|
||||||
Os.Dispose();
|
Os.Dispose();
|
||||||
VFs.Dispose();
|
VFs.Dispose();
|
||||||
|
Gpu.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
169
Ryujinx.ImGui/Config.cs
Normal file
169
Ryujinx.ImGui/Config.cs
Normal file
|
@ -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<string, string> Values;
|
||||||
|
private readonly Dictionary<string, string> 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<string, string>();
|
||||||
|
foreach (string Line in Lines)
|
||||||
|
{
|
||||||
|
if (Line.StartsWith("#"))
|
||||||
|
CurrentComment += Line + Environment.NewLine;
|
||||||
|
else if (!string.IsNullOrWhiteSpace(Line))
|
||||||
|
{
|
||||||
|
string key = Line.Split("=", 2).First().Trim();
|
||||||
|
Comments.Add(key, CurrentComment.TrimEnd());
|
||||||
|
CurrentComment = string.Empty;
|
||||||
|
}
|
||||||
|
else CurrentComment = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetValue(string Name)
|
||||||
|
{
|
||||||
|
return Values.TryGetValue(Name, out string Value) ? Value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(string Name, string Value)
|
||||||
|
{
|
||||||
|
lock (Values)
|
||||||
|
if (Values.ContainsKey(Name))
|
||||||
|
{
|
||||||
|
Values[Name] = Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Values.Add(Name, Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Save()
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
List<string> Records = new List<string>();
|
||||||
|
foreach (var Record in Values)
|
||||||
|
{
|
||||||
|
if (Comments.ContainsKey(Record.Key))
|
||||||
|
{
|
||||||
|
string Comment = Comments[Record.Key];
|
||||||
|
if (!string.IsNullOrWhiteSpace(Comment))
|
||||||
|
{
|
||||||
|
Records.Add(Environment.NewLine);
|
||||||
|
Records.Add(Comments[Record.Key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Records.Add(string.Format("{0} = {1}", Record.Key, Record.Value));
|
||||||
|
}
|
||||||
|
File.WriteAllLines(Path, Records);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
Ryujinx.ImGui/ConsoleLog.cs
Normal file
51
Ryujinx.ImGui/ConsoleLog.cs
Normal file
|
@ -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<LogLevel, ConsoleColor> LogColors;
|
||||||
|
|
||||||
|
private static object ConsoleLock;
|
||||||
|
|
||||||
|
static ConsoleLog()
|
||||||
|
{
|
||||||
|
LogColors = new Dictionary<LogLevel, ConsoleColor>()
|
||||||
|
{
|
||||||
|
{ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
Ryujinx.ImGui/EmulationController.cs
Normal file
37
Ryujinx.ImGui/EmulationController.cs
Normal file
|
@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
354
Ryujinx.ImGui/GUI/EmulationWindow.cs
Normal file
354
Ryujinx.ImGui/GUI/EmulationWindow.cs
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
22
Ryujinx.ImGui/GUI/Values.cs
Normal file
22
Ryujinx.ImGui/GUI/Values.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ImGuiNET
|
||||||
|
{
|
||||||
|
public struct Values
|
||||||
|
{
|
||||||
|
public const float ButtonWidth = 170f;
|
||||||
|
public const float ButtonHeight = 50f;
|
||||||
|
public const float DefaultWindowScale = 1.0f;
|
||||||
|
public const float SelectibleHeight = 20.0f;
|
||||||
|
public static float CurrentWindowScale = 1.0f;
|
||||||
|
public static float CurrentFontScale = 1.2f;
|
||||||
|
|
||||||
|
public struct Color
|
||||||
|
{
|
||||||
|
public static Vector4 Yellow = new Vector4(1.0f, 1.0f, 0, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs
Normal file
102
Ryujinx.ImGui/GUI/Widgets/ConfigurationWidget.cs
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
148
Ryujinx.ImGui/GUI/Widgets/FilePicker.cs
Normal file
148
Ryujinx.ImGui/GUI/Widgets/FilePicker.cs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ImGuiNET
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adapted from Mellinoe's file picker for imgui
|
||||||
|
/// https://github.com/mellinoe/synthapp/blob/master/src/synthapp/Widgets/FilePicker.cs
|
||||||
|
/// </summary>
|
||||||
|
public class FilePicker
|
||||||
|
{
|
||||||
|
private const string FilePickerID = "###FilePicker";
|
||||||
|
private static readonly Dictionary<object, FilePicker> s_filePickers = new Dictionary<object, FilePicker>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
92
Ryujinx.ImGui/GUI/Widgets/HomeUI.cs
Normal file
92
Ryujinx.ImGui/GUI/Widgets/HomeUI.cs
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
535
Ryujinx.ImGui/GUI/Widgets/InputPage.cs
Normal file
535
Ryujinx.ImGui/GUI/Widgets/InputPage.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
Ryujinx.ImGui/GUI/Widgets/PauseUI.cs
Normal file
71
Ryujinx.ImGui/GUI/Widgets/PauseUI.cs
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
243
Ryujinx.ImGui/GUI/WindowHelper.cs
Normal file
243
Ryujinx.ImGui/GUI/WindowHelper.cs
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
Ryujinx.ImGui/Program.cs
Normal file
15
Ryujinx.ImGui/Program.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
Ryujinx.ImGui/Ryujinx.UI.csproj
Normal file
35
Ryujinx.ImGui/Ryujinx.UI.csproj
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ImGui.NET" Version="0.4.5" />
|
||||||
|
<PackageReference Include="OpenTK.NETCore" Version="1.1.2749.6433" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Graphics\Ryujinx.Graphics.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="RyujinxUI.conf">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
47
Ryujinx.ImGui/RyujinxUI.conf
Normal file
47
Ryujinx.ImGui/RyujinxUI.conf
Normal file
|
@ -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
|
10
Ryujinx.sln
10
Ryujinx.sln
|
@ -15,9 +15,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics", "Ryujinx
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "Ryujinx.Audio\Ryujinx.Audio.csproj", "{5C1D818E-682A-46A5-9D54-30006E26C270}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "Ryujinx.Audio\Ryujinx.Audio.csproj", "{5C1D818E-682A-46A5-9D54-30006E26C270}"
|
||||||
EndProject
|
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
|
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
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue