Implemented Gamelist
This commit is contained in:
parent
71e1f0bda6
commit
f1ffb129d6
15 changed files with 1611 additions and 16 deletions
|
@ -1,8 +1,11 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Executables
|
||||
{
|
||||
class Nro : IExecutable
|
||||
public class Nro : IExecutable
|
||||
{
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
|
@ -15,10 +18,11 @@ namespace Ryujinx.HLE.Loaders.Executables
|
|||
public int ROOffset { get; private set; }
|
||||
public int DataOffset { get; private set; }
|
||||
public int BssSize { get; private set; }
|
||||
|
||||
public int FileSize { get; private set; }
|
||||
|
||||
public Nro(Stream Input, string FilePath)
|
||||
{
|
||||
this.FilePath = FilePath;
|
||||
this.FilePath = this.FilePath;
|
||||
|
||||
BinaryReader Reader = new BinaryReader(Input);
|
||||
|
||||
|
@ -39,11 +43,12 @@ namespace Ryujinx.HLE.Loaders.Executables
|
|||
int DataSize = Reader.ReadInt32();
|
||||
int BssSize = Reader.ReadInt32();
|
||||
|
||||
this.Mod0Offset = Mod0Offset;
|
||||
this.TextOffset = TextOffset;
|
||||
this.ROOffset = ROOffset;
|
||||
this.DataOffset = DataOffset;
|
||||
this.BssSize = BssSize;
|
||||
this.Mod0Offset = Mod0Offset;
|
||||
this.TextOffset = TextOffset;
|
||||
this.ROOffset = ROOffset;
|
||||
this.DataOffset = DataOffset;
|
||||
this.BssSize = BssSize;
|
||||
this.FileSize = FileSize;
|
||||
|
||||
byte[] Read(long Position, int Size)
|
||||
{
|
||||
|
|
|
@ -43,6 +43,16 @@ namespace Ryujinx.HLE.Logging
|
|||
EnabledClasses[(int)Class] = Enabled;
|
||||
}
|
||||
|
||||
public bool IsEnabled(LogLevel LogLevel)
|
||||
{
|
||||
return EnabledLevels[(int)LogLevel];
|
||||
}
|
||||
|
||||
public bool IsFiltered(LogClass LogClass)
|
||||
{
|
||||
return EnabledClasses[(int)LogClass];
|
||||
}
|
||||
|
||||
internal void PrintDebug(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||
{
|
||||
Print(LogLevel.Debug, Class, GetFormattedMessage(Class, Message, Caller));
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.IO;
|
|||
|
||||
namespace Ryujinx.HLE
|
||||
{
|
||||
class VirtualFileSystem : IDisposable
|
||||
public class VirtualFileSystem : IDisposable
|
||||
{
|
||||
private const string BasePath = "RyuFs";
|
||||
private const string NandPath = "nand";
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Ryujinx.HLE.Input;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.Input;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -14,6 +15,8 @@ namespace Ryujinx
|
|||
|
||||
public static string IniPath { get; set; }
|
||||
|
||||
public static string DefaultGameDirectory { get; set; }
|
||||
|
||||
public static void Read(Logger Log)
|
||||
{
|
||||
string IniFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
|
@ -92,6 +95,68 @@ namespace Ryujinx
|
|||
ButtonZR = Convert.ToInt16(Parser.GetValue("Controls_Right_FakeJoycon_Button_ZR"))
|
||||
}
|
||||
};
|
||||
|
||||
DefaultGameDirectory = Parser.GetValue("Default_Game_Directory");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(DefaultGameDirectory))
|
||||
{
|
||||
VirtualFileSystem FS = new HLE.VirtualFileSystem();
|
||||
DefaultGameDirectory = Path.Combine(FS.GetSdCardPath(), "switch");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Save(Logger Log)
|
||||
{
|
||||
IniParser Parser = new IniParser(IniPath);
|
||||
|
||||
Parser.SetValue("Enable_Memory_Checks", (!AOptimizations.DisableMemoryChecks).ToString());
|
||||
|
||||
Parser.SetValue("Logging_Enable_Debug", Log.IsEnabled(LogLevel.Debug).ToString());
|
||||
Parser.SetValue("Logging_Enable_Stub", Log.IsEnabled(LogLevel.Stub).ToString());
|
||||
Parser.SetValue("Logging_Enable_Info", Log.IsEnabled(LogLevel.Info).ToString());
|
||||
Parser.SetValue("Logging_Enable_Warn", Log.IsEnabled(LogLevel.Warning).ToString());
|
||||
Parser.SetValue("Logging_Enable_Error", Log.IsEnabled(LogLevel.Error).ToString());
|
||||
|
||||
|
||||
List<string> FilteredClasses = new List<string>();
|
||||
|
||||
foreach(LogClass LogClass in Enum.GetValues(typeof(LogClass)))
|
||||
{
|
||||
if (Log.IsFiltered(LogClass))
|
||||
FilteredClasses.Add(LogClass.ToString());
|
||||
}
|
||||
|
||||
Parser.SetValue("Logging_Filtered_Classes", string.Join(',', FilteredClasses));
|
||||
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_Stick_Up", FakeJoyCon.Left.StickUp.ToString());
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_Stick_Down", FakeJoyCon.Left.StickDown.ToString());
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_Stick_Left", FakeJoyCon.Left.StickLeft.ToString());
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_Stick_Right", FakeJoyCon.Left.StickRight.ToString());
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_Stick_Button", FakeJoyCon.Left.StickButton.ToString());
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_DPad_Up", FakeJoyCon.Left.DPadUp.ToString());
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_DPad_Down", FakeJoyCon.Left.DPadDown.ToString());
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_DPad_Left", FakeJoyCon.Left.DPadLeft.ToString());
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_DPad_Right", FakeJoyCon.Left.DPadRight.ToString());
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_Button_Minus", FakeJoyCon.Left.ButtonMinus.ToString());
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_Button_L", FakeJoyCon.Left.ButtonL.ToString());
|
||||
Parser.SetValue("Controls_Left_FakeJoycon_Button_ZL", FakeJoyCon.Left.ButtonZL.ToString());
|
||||
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Stick_Up", FakeJoyCon.Right.StickUp.ToString());
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Stick_Down", FakeJoyCon.Right.StickDown.ToString());
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Stick_Left", FakeJoyCon.Right.StickLeft.ToString());
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Stick_Right", FakeJoyCon.Right.StickRight.ToString());
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Stick_Button", FakeJoyCon.Right.StickButton.ToString());
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Button_A", FakeJoyCon.Right.StickUp.ToString());
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Button_B", FakeJoyCon.Right.StickUp.ToString());
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Button_X", FakeJoyCon.Right.StickUp.ToString());
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Button_Y", FakeJoyCon.Right.StickUp.ToString());
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Button_Plus", FakeJoyCon.Right.StickUp.ToString());
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Button_R", FakeJoyCon.Right.StickUp.ToString());
|
||||
Parser.SetValue("Controls_Right_FakeJoycon_Button_ZR", FakeJoyCon.Right.StickUp.ToString());
|
||||
|
||||
Parser.SetValue("Default_Game_Directory", DefaultGameDirectory);
|
||||
|
||||
Parser.Save();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
53
Ryujinx.ImGui/Extensions/ControlArchive.cs
Normal file
53
Ryujinx.ImGui/Extensions/ControlArchive.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.UI
|
||||
{
|
||||
public class ControlArchive
|
||||
{
|
||||
public LanguageEntry[] LanguageEntries { get; set; }
|
||||
public long ApplicationTitleID { get; set; }
|
||||
public long BaseTitleID { get; set; }
|
||||
public long ProductCode { get; set; }
|
||||
public string ApplicationVersion { get; set; }
|
||||
|
||||
public ControlArchive(Stream Input)
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(Input);
|
||||
|
||||
byte[] LanguageEntryData = Reader.ReadBytes(0x3000);
|
||||
|
||||
Input.Seek(0x3060, SeekOrigin.Begin);
|
||||
ApplicationVersion = Encoding.ASCII.GetString(Reader.ReadBytes(0x10));
|
||||
BaseTitleID = Reader.ReadInt64();
|
||||
ApplicationTitleID = Reader.ReadInt64();
|
||||
|
||||
Input.Seek(0x30a8, SeekOrigin.Begin);
|
||||
ProductCode = Reader.ReadInt64();
|
||||
|
||||
LanguageEntries = new LanguageEntry[16];
|
||||
|
||||
using (MemoryStream LanguageStream = new MemoryStream(LanguageEntryData))
|
||||
{
|
||||
BinaryReader LanguageReader = new BinaryReader(LanguageStream);
|
||||
for (int index = 0; index < 16; index++)
|
||||
{
|
||||
LanguageEntries[index] = new LanguageEntry()
|
||||
{
|
||||
AplicationName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x200)).Trim('\0'),
|
||||
DeveloperName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x100)).Trim('\0')
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct LanguageEntry
|
||||
{
|
||||
public string AplicationName;
|
||||
public string DeveloperName;
|
||||
}
|
||||
}
|
72
Ryujinx.ImGui/Extensions/Nro.cs
Normal file
72
Ryujinx.ImGui/Extensions/Nro.cs
Normal file
|
@ -0,0 +1,72 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using Ryujinx.HLE.Loaders;
|
||||
|
||||
namespace Ryujinx.UI
|
||||
{
|
||||
class Nro : HLE.Loaders.Executables.Nro
|
||||
{
|
||||
public byte[] AssetRomfData { get; set; }
|
||||
public byte[] IconData { get; set; }
|
||||
|
||||
private byte[] NACPData { get; set; }
|
||||
|
||||
public int AssetOffset { get; set; }
|
||||
|
||||
public ControlArchive ControlArchive { get; set; }
|
||||
|
||||
|
||||
public Nro(Stream Input, string Name) : base(Input, Name)
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(Input);
|
||||
|
||||
byte[] Read(long Position, int Size)
|
||||
{
|
||||
Input.Seek(Position, SeekOrigin.Begin);
|
||||
|
||||
return Reader.ReadBytes(Size);
|
||||
}
|
||||
|
||||
if (Input.Length > FileSize)
|
||||
{
|
||||
AssetOffset = FileSize;
|
||||
|
||||
string AssetMagic = Encoding.ASCII.GetString(Read(AssetOffset, 4));
|
||||
|
||||
if (AssetMagic == "ASET")
|
||||
{
|
||||
Input.Seek(AssetOffset, SeekOrigin.Begin);
|
||||
int AssetMagic0 = Reader.ReadInt32();
|
||||
int AssetFormat = Reader.ReadInt32();
|
||||
byte[] IconSectionInfo = Reader.ReadBytes(0x10);
|
||||
byte[] NACPSectionInfo = Reader.ReadBytes(0x10);
|
||||
byte[] AssetRomfSectionInfo = Reader.ReadBytes(0x10);
|
||||
|
||||
long IconOffset = BitConverter.ToInt64(IconSectionInfo, 0);
|
||||
long IconSize = BitConverter.ToInt64(IconSectionInfo, 8);
|
||||
long NACPOffset = BitConverter.ToInt64(NACPSectionInfo, 0);
|
||||
long NACPSize = BitConverter.ToInt64(NACPSectionInfo, 8);
|
||||
long RomfOffset = BitConverter.ToInt64(AssetRomfSectionInfo, 0);
|
||||
long RomfSize = BitConverter.ToInt64(AssetRomfSectionInfo, 8);
|
||||
|
||||
Input.Seek(AssetOffset + IconOffset, SeekOrigin.Begin);
|
||||
IconData = Reader.ReadBytes((int)IconSize);
|
||||
|
||||
Input.Seek(AssetOffset + NACPOffset, SeekOrigin.Begin);
|
||||
NACPData = Reader.ReadBytes((int)NACPSize);
|
||||
|
||||
Input.Seek(AssetOffset + RomfOffset, SeekOrigin.Begin);
|
||||
AssetRomfData = Reader.ReadBytes((int)RomfSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (NACPData != null)
|
||||
using (MemoryStream NACPStream = new MemoryStream(NACPData))
|
||||
{
|
||||
ControlArchive = new ControlArchive(NACPStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,7 +57,7 @@ namespace Ryujinx.UI
|
|||
|
||||
private EmulationController EmulationController;
|
||||
|
||||
private Page CurrentPage = Page.PackageLoader;
|
||||
private Page CurrentPage = Page.GameList;
|
||||
|
||||
private bool EscapePressed;
|
||||
|
||||
|
@ -74,7 +74,7 @@ namespace Ryujinx.UI
|
|||
|
||||
IGalRenderer Renderer;
|
||||
IAalOutput AudioOut;
|
||||
Switch Ns;
|
||||
public static Switch Ns;
|
||||
|
||||
public EmulationWindow() : base("Test")
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ namespace Ryujinx.UI
|
|||
_deltaTime = (float)e.Time;
|
||||
if (UIActive)
|
||||
{
|
||||
StartFrame();
|
||||
StartFrame();
|
||||
isRunning = false;
|
||||
if (ShowMainUI)
|
||||
{
|
||||
|
@ -119,6 +119,7 @@ namespace Ryujinx.UI
|
|||
showMainUI = false;
|
||||
RenderPauseUI();
|
||||
}
|
||||
ImGuiNative.igShowMetricsWindow(ref UIActive);
|
||||
EndFrame();
|
||||
}
|
||||
else
|
||||
|
@ -347,6 +348,7 @@ namespace Ryujinx.UI
|
|||
{
|
||||
Configuration,
|
||||
Emulation,
|
||||
GameList,
|
||||
PackageLoader
|
||||
}
|
||||
|
||||
|
|
|
@ -13,11 +13,16 @@ namespace Ryujinx.UI.Widgets
|
|||
public static JoyCon CurrentJoyConLayout;
|
||||
static Page CurrentPage = Page.General;
|
||||
static bool ConfigIntialized = false;
|
||||
static bool OpenFolderPicker;
|
||||
static string CurrentPath;
|
||||
static IniParser IniParser;
|
||||
static FolderPicker FolderPicker;
|
||||
|
||||
static ConfigurationWidget()
|
||||
{
|
||||
IniParser = new IniParser(Config.IniPath);
|
||||
FolderPicker = FolderPicker.GetFolderPicker("FolderDialog",Config.DefaultGameDirectory);
|
||||
CurrentPath = Config.DefaultGameDirectory.ToString();
|
||||
}
|
||||
|
||||
public static void Draw()
|
||||
|
@ -54,6 +59,33 @@ namespace Ryujinx.UI.Widgets
|
|||
if (ImGui.BeginChild("generalFrame", true, WindowFlags.AlwaysAutoResize))
|
||||
{
|
||||
ImGui.Text("General Emulation Settings");
|
||||
ImGui.Spacing();
|
||||
ImGui.LabelText("","Default Game Directory");
|
||||
ImGui.SameLine();
|
||||
|
||||
if( ImGui.Selectable(Config.DefaultGameDirectory))
|
||||
{
|
||||
OpenFolderPicker = true;
|
||||
}
|
||||
if (OpenFolderPicker)
|
||||
ImGui.OpenPopup("OpenFolder");
|
||||
|
||||
ImGui.SetNextWindowSize(new Vector2(500, 500), Condition.FirstUseEver);
|
||||
if(ImGui.BeginPopupModal("OpenFolder",WindowFlags.NoResize))
|
||||
{
|
||||
string output = CurrentPath;
|
||||
if (FolderPicker.Draw(ref output, false))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(output))
|
||||
{
|
||||
Config.DefaultGameDirectory = output;
|
||||
}
|
||||
ImGui.CloseCurrentPopup();
|
||||
OpenFolderPicker = false;
|
||||
}
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
ImGui.Spacing();
|
||||
ImGui.Checkbox("Disable Cpu Memory Checks", ref AOptimizations.DisableMemoryChecks);
|
||||
ImGui.EndChild();
|
||||
|
@ -83,7 +115,7 @@ namespace Ryujinx.UI.Widgets
|
|||
}
|
||||
if (ImGui.Button("Save", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
|
||||
{
|
||||
IniParser.Save();
|
||||
Config.Save(EmulationWindow.Ns.Log);
|
||||
}
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Discard", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
|
||||
|
|
127
Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs
Normal file
127
Ryujinx.ImGui/GUI/Widgets/FolderPicker.cs
Normal file
|
@ -0,0 +1,127 @@
|
|||
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 FolderPicker
|
||||
{
|
||||
private const string FilePickerID = "###FilePicker";
|
||||
private static readonly Dictionary<object, FolderPicker> s_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 static FolderPicker GetFolderPicker(object o, string startingPath)
|
||||
{
|
||||
if (File.Exists(startingPath))
|
||||
{
|
||||
startingPath = new FileInfo(startingPath).DirectoryName;
|
||||
}
|
||||
else if (string.IsNullOrEmpty(startingPath) || !Directory.Exists(startingPath))
|
||||
{
|
||||
startingPath = Environment.CurrentDirectory;
|
||||
if (string.IsNullOrEmpty(startingPath))
|
||||
{
|
||||
startingPath = AppContext.BaseDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
if (!s_folderPickers.TryGetValue(o, out FolderPicker fp))
|
||||
{
|
||||
fp = new FolderPicker();
|
||||
fp.CurrentFolder = startingPath;
|
||||
s_folderPickers.Add(o, fp);
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
public bool Draw(ref string selected, bool returnOnSelection)
|
||||
{
|
||||
bool result = false;
|
||||
result = DrawFolder(ref selected, returnOnSelection);
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool DrawFolder(ref string selected, bool returnOnSelection = false)
|
||||
{
|
||||
ImGui.Text("Current Folder: " + CurrentFolder);
|
||||
bool result = false;
|
||||
|
||||
if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable() - new Vector2(20, Values.ButtonHeight),
|
||||
WindowFlags.Default))
|
||||
{
|
||||
DirectoryInfo di = new DirectoryInfo(CurrentFolder);
|
||||
if (di.Exists)
|
||||
{
|
||||
if (di.Parent != null)
|
||||
{
|
||||
ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow);
|
||||
|
||||
if (ImGui.Selectable("../", false, SelectableFlags.DontClosePopups
|
||||
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
|
||||
{
|
||||
CurrentFolder = di.Parent.FullName;
|
||||
}
|
||||
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
foreach (var dir in Directory.EnumerateFileSystemEntries(di.FullName))
|
||||
{
|
||||
if (Directory.Exists(dir))
|
||||
{
|
||||
string name = Path.GetFileName(dir);
|
||||
bool isSelected = SelectedFile == dir;
|
||||
|
||||
ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow);
|
||||
|
||||
if (ImGui.Selectable(name + "/", isSelected, SelectableFlags.DontClosePopups
|
||||
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
|
||||
{
|
||||
SelectedFile = dir;
|
||||
selected = SelectedFile;
|
||||
}
|
||||
|
||||
if (SelectedFile != null)
|
||||
if (ImGui.IsMouseDoubleClicked(0) && SelectedFile.Equals(dir))
|
||||
{
|
||||
SelectedFile = null;
|
||||
selected = null;
|
||||
CurrentFolder = dir;
|
||||
}
|
||||
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui.EndChildFrame();
|
||||
|
||||
|
||||
if (ImGui.Button("Cancel", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (SelectedFile != null)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Open", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
|
||||
{
|
||||
result = true;
|
||||
selected = SelectedFile;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
198
Ryujinx.ImGui/GUI/Widgets/GameList.cs
Normal file
198
Ryujinx.ImGui/GUI/Widgets/GameList.cs
Normal file
|
@ -0,0 +1,198 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using ImGuiNET;
|
||||
using System.Numerics;
|
||||
using NanoJpeg;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Ryujinx.UI.Widgets
|
||||
{
|
||||
class GameList
|
||||
{
|
||||
static List<GameItem> GameItems = new List<GameItem>();
|
||||
static GameItem SelectedGame;
|
||||
static bool OpenFolderPicker;
|
||||
static FolderPicker FolderPicker;
|
||||
static string CurrentPath;
|
||||
|
||||
static GameList()
|
||||
{
|
||||
Refresh(Config.DefaultGameDirectory);
|
||||
FolderPicker = FolderPicker.GetFolderPicker("FolderDialog", Config.DefaultGameDirectory);
|
||||
}
|
||||
|
||||
public unsafe static void Refresh(string Path)
|
||||
{
|
||||
GameItems = new List<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,
|
||||
PixelType.UnsignedByte, new IntPtr(image.Image));
|
||||
image.Dispose();
|
||||
GL.BindTexture(TextureTarget.Texture2D, 0);
|
||||
}
|
||||
GameItems.Add(GameItem);
|
||||
}
|
||||
}
|
||||
else if (Directory.Exists(Path))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe static void DrawList()
|
||||
{
|
||||
uint id = 100;
|
||||
if (ImGui.Button("Refresh GameList"))
|
||||
Refresh(Config.DefaultGameDirectory);
|
||||
ImGui.SameLine();
|
||||
if(ImGui.Button("Select Game Directory"))
|
||||
{
|
||||
OpenFolderPicker = true;
|
||||
}
|
||||
if (OpenFolderPicker)
|
||||
ImGui.OpenPopup("OpenFolder");
|
||||
|
||||
ImGui.SetNextWindowSize(new Vector2(500, 500), Condition.FirstUseEver);
|
||||
if (ImGui.BeginPopupModal("OpenFolder", WindowFlags.NoResize))
|
||||
{
|
||||
string output = CurrentPath;
|
||||
if (FolderPicker.Draw(ref output, false))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(output))
|
||||
{
|
||||
Config.DefaultGameDirectory = output;
|
||||
Refresh(output);
|
||||
}
|
||||
ImGui.CloseCurrentPopup();
|
||||
OpenFolderPicker = false;
|
||||
}
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
if (ImGui.BeginChildFrame(20, ImGui.GetContentRegionAvailable(), WindowFlags.AlwaysAutoResize))
|
||||
{
|
||||
foreach (GameItem GameItem in GameItems)
|
||||
{
|
||||
id++;
|
||||
if (GameItem == SelectedGame)
|
||||
ImGui.PushStyleColor(ColorTarget.FrameBg, Values.Color.Yellow);
|
||||
if (ImGui.BeginChildFrame(id, new Vector2(ImGui.GetContentRegionAvailableWidth(), 60)
|
||||
, WindowFlags.AlwaysAutoResize))
|
||||
{
|
||||
if (GameItem.IsNro && GameItem.HasIcon)
|
||||
{
|
||||
ImGui.Image(new IntPtr(GameItem.TextureID), new Vector2(50, 50), new Vector2(0, 0),
|
||||
new Vector2(1, 1), new Vector4(255, 255, 255, 255), new Vector4(0, 0, 0, 255));
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.BeginChildFrame(id + 500, new Vector2(50, 50), WindowFlags.NoResize);
|
||||
ImGui.EndChildFrame();
|
||||
ImGui.SameLine();
|
||||
ImGui.Text(Path.GetFileName(GameItem.Path));
|
||||
|
||||
}
|
||||
ImGui.SameLine();
|
||||
ImGuiNative.igBeginGroup();
|
||||
if (GameItem.IsNro)
|
||||
{
|
||||
if (GameItem.Nro.ControlArchive != null)
|
||||
{
|
||||
ImGui.Text(GameItem.Nro.ControlArchive.LanguageEntries[0].AplicationName);
|
||||
ImGui.Text(GameItem.Nro.ControlArchive.LanguageEntries[0].DeveloperName);
|
||||
}
|
||||
|
||||
}
|
||||
ImGuiNative.igEndGroup();
|
||||
if (GameItem == SelectedGame)
|
||||
ImGui.PopStyleColor();
|
||||
if (ImGui.IsMouseDoubleClicked(0) && ImGui.IsItemHovered(HoveredFlags.AllowWhenOverlapped) && GameItem == SelectedGame)
|
||||
{
|
||||
|
||||
}
|
||||
else if (ImGui.IsMouseClicked(0) && ImGui.IsItemHovered(HoveredFlags.AllowWhenOverlapped | HoveredFlags.RootAndChildWindows))
|
||||
{
|
||||
SelectedGame = GameItem;
|
||||
}
|
||||
ImGui.EndChildFrame();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndChildFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GameItem
|
||||
{
|
||||
public AppletType AppletType;
|
||||
public string Path;
|
||||
public Nro Nro;
|
||||
public bool IsNro;
|
||||
public bool HasIcon => Nro?.IconData != null;
|
||||
public int TextureID;
|
||||
|
||||
public GameItem(string Path)
|
||||
{
|
||||
this.Path = Path;
|
||||
|
||||
if (File.Exists(Path))
|
||||
{
|
||||
AppletType = AppletType.Homebrew;
|
||||
FileInfo Package = new FileInfo(Path);
|
||||
if (Package.Extension.ToLower() == ".nro")
|
||||
{
|
||||
IsNro = true;
|
||||
Nro = new Nro(File.Open(Path, FileMode.Open), new FileInfo(Path).Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
AppletType = AppletType.Cartridge;
|
||||
}
|
||||
|
||||
public Bitmap GetBitmap()
|
||||
{
|
||||
if (IsNro)
|
||||
{
|
||||
return new Bitmap(new Bitmap(new MemoryStream(Nro.IconData)),new Size(50,50));
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
|
||||
public byte[] GetIconData()
|
||||
{
|
||||
if (IsNro)
|
||||
{
|
||||
return Nro.IconData;
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
}
|
||||
|
||||
enum AppletType
|
||||
{
|
||||
Homebrew,
|
||||
Cartridge
|
||||
}
|
||||
}
|
|
@ -24,6 +24,12 @@ namespace Ryujinx.UI
|
|||
CurrentPage = Page.PackageLoader;
|
||||
}
|
||||
|
||||
if (ImGui.Button("Game List", new System.Numerics.Vector2(Values.ButtonWidth,
|
||||
Values.ButtonHeight)))
|
||||
{
|
||||
CurrentPage = Page.GameList;
|
||||
}
|
||||
|
||||
if (ImGui.Button("Settings", new System.Numerics.Vector2(Values.ButtonWidth,
|
||||
Values.ButtonHeight)))
|
||||
{
|
||||
|
@ -54,6 +60,9 @@ namespace Ryujinx.UI
|
|||
case Page.Configuration:
|
||||
Widgets.ConfigurationWidget.Draw();
|
||||
break;
|
||||
case Page.GameList:
|
||||
Widgets.GameList.DrawList();
|
||||
break;
|
||||
}
|
||||
ImGui.EndChildFrame();
|
||||
}
|
||||
|
|
1008
Ryujinx.ImGui/GUI/Widgets/NanoJpeg.cs
Normal file
1008
Ryujinx.ImGui/GUI/Widgets/NanoJpeg.cs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -172,7 +172,7 @@ namespace Ryujinx.UI
|
|||
GL.EnableClientState(ArrayCap.ColorArray);
|
||||
GL.Enable(EnableCap.Texture2D);
|
||||
|
||||
GL.UseProgram(1);
|
||||
GL.UseProgram(0);
|
||||
|
||||
// Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays)
|
||||
IO io = ImGui.GetIO();
|
||||
|
@ -194,13 +194,16 @@ namespace Ryujinx.UI
|
|||
GL.LoadIdentity();
|
||||
|
||||
// Render command lists
|
||||
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
NativeDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
byte* vtx_buffer = (byte*)cmd_list->VtxBuffer.Data;
|
||||
ushort* idx_buffer = (ushort*)cmd_list->IdxBuffer.Data;
|
||||
|
||||
DrawVert vert0 = *((DrawVert*)vtx_buffer);
|
||||
DrawVert vert1 = *(((DrawVert*)vtx_buffer) + 1);
|
||||
DrawVert vert2 = *(((DrawVert*)vtx_buffer) + 2);
|
||||
|
||||
GL.VertexPointer(2, VertexPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.PosOffset));
|
||||
GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.UVOffset));
|
||||
GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.ColOffset));
|
||||
|
@ -220,6 +223,8 @@ namespace Ryujinx.UI
|
|||
(int)(io.DisplaySize.Y - pcmd->ClipRect.W),
|
||||
(int)(pcmd->ClipRect.Z - pcmd->ClipRect.X),
|
||||
(int)(pcmd->ClipRect.W - pcmd->ClipRect.Y));
|
||||
ushort[] indices = new ushort[pcmd->ElemCount];
|
||||
for (int i = 0; i < indices.Length; i++) { indices[i] = idx_buffer[i]; }
|
||||
GL.DrawElements(PrimitiveType.Triangles, (int)pcmd->ElemCount, DrawElementsType.UnsignedShort, new IntPtr(idx_buffer));
|
||||
}
|
||||
idx_buffer += pcmd->ElemCount;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="ImGui.NET" Version="0.4.5" />
|
||||
<PackageReference Include="OpenTK.NETCore" Version="1.1.2749.6433" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
8
Ryujinx/Properties/launchSettings.json
Normal file
8
Ryujinx/Properties/launchSettings.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profiles": {
|
||||
"Ryujinx": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "\"C:\\Users\\Emmanuel Hansen\\AppData\\Roaming\\RyuFs\\sdmc\\switch\\fruity\\fruity.nro\""
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue