cleanup, refactoring, style changes, fixes

This commit is contained in:
emmaus 2018-06-23 10:15:29 +00:00
parent f1ffb129d6
commit b9d2039995
21 changed files with 634 additions and 417 deletions

View file

@ -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<long, string> 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);
}

View file

@ -18,6 +18,8 @@ namespace Ryujinx.HLE.OsHle
private ConcurrentDictionary<int, Process> Processes;
private bool IsDisposing;
public SystemStateMgr SystemState { get; private set; }
internal MemoryAllocator Allocator { get; private set; }
@ -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)

View file

@ -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.

View file

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

View file

@ -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<string, string> Values;
private readonly Dictionary<string, string> Comments;
private string Path;
private readonly string Path;
public IniParser(string Path)
{
@ -214,20 +224,25 @@ namespace Ryujinx
{
bool result = false;
List<string> Records = new List<string>();
foreach (var Record in Values)
{
if (Comments.ContainsKey(Record.Key))
{
string Comment = Comments[Record.Key];
if (!string.IsNullOrWhiteSpace(Comment))
{
Records.Add(Environment.NewLine);
Records.Add(Comments[Record.Key]);
}
}
Records.Add(string.Format("{0} = {1}", Record.Key, Record.Value));
}
File.WriteAllLines(Path, Records);
return result;
}
}

View file

@ -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;
}
}
}

View file

@ -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();

View file

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
public enum DialogResult
{
OK,
Cancel,
Yes,
No,
None
}

View file

@ -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);

View file

@ -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

View file

@ -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();

View file

@ -11,115 +11,115 @@ namespace ImGuiNET
/// </summary>
public class FilePicker
{
private const string FilePickerID = "###FilePicker";
private static readonly Dictionary<object, FilePicker> s_filePickers = new Dictionary<object, FilePicker>();
private const string FilePickerID = "###FilePicker";
private static readonly Dictionary<object, FilePicker> FilePickers = new Dictionary<object, FilePicker>();
private static readonly Vector2 DefaultFilePickerSize = new Vector2(600, 400);
public string CurrentFolder { get; set; }
public string 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;
}
}
}

View file

@ -11,91 +11,91 @@ namespace ImGuiNET
/// </summary>
public class FolderPicker
{
private const string FilePickerID = "###FilePicker";
private static readonly Dictionary<object, FolderPicker> s_folderPickers
private const string FolderPickerID = "###FolderPicker";
private static readonly Dictionary<object, FolderPicker> FolderPickers
= new Dictionary<object, FolderPicker>();
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;
}
}
}

View file

@ -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<GameItem> GameItems = new List<GameItem>();
static GameItem SelectedGame;
static bool OpenFolderPicker;
static FolderPicker FolderPicker;
static string CurrentPath;
static bool OpenFolderPicker;
static string GameDirectory;
static List<GameItem> 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<GameItem>();
foreach (string entry in Directory.EnumerateFileSystemEntries(Path))
{
if (File.Exists(entry))
{
string Extension = System.IO.Path.GetExtension(entry).ToLower();
if (Extension == ".nro" || Extension == ".nso")
{
GameItem GameItem = new GameItem(entry);
if (GameItem.IsNro && GameItem.HasIcon)
{
GameItem.TextureID = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, GameItem.TextureID);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
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<bool,string> DrawList()
{
uint id = 100;
if (ImGui.Button("Refresh GameList"))
Refresh(Config.DefaultGameDirectory);
ImGui.SameLine();
if(ImGui.Button("Select Game Directory"))
{
OpenFolderPicker = true;
}
if (OpenFolderPicker)
ImGui.OpenPopup("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<bool, string>(true, GameItem.Path);
}
else if (ImGui.IsMouseClicked(0) && ImGui.IsItemHovered(HoveredFlags.AllowWhenOverlapped | HoveredFlags.RootAndChildWindows))
{
SelectedGame = GameItem;
}
}
ImGui.EndChildFrame();
}
}
ImGui.EndChildFrame();
}
return new Tuple<bool, string>(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()
{

View file

@ -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();

View file

@ -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;
}
}

View file

@ -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();

View file

@ -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;
}
}
}

View file

@ -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);

View file

@ -16,7 +16,7 @@
<ItemGroup>
<PackageReference Include="ImGui.NET" Version="0.4.5" />
<PackageReference Include="OpenTK.NETCore" Version="1.1.2749.6433" />
<PackageReference Include="OpenTK.NetStandard" Version="1.0.4" />
<PackageReference Include="System.Drawing.Common" Version="4.5.0" />
</ItemGroup>

View file

@ -1,8 +0,0 @@
{
"profiles": {
"Ryujinx": {
"commandName": "Project",
"commandLineArgs": "\"C:\\Users\\Emmanuel Hansen\\AppData\\Roaming\\RyuFs\\sdmc\\switch\\fruity\\fruity.nro\""
}
}
}