diff --git a/Ryujinx.UI/Extensions/ControlArchive.cs b/Ryujinx.UI/Extensions/ControlArchive.cs index e478383716..07e988daf0 100644 --- a/Ryujinx.UI/Extensions/ControlArchive.cs +++ b/Ryujinx.UI/Extensions/ControlArchive.cs @@ -6,9 +6,10 @@ namespace Ryujinx.UI public class ControlArchive { public LanguageEntry[] LanguageEntries { get; set; } - public long ApplicationTitleID { get; set; } - public long BaseTitleID { get; set; } - public long ProductCode { get; set; } + + public long ApplicationTitleID { get; set; } + public long BaseTitleID { get; set; } + public long ProductCode { get; set; } public string ApplicationVersion { get; set; } public ControlArchive(Stream Input) @@ -20,10 +21,11 @@ namespace Ryujinx.UI Input.Seek(0x3060, SeekOrigin.Begin); ApplicationVersion = Encoding.ASCII.GetString(Reader.ReadBytes(0x10)); - BaseTitleID = Reader.ReadInt64(); + BaseTitleID = Reader.ReadInt64(); ApplicationTitleID = Reader.ReadInt64(); Input.Seek(0x30a8, SeekOrigin.Begin); + ProductCode = Reader.ReadInt64(); LanguageEntries = new LanguageEntry[16]; @@ -31,12 +33,13 @@ namespace Ryujinx.UI using (MemoryStream LanguageStream = new MemoryStream(LanguageEntryData)) { BinaryReader LanguageReader = new BinaryReader(LanguageStream); - for (int index = 0; index < 16; index++) + + for (int Index = 0; Index < 16; Index++) { - LanguageEntries[index] = new LanguageEntry() + LanguageEntries[Index] = new LanguageEntry() { AplicationName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x200)).Trim('\0'), - DeveloperName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x100)).Trim('\0') + DeveloperName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x100)).Trim('\0') }; } } diff --git a/Ryujinx.UI/Extensions/Nro.cs b/Ryujinx.UI/Extensions/Nro.cs index e37ce87d3f..7bedc3e9ee 100644 --- a/Ryujinx.UI/Extensions/Nro.cs +++ b/Ryujinx.UI/Extensions/Nro.cs @@ -7,12 +7,13 @@ namespace Ryujinx.UI class Nro : HLE.Loaders.Executables.Nro { public byte[] AssetRomfData { get; set; } - public byte[] IconData { get; set; } - private byte[] NACPData { get; set; } - public int AssetOffset { get; set; } + public byte[] IconData { get; set; } + public int AssetOffset { get; set; } public ControlArchive ControlArchive { get; set; } + private byte[] NACPData { get; set; } + public Nro(Stream Input, string Name) : base(Input, Name) { BinaryReader Reader = new BinaryReader(Input); @@ -34,26 +35,29 @@ namespace Ryujinx.UI { Input.Seek(AssetOffset, SeekOrigin.Begin); - int AssetMagic0 = Reader.ReadInt32(); - int AssetFormat = Reader.ReadInt32(); - byte[] IconSectionInfo = Reader.ReadBytes(0x10); - byte[] NACPSectionInfo = Reader.ReadBytes(0x10); + int AssetMagic0 = Reader.ReadInt32(); + int AssetFormat = Reader.ReadInt32(); + byte[] IconSectionInfo = Reader.ReadBytes(0x10); + byte[] NACPSectionInfo = Reader.ReadBytes(0x10); byte[] AssetRomfSectionInfo = Reader.ReadBytes(0x10); long IconOffset = BitConverter.ToInt64(IconSectionInfo, 0); - long IconSize = BitConverter.ToInt64(IconSectionInfo, 8); + long IconSize = BitConverter.ToInt64(IconSectionInfo, 8); long NACPOffset = BitConverter.ToInt64(NACPSectionInfo, 0); - long NACPSize = BitConverter.ToInt64(NACPSectionInfo, 8); + long NACPSize = BitConverter.ToInt64(NACPSectionInfo, 8); long RomfOffset = BitConverter.ToInt64(AssetRomfSectionInfo, 0); - long RomfSize = BitConverter.ToInt64(AssetRomfSectionInfo, 8); + long RomfSize = BitConverter.ToInt64(AssetRomfSectionInfo, 8); Input.Seek(AssetOffset + IconOffset, SeekOrigin.Begin); + IconData = Reader.ReadBytes((int)IconSize); Input.Seek(AssetOffset + NACPOffset, SeekOrigin.Begin); + NACPData = Reader.ReadBytes((int)NACPSize); Input.Seek(AssetOffset + RomfOffset, SeekOrigin.Begin); + AssetRomfData = Reader.ReadBytes((int)RomfSize); } } diff --git a/Ryujinx.UI/Extensions/DialogResult.cs b/Ryujinx.UI/GUI/DialogResult.cs similarity index 100% rename from Ryujinx.UI/Extensions/DialogResult.cs rename to Ryujinx.UI/GUI/DialogResult.cs diff --git a/Ryujinx.UI/GUI/EmulationWindow.cs b/Ryujinx.UI/GUI/EmulationWindow.cs index 5dc1f75b72..7582757e8a 100644 --- a/Ryujinx.UI/GUI/EmulationWindow.cs +++ b/Ryujinx.UI/GUI/EmulationWindow.cs @@ -9,15 +9,17 @@ using Ryujinx.Graphics.Gal.OpenGL; using Ryujinx.HLE; using Ryujinx.HLE.Input; using System; +using System.Threading; + +using Stopwatch = System.Diagnostics.Stopwatch; namespace Ryujinx.UI { partial class EmulationWindow : WindowHelper { public static EmulationController EmulationController; - //toggles - private bool showMainUI = true; - private bool showPauseUI; + + //toggles private bool isRunning = false; private bool IsRunning { @@ -29,6 +31,7 @@ namespace Ryujinx.UI } } + private bool showMainUI = true; private bool ShowMainUI { get => showMainUI; @@ -45,6 +48,7 @@ namespace Ryujinx.UI } } + private bool showPauseUI; private bool ShowPauseUI { get => showPauseUI; @@ -63,10 +67,9 @@ namespace Ryujinx.UI private Page CurrentPage = Page.GameList; - private bool EscapePressed; - - private string CurrentPath = Environment.CurrentDirectory; - private string PackagePath = string.Empty; + private bool EscapePressed; + private string CurrentPath; + private string PackagePath; private const int TouchScreenWidth = 1280; private const int TouchScreenHeight = 720; @@ -74,17 +77,33 @@ namespace Ryujinx.UI private const float TouchScreenRatioX = (float)TouchScreenWidth / TouchScreenHeight; private const float TouchScreenRatioY = (float)TouchScreenHeight / TouchScreenWidth; + private const int TargetFPS = 60; + FilePicker FileDialog; IGalRenderer Renderer; public static Switch Ns; + private Thread RenderThread; + + private bool ResizeEvent; + + private bool TitleEvent; + + private string NewTitle; + public EmulationWindow() : base("Ryujinx") { - FileDialog = FilePicker.GetFilePicker("rom",null); + CurrentPath = Environment.CurrentDirectory; + PackagePath = string.Empty; + FileDialog = FilePicker.GetFilePicker("rom",null); InitializeSwitch(); + + ResizeEvent = false; + + TitleEvent = false; } protected override void OnLoad(EventArgs e) @@ -94,10 +113,87 @@ namespace Ryujinx.UI VSync = VSyncMode.On; } - protected override void OnRenderFrame(FrameEventArgs e) + private void RenderLoop() { - DeltaTime = (float)e.Time; + MakeCurrent(); + PrepareTexture(); + + Stopwatch Chrono = new Stopwatch(); + + Chrono.Start(); + + long TicksPerFrame = Stopwatch.Frequency / TargetFPS; + + long Ticks = 0; + + while (Exists && !IsExiting) + { + if (Ns.WaitFifo()) + { + Ns.ProcessFrame(); + } + + Renderer.RunActions(); + + if (ResizeEvent) + { + ResizeEvent = false; + + Renderer.FrameBuffer.SetWindowSize(Width, Height); + } + + Ticks += Chrono.ElapsedTicks; + + DeltaTime = (float)Chrono.Elapsed.TotalSeconds; + + Chrono.Restart(); + + if (Ticks >= TicksPerFrame) + { + RenderFrame(); + + //Queue max. 1 vsync + Ticks = Math.Min(Ticks - TicksPerFrame, TicksPerFrame); + } + } + } + + public void MainLoop() + { + VSync = VSyncMode.Off; + + Visible = true; + + Renderer.FrameBuffer.SetWindowSize(Width, Height); + + Context.MakeCurrent(null); + + //OpenTK doesn't like sleeps in its thread, to avoid this a renderer thread is created + RenderThread = new Thread(RenderLoop); + + RenderThread.Start(); + + while (Exists && !IsExiting) + { + ProcessEvents(); + + if (!IsExiting) + { + UpdateFrame(); + + if (TitleEvent) + { + TitleEvent = false; + + Title = NewTitle; + } + } + } + } + + private new void RenderFrame() + { if (UIActive) { StartFrame(); @@ -107,11 +203,13 @@ namespace Ryujinx.UI if (ShowMainUI) { showPauseUI = false; + RenderMainUI(); } else if (ShowPauseUI) { showMainUI = false; + RenderPauseUI(); } @@ -126,7 +224,9 @@ namespace Ryujinx.UI double HostFps = Ns.Statistics.GetSystemFrameRate(); double GameFps = Ns.Statistics.GetGameFrameRate(); - Title = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}"; + NewTitle = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}"; + + TitleEvent = true; SwapBuffers(); @@ -151,7 +251,7 @@ namespace Ryujinx.UI Ns.Log.Updated += ConsoleLog.PrintLog; } - protected override void OnUpdateFrame(FrameEventArgs e) + private new void UpdateFrame() { KeyboardState Keyboard = this.Keyboard ?? new KeyboardState(); @@ -178,8 +278,8 @@ namespace Ryujinx.UI EscapePressed = false; HidControllerButtons CurrentButton = 0; - HidJoystickPosition LeftJoystick; - HidJoystickPosition RightJoystick; + HidJoystickPosition LeftJoystick; + HidJoystickPosition RightJoystick; int LeftJoystickDX = 0; int LeftJoystickDY = 0; @@ -282,7 +382,7 @@ namespace Ryujinx.UI { MouseState Mouse = this.Mouse.Value; - int ScrnWidth = Width; + int ScrnWidth = Width; int ScrnHeight = Height; if (Width > Height * TouchScreenRatioX) @@ -319,7 +419,7 @@ namespace Ryujinx.UI //Placeholder values till more data is acquired DiameterX = 10, DiameterY = 10, - Angle = 90 + Angle = 90 }; HasTouch = true; @@ -346,10 +446,6 @@ namespace Ryujinx.UI CurrentButton, LeftJoystick, RightJoystick); - - Ns.ProcessFrame(); - - Renderer.RunActions(); } else if (EmulationController != null) if (EmulationController.IsLoaded) @@ -373,13 +469,25 @@ namespace Ryujinx.UI } } + protected override void OnUnload(EventArgs e) + { + RenderThread.Join(); + + base.OnUnload(e); + } + + protected override void OnResize(EventArgs e) + { + ResizeEvent = true; + } + public void LoadPackage(string path) { MainContext.MakeCurrent(WindowInfo); - if(Ns == null) - InitializeSwitch(); + if (Ns == null) + InitializeSwitch(); if (EmulationController == null) EmulationController = new EmulationController(Ns); diff --git a/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs b/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs index 4141728e68..9a7a657cb1 100644 --- a/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs +++ b/Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs @@ -67,6 +67,7 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + if (ImGui.Button("Input", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { CurrentPage = Page.Input; @@ -90,6 +91,7 @@ namespace Ryujinx.UI.Widgets { OpenFolderPicker = true; } + if (OpenFolderPicker) ImGui.OpenPopup("Open Folder"); @@ -101,22 +103,28 @@ namespace Ryujinx.UI.Widgets Config.DefaultGameDirectory = CurrentPath; } } + if (DialogResult != DialogResult.None) { OpenFolderPicker = false; } ImGui.Spacing(); + ImGui.Checkbox("Disable Cpu Memory Checks", ref AOptimizations.DisableMemoryChecks); + ImGui.EndChild(); } + break; case Page.Input: if (ImGui.BeginChild("inputFrame", true, WindowFlags.AlwaysAutoResize)) { DrawInputPage(); + ImGui.EndChild(); } + break; } @@ -131,15 +139,19 @@ namespace Ryujinx.UI.Widgets { Apply(); } + ImGui.SameLine(); } + if (ImGui.Button("Save", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { Apply(); Config.Save(EmulationWindow.Ns.Log); } + ImGui.SameLine(); + if (ImGui.Button("Discard", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { IniParser = new IniParser(Config.IniPath); diff --git a/Ryujinx.UI/GUI/Widgets/FilePicker.cs b/Ryujinx.UI/GUI/Widgets/FilePicker.cs index 0eeac2ad7c..77ab3fa66e 100644 --- a/Ryujinx.UI/GUI/Widgets/FilePicker.cs +++ b/Ryujinx.UI/GUI/Widgets/FilePicker.cs @@ -10,7 +10,9 @@ namespace ImGuiNET public class FilePicker { private const string FilePickerID = "###FilePicker"; + private static readonly Dictionary FilePickers = new Dictionary(); + private static readonly Vector2 DefaultFilePickerSize = new Vector2(600, 400); public string CurrentFolder { get; set; } @@ -26,6 +28,7 @@ namespace ImGuiNET else if (string.IsNullOrEmpty(StartingPath) || !Directory.Exists(StartingPath)) { StartingPath = Environment.CurrentDirectory; + if (string.IsNullOrEmpty(StartingPath)) { StartingPath = AppContext.BaseDirectory; @@ -68,9 +71,10 @@ namespace ImGuiNET if (ImGui.Selectable(Drive.Name + "/", IsSelected, SelectableFlags.DontClosePopups , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) { - CurrentDrive = Drive.Name; + CurrentDrive = Drive.Name; CurrentFolder = Drive.Name; } + ImGui.PopStyleColor(); } @@ -128,8 +132,8 @@ namespace ImGuiNET if (!FoldersOnly) foreach (string File in Directory.EnumerateFiles(CurrentDirectory.FullName)) { - string Name = Path.GetFileName(File); - bool IsSelected = SelectedEntry == File; + string Name = Path.GetFileName(File); + bool IsSelected = SelectedEntry == File; if (ImGui.Selectable(Name, IsSelected, SelectableFlags.DontClosePopups , new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight))) @@ -149,8 +153,8 @@ namespace ImGuiNET } } } - ImGui.EndChildFrame(); + ImGui.EndChildFrame(); if (ImGui.Button("Cancel", new Vector2(Values.ButtonWidth, Values.ButtonHeight))) { @@ -180,11 +184,13 @@ namespace ImGuiNET public DialogResult GetFolder(ref string CurrentPath) { ImGui.SetNextWindowSize(new Vector2(600, 600), Condition.FirstUseEver); + if (ImGui.BeginPopupModal("Open Folder", WindowFlags.NoResize)) { try { string Output = CurrentPath; + DialogResult DialogResult = Draw(ref Output, false, true); if (DialogResult == DialogResult.OK) diff --git a/Ryujinx.UI/GUI/Widgets/GameList.cs b/Ryujinx.UI/GUI/Widgets/GameList.cs index 59746f1f3f..38ae21bd3c 100644 --- a/Ryujinx.UI/GUI/Widgets/GameList.cs +++ b/Ryujinx.UI/GUI/Widgets/GameList.cs @@ -47,11 +47,15 @@ namespace Ryujinx.UI.Widgets GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); - NanoJpeg.NJImage image = new NJImage(); - image.Decode(GameItem.GetIconData()); - GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, image.Width, image.Height, 0, PixelFormat.Rgb, - PixelType.UnsignedByte, new IntPtr(image.Image)); - image.Dispose(); + NJImage Image = new NJImage(); + + Image.Decode(GameItem.GetIconData()); + + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, Image.Width, Image.Height, 0, PixelFormat.Rgb, + PixelType.UnsignedByte, new IntPtr(Image.Image)); + + Image.Dispose(); + GL.BindTexture(TextureTarget.Texture2D, 0); } @@ -63,12 +67,13 @@ namespace Ryujinx.UI.Widgets public unsafe static (bool,string) DrawList() { - uint id = 100; + uint Id = 100; if (ImGui.Button("Refresh GameList")) Refresh(Config.DefaultGameDirectory); ImGui.SameLine(); + if(ImGui.Button("Select Game Directory")) { OpenFolderPicker = true; @@ -78,6 +83,7 @@ namespace Ryujinx.UI.Widgets ImGui.OpenPopup("Open Folder"); DialogResult DialogResult = FolderPicker.GetFolder(ref GameDirectory); + if (DialogResult == DialogResult.OK) { Config.DefaultGameDirectory = GameDirectory; @@ -91,12 +97,12 @@ namespace Ryujinx.UI.Widgets { foreach (GameItem GameItem in GameItems) { - id++; + Id++; if (GameItem == SelectedGame) ImGui.PushStyleColor(ColorTarget.FrameBg, Values.Color.Yellow); - if (ImGui.BeginChildFrame(id, new Vector2(ImGui.GetContentRegionAvailableWidth(), 60) + if (ImGui.BeginChildFrame(Id, new Vector2(ImGui.GetContentRegionAvailableWidth(), 60) , WindowFlags.AlwaysAutoResize)) { if (GameItem.IsNro && GameItem.HasIcon) @@ -106,7 +112,7 @@ namespace Ryujinx.UI.Widgets } else { - ImGui.BeginChildFrame(id + 500, new Vector2(50, 50), WindowFlags.NoResize); + ImGui.BeginChildFrame(Id + 500, new Vector2(50, 50), WindowFlags.NoResize); ImGui.EndChildFrame(); ImGui.SameLine(); ImGui.Text(Path.GetFileName(GameItem.Path)); @@ -114,7 +120,9 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + if (GameItem.IsNro) { if (GameItem.Nro.ControlArchive != null) @@ -124,6 +132,7 @@ namespace Ryujinx.UI.Widgets } } + ImGuiNative.igEndGroup(); if (GameItem == SelectedGame) @@ -166,7 +175,9 @@ namespace Ryujinx.UI.Widgets if (File.Exists(Path)) { AppletType = AppletType.Homebrew; + FileInfo Package = new FileInfo(Path); + if (Package.Extension.ToLower() == ".nro") { Nro = new Nro(File.Open(Path, FileMode.Open), new FileInfo(Path).Name); diff --git a/Ryujinx.UI/GUI/Widgets/HomeUI.cs b/Ryujinx.UI/GUI/Widgets/HomeUI.cs index 188306e0bf..4cde8154a9 100644 --- a/Ryujinx.UI/GUI/Widgets/HomeUI.cs +++ b/Ryujinx.UI/GUI/Widgets/HomeUI.cs @@ -10,7 +10,9 @@ namespace Ryujinx.UI { ImGui.SetNextWindowPos(Vector2.Zero, Condition.Always, Vector2.Zero); + ImGui.SetNextWindowSize(new Vector2(Width, Height), Condition.Always); + if (ImGui.BeginWindow("MainWindow", ref showMainUI, WindowFlags.NoTitleBar | WindowFlags.NoMove | WindowFlags.AlwaysAutoResize)) { @@ -42,6 +44,7 @@ namespace Ryujinx.UI ImGuiNative.igEndGroup(); ImGui.SameLine(); + if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable(), WindowFlags.AlwaysAutoResize)) { @@ -49,30 +52,38 @@ namespace Ryujinx.UI { case Page.PackageLoader: string output = CurrentPath; + if (FileDialog.Draw(ref output, false) == DialogResult.OK) { if (!string.IsNullOrWhiteSpace(output)) { PackagePath = output; + LoadPackage(PackagePath); } } break; case Page.Configuration: Widgets.ConfigurationWidget.Draw(); + break; case Page.GameList: var SelectedPath = Widgets.GameList.DrawList(); + if (SelectedPath.Item1) { LoadPackage(SelectedPath.Item2); } + break; } + ImGui.EndChildFrame(); } + ImGui.EndChildFrame(); } + ImGui.EndWindow(); } } diff --git a/Ryujinx.UI/GUI/Widgets/InputPage.cs b/Ryujinx.UI/GUI/Widgets/InputPage.cs index 56eaf46871..230eef50ab 100644 --- a/Ryujinx.UI/GUI/Widgets/InputPage.cs +++ b/Ryujinx.UI/GUI/Widgets/InputPage.cs @@ -68,7 +68,7 @@ namespace Ryujinx.UI.Widgets ImGui.SliderFloat(string.Empty, ref CurrentGamePadDeadzone, 0, 1, CurrentGamePadDeadzone.ToString(), 1f); - ImGuiNative.igEndGroup(); + ImGuiNative.igEndGroup(); ImGui.SameLine(); @@ -119,8 +119,10 @@ namespace Ryujinx.UI.Widgets { // Show the Left Analog bindings ImGui.Text("Left Analog"); + ImGuiNative.igBeginGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickUp).ToString(), @@ -134,6 +136,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.StickUp = (int)PressedKey; + Toggles[0] = false; } } @@ -141,7 +144,9 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickDown).ToString(), @@ -155,6 +160,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.StickDown = (int)PressedKey; + Toggles[1] = false; } } @@ -162,6 +168,7 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickLeft).ToString(), @@ -175,13 +182,17 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.StickLeft = (int)PressedKey; + Toggles[2] = false; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); if (ImGui.Button(((Key)KeyboardInputLayout.Left.StickRight).ToString(), @@ -195,6 +206,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.StickRight = (int)PressedKey; + Toggles[3] = false; } } @@ -208,9 +220,11 @@ namespace Ryujinx.UI.Widgets { //Show Right Analog Bindings ImGui.Text("Right Analog"); + ImGuiNative.igBeginGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickUp).ToString(), @@ -231,7 +245,9 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickDown).ToString(), @@ -245,12 +261,15 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.StickDown = (int)PressedKey; + Toggles[5] = false; } } + ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickLeft).ToString(), @@ -264,13 +283,16 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.StickLeft = (int)PressedKey; + Toggles[6] = false; } } ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); if (ImGui.Button(((Key)KeyboardInputLayout.Right.StickRight).ToString(), @@ -284,6 +306,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.StickRight = (int)PressedKey; + Toggles[7] = false; } } @@ -298,6 +321,7 @@ namespace Ryujinx.UI.Widgets ImGui.Text("Left Analog"); ImGuiNative.igBeginGroup(); + ImGuiNative.igBeginGroup(); ImGui.Text("Stick"); @@ -314,6 +338,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.Stick = (GamePadStick)Enum.Parse(typeof(GamePadStick), Axis); + Toggles[0] = false; } } @@ -338,6 +363,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.StickButton = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[3] = false; } } @@ -351,9 +377,11 @@ namespace Ryujinx.UI.Widgets { //Show Right Analog Bindings ImGui.Text("Right Analog"); + ImGuiNative.igBeginGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Stick"); if (ImGui.Button(ControllerInputLayout.Right.Stick.ToString() @@ -372,10 +400,13 @@ namespace Ryujinx.UI.Widgets Toggles[4] = false; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Button"); if (ImGui.Button(ControllerInputLayout.Right.StickButton.ToString(), @@ -390,6 +421,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.StickButton = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[7] = false; } } @@ -404,9 +436,11 @@ namespace Ryujinx.UI.Widgets //Show DPad Bindings ImGui.Text("D-Pad"); + ImGuiNative.igBeginGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Up"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -427,6 +461,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.DPadUp = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[8] = false; } break; @@ -434,15 +469,19 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.DPadUp = (int)PressedKey; + Toggles[8] = false; } break; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Down"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -475,9 +514,11 @@ namespace Ryujinx.UI.Widgets break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("Left"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -498,6 +539,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.DPadLeft = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[10] = false; } break; @@ -505,15 +547,19 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.DPadLeft = (int)PressedKey; + Toggles[10] = false; } break; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Right"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -534,6 +580,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.DPadRight = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[11] = false; } break; @@ -541,11 +588,13 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.DPadRight = (int)PressedKey; + Toggles[11] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igEndGroup(); @@ -554,11 +603,14 @@ namespace Ryujinx.UI.Widgets static void DrawActionKeys() { string ButtonHeader = string.Empty; + //Show Action Key Bindings ImGui.Text("Action Keys"); + ImGuiNative.igBeginGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("A"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -579,6 +631,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonA = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[12] = false; } break; @@ -586,15 +639,19 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonA = (int)PressedKey; + Toggles[12] = false; } break; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("B"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -615,6 +672,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonB = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[13] = false; } break; @@ -622,14 +680,17 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonB = (int)PressedKey; + Toggles[13] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("X"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -650,6 +711,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonX = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[14] = false; } break; @@ -657,15 +719,19 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonX = (int)PressedKey; + Toggles[14] = false; } break; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("Y"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -686,6 +752,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonY = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[15] = false; } break; @@ -693,6 +760,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonY = (int)PressedKey; + Toggles[15] = false; } break; @@ -707,12 +775,14 @@ namespace Ryujinx.UI.Widgets static void DrawTriggers() { string ButtonHeader = string.Empty; + //Draw Triggers ImGuiNative.igBeginGroup(); ImGui.Text("Triggers"); ImGuiNative.igBeginGroup(); + ImGui.Text("L"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -733,6 +803,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.ButtonL = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[17] = false; } break; @@ -740,6 +811,7 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.ButtonL = (int)PressedKey; + Toggles[17] = false; } break; @@ -749,7 +821,9 @@ namespace Ryujinx.UI.Widgets ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("R"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -770,6 +844,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonR = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[16] = false; } break; @@ -777,14 +852,17 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonR = (int)PressedKey; + Toggles[16] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("ZL"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -805,6 +883,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.ButtonZL = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[19] = false; } break; @@ -812,15 +891,19 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.ButtonZL = (int)PressedKey; + Toggles[19] = false; } break; } } + ImGuiNative.igEndGroup(); ImGui.SameLine(); + ImGuiNative.igBeginGroup(); + ImGui.Text("ZR"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -841,6 +924,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonZR = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[18] = false; } break; @@ -848,11 +932,13 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonZR = (int)PressedKey; + Toggles[18] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igEndGroup(); @@ -864,9 +950,11 @@ namespace Ryujinx.UI.Widgets //Draw Extra ImGuiNative.igBeginGroup(); + ImGui.Text("Extra Keys"); ImGuiNative.igBeginGroup(); + ImGui.Text("-"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -887,6 +975,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Left.ButtonMinus = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[20] = false; } break; @@ -894,14 +983,17 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Left.ButtonMinus = (int)PressedKey; + Toggles[20] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igBeginGroup(); + ImGui.Text("+"); ButtonHeader = CurrentSelectedDevice.DeviceType == DeviceType.Keyboard ? @@ -922,6 +1014,7 @@ namespace Ryujinx.UI.Widgets { ControllerInputLayout.Right.ButtonPlus = (GamePadButton)Enum.Parse(typeof(GamePadButton),PressedButton); + Toggles[21] = false; } break; @@ -929,11 +1022,13 @@ namespace Ryujinx.UI.Widgets if (GetKey(ref PressedKey)) { KeyboardInputLayout.Right.ButtonPlus = (int)PressedKey; + Toggles[21] = false; } break; } } + ImGuiNative.igEndGroup(); ImGuiNative.igEndGroup(); @@ -942,11 +1037,13 @@ namespace Ryujinx.UI.Widgets static bool GetKey(ref Key PressedKey) { IO IO = ImGui.GetIO(); + foreach (Key Key in Enum.GetValues(typeof(Key))) { if (IO.KeysDown[(int)Key]) { PressedKey = Key; + return true; } } @@ -956,12 +1053,15 @@ namespace Ryujinx.UI.Widgets static bool GetButton(ref string PressedButton) { IO IO = ImGui.GetIO(); + GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex); + foreach (GamePadButton Button in Enum.GetValues(typeof(GamePadButton))) { if (WindowHelper.IsGamePadButtonPressed(GamePad, Button)) { PressedButton = Button.ToString(); + return true; } } @@ -971,12 +1071,15 @@ namespace Ryujinx.UI.Widgets static bool GetAxis(ref string Axis) { IO IO = ImGui.GetIO(); + GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex); + foreach (GamePadStick Stick in Enum.GetValues(typeof(GamePadStick))) { if (WindowHelper.GetJoystickAxis(GamePad,Stick).Length > 0) { Axis = Stick.ToString(); + return true; } } @@ -988,7 +1091,7 @@ namespace Ryujinx.UI.Widgets if (ImGui.BeginChildFrame(11, GroupSize, WindowFlags.AlwaysAutoResize)) { ContentWidth = (ImGui.GetContentRegionAvailableWidth() - 10) / 2; - GroupSize = ImGui.GetContentRegionMax(); + GroupSize = ImGui.GetContentRegionMax(); DrawLeftAnalog(); @@ -996,6 +1099,7 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + if (ImGui.BeginChildFrame(12, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawRightAnalog(); @@ -1011,7 +1115,7 @@ namespace Ryujinx.UI.Widgets if (ImGui.BeginChildFrame(11, GroupSize, WindowFlags.AlwaysAutoResize)) { ContentWidth = (ImGui.GetContentRegionAvailableWidth() - 10) / 2; - GroupSize = ImGui.GetContentRegionMax(); + GroupSize = ImGui.GetContentRegionMax(); DrawControllerLeftAnalog(); @@ -1019,6 +1123,7 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + if (ImGui.BeginChildFrame(12, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawControllerRightAnalog(); @@ -1039,6 +1144,7 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + if (ImGui.BeginChildFrame(14, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawActionKeys(); @@ -1054,6 +1160,7 @@ namespace Ryujinx.UI.Widgets } ImGui.SameLine(); + if (ImGui.BeginChildFrame(16, GroupSize, WindowFlags.AlwaysAutoResize)) { DrawExtras(); @@ -1070,28 +1177,32 @@ namespace Ryujinx.UI.Widgets InputDevice KeyboardInputDevice = new InputDevice() { - Index = short.MaxValue, + Index = short.MaxValue, DeviceType = DeviceType.Keyboard, - Name = "Keyboard" + Name = "Keyboard" }; - ConnectedHIDs.Add(short.MaxValue, KeyboardInputDevice); + + ConnectedHIDs.Add(short.MaxValue, KeyboardInputDevice); // Scans for connected joysticks while (true) { JoystickState GamePad = Joystick.GetState(GamePadIndex); + if (GamePad.IsConnected) { InputDevice GamePadDevice = new InputDevice() { - Index = GamePadIndex, + Index = GamePadIndex, DeviceType = DeviceType.GamePad, - Name = "GamePad " + GamePadIndex + Name = "GamePad " + GamePadIndex }; + ConnectedHIDs.Add(GamePadIndex, GamePadDevice); } else break; + GamePadIndex++; } } diff --git a/Ryujinx.UI/GUI/Widgets/PauseUI.cs b/Ryujinx.UI/GUI/Widgets/PauseUI.cs index 1a990b13a7..a85994d89f 100644 --- a/Ryujinx.UI/GUI/Widgets/PauseUI.cs +++ b/Ryujinx.UI/GUI/Widgets/PauseUI.cs @@ -9,6 +9,7 @@ namespace Ryujinx.UI System.Numerics.Vector2.Zero); ImGui.SetNextWindowSize(new System.Numerics.Vector2(Width, Height), Condition.Always); + if (ImGui.BeginWindow("PauseWindow", ref showMainUI, WindowFlags.NoTitleBar | WindowFlags.NoMove | WindowFlags.AlwaysAutoResize)) { @@ -34,6 +35,7 @@ namespace Ryujinx.UI ImGuiNative.igEndGroup(); ImGui.SameLine(); + if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable(), WindowFlags.AlwaysAutoResize)) { @@ -44,6 +46,7 @@ namespace Ryujinx.UI Values.ButtonHeight))) { ShowPauseUI = false; + EmulationController.Resume(); } @@ -51,7 +54,9 @@ namespace Ryujinx.UI Values.ButtonHeight))) { ShowPauseUI = false; + EmulationController.ShutDown(); + ShowMainUI = true; } @@ -61,12 +66,15 @@ namespace Ryujinx.UI break; } + ImGui.EndChildFrame(); } + ImGui.EndChildFrame(); } + ImGui.EndWindow(); } } } -} +} \ No newline at end of file diff --git a/Ryujinx.UI/GUI/WindowHelper.cs b/Ryujinx.UI/GUI/WindowHelper.cs index b803f47c0b..227e5ddc22 100644 --- a/Ryujinx.UI/GUI/WindowHelper.cs +++ b/Ryujinx.UI/GUI/WindowHelper.cs @@ -11,11 +11,12 @@ namespace Ryujinx.UI class WindowHelper : GameWindow { protected float DeltaTime; + protected bool UIActive; + protected GraphicsContext MainContext; protected GraphicsContext UIContext; - protected bool UIActive; - private bool IsWindowOpened = false; + private bool IsWindowOpened; private int FontTexture; private float WheelPosition; @@ -47,19 +48,15 @@ namespace Ryujinx.UI UIActive = true; } - public void ShowDemo() - { - ImGuiNative.igShowDemoWindow(ref IsWindowOpened); - } - public void StartFrame() { UIContext.MakeCurrent(WindowInfo); IO IO = ImGui.GetIO(); - IO.DisplaySize = new System.Numerics.Vector2(Width, Height); + + IO.DisplaySize = new System.Numerics.Vector2(Width, Height); IO.DisplayFramebufferScale = new System.Numerics.Vector2(Values.CurrentWindowScale); - IO.DeltaTime = DeltaTime; + IO.DeltaTime = DeltaTime; ImGui.NewFrame(); @@ -71,6 +68,7 @@ namespace Ryujinx.UI ImGui.Render(); DrawData* data = ImGui.GetDrawData(); + RenderImDrawData(data); MainContext?.MakeCurrent(WindowInfo); @@ -87,9 +85,13 @@ namespace Ryujinx.UI // Create OpenGL texture FontTexture = GL.GenTexture(); + GL.BindTexture(TextureTarget.Texture2D, FontTexture); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); + GL.TexImage2D( TextureTarget.Texture2D, 0, @@ -104,25 +106,21 @@ namespace Ryujinx.UI // Store the texture identifier in the ImFontAtlas substructure. IO.FontAtlas.SetTexID(FontTexture); - // Cleanup (don't clear the input data if you want to append new fonts later) - //io.Fonts->ClearInputData(); IO.FontAtlas.ClearTexData(); - GL.BindTexture(TextureTarget.Texture2D, 0); - } - protected unsafe override void OnLoad(EventArgs e) - { - PrepareTexture(); + GL.BindTexture(TextureTarget.Texture2D, 0); } unsafe void HandleInput(IO IO) { KeyboardState KeyboardState = default(KeyboardState); + if (Keyboard != null) if (Keyboard.HasValue) KeyboardState = Keyboard.Value; MouseState MouseState = default(MouseState); + if (Mouse != null) if (Mouse.HasValue) MouseState = Mouse.Value; @@ -132,6 +130,7 @@ namespace Ryujinx.UI if (Mouse.HasValue) { Point WindowPoint = new Point(MouseState.X, MouseState.Y); + IO.MousePosition = new System.Numerics.Vector2(WindowPoint.X, WindowPoint.Y); } @@ -143,12 +142,16 @@ namespace Ryujinx.UI if (KeyboardState[Key]) continue; + ImGuiNative.igGetIO()->KeyAlt = (byte)((KeyboardState[Key.AltLeft] || KeyboardState[Key.AltRight]) ? 1 : 0); + ImGuiNative.igGetIO()->KeyCtrl = (byte)((KeyboardState[Key.ControlLeft] || KeyboardState[Key.ControlRight]) ? 1 : 0); + ImGuiNative.igGetIO()->KeyShift = (byte)((KeyboardState[Key.ShiftLeft] || KeyboardState[Key.ShiftRight]) ? 1 : 0); + ImGuiNative.igGetIO()->KeySuper = (byte)((KeyboardState[Key.WinLeft] || KeyboardState[Key.WinRight]) ? 1 : 0); } @@ -156,6 +159,7 @@ namespace Ryujinx.UI else { IO.MousePosition = new System.Numerics.Vector2(-1f, -1f); + for (int i = 0; i <= 512; i++) { IO.KeysDown[i] = false; @@ -164,8 +168,8 @@ namespace Ryujinx.UI if (Mouse.HasValue) { - IO.MouseDown[0] = MouseState.LeftButton == ButtonState.Pressed; - IO.MouseDown[1] = MouseState.RightButton == ButtonState.Pressed; + IO.MouseDown[0] = MouseState.LeftButton == ButtonState.Pressed; + IO.MouseDown[1] = MouseState.RightButton == ButtonState.Pressed; IO.MouseDown[2] = MouseState.MiddleButton == ButtonState.Pressed; float NewWheelPos = MouseState.WheelPrecise; @@ -178,32 +182,47 @@ namespace Ryujinx.UI private unsafe void RenderImDrawData(DrawData* DrawData) { Vector4 ClearColor = new Vector4(114f / 255f, 144f / 255f, 154f / 255f, 1.0f); + GL.Viewport(0, 0, Width, Height); + GL.ClearColor(ClearColor.X, ClearColor.Y, ClearColor.Z, ClearColor.W); + GL.Clear(ClearBufferMask.ColorBufferBit); GL.GetInteger(GetPName.TextureBinding2D, out int last_texture); + GL.PushAttrib(AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.TransformBit); + GL.Enable(EnableCap.Blend); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + GL.Disable(EnableCap.CullFace); + GL.Disable(EnableCap.DepthTest); + GL.Enable(EnableCap.ScissorTest); + GL.EnableClientState(ArrayCap.VertexArray); + GL.EnableClientState(ArrayCap.TextureCoordArray); + GL.EnableClientState(ArrayCap.ColorArray); + GL.Enable(EnableCap.Texture2D); GL.UseProgram(0); - - // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) + IO IO = ImGui.GetIO(); - ImGui.ScaleClipRects(DrawData, IO.DisplayFramebufferScale); - // Setup orthographic projection matrix + ImGui.ScaleClipRects(DrawData, IO.DisplayFramebufferScale); + GL.MatrixMode(MatrixMode.Projection); + GL.PushMatrix(); + GL.LoadIdentity(); + GL.Ortho( 0.0f, IO.DisplaySize.X / IO.DisplayFramebufferScale.X, @@ -211,24 +230,30 @@ namespace Ryujinx.UI 0.0f, -1.0f, 1.0f); + GL.MatrixMode(MatrixMode.Modelview); + GL.PushMatrix(); + GL.LoadIdentity(); // Render command lists for (int n = 0; n < DrawData->CmdListsCount; n++) { - NativeDrawList* CmdList = DrawData->CmdLists[n]; - byte* VtxBuffer = (byte*)CmdList->VtxBuffer.Data; - ushort* IdxBuffer = (ushort*)CmdList->IdxBuffer.Data; + NativeDrawList* CmdList = DrawData->CmdLists[n]; + byte* VtxBuffer = (byte*)CmdList->VtxBuffer.Data; + ushort* IdxBuffer = (ushort*)CmdList->IdxBuffer.Data; GL.VertexPointer(2, VertexPointerType.Float, sizeof(DrawVert), new IntPtr(VtxBuffer + DrawVert.PosOffset)); + GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(DrawVert), new IntPtr(VtxBuffer + DrawVert.UVOffset)); + GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(DrawVert), new IntPtr(VtxBuffer + DrawVert.ColOffset)); for (int Cmd = 0; Cmd < CmdList->CmdBuffer.Size; Cmd++) { DrawCmd* PCmd = &(((DrawCmd*)CmdList->CmdBuffer.Data)[Cmd]); + if (PCmd->UserCallback != IntPtr.Zero) { throw new NotImplementedException(); @@ -236,29 +261,42 @@ namespace Ryujinx.UI else { GL.BindTexture(TextureTarget.Texture2D, PCmd->TextureId.ToInt32()); + GL.Scissor( (int)PCmd->ClipRect.X, (int)(IO.DisplaySize.Y - PCmd->ClipRect.W), (int)(PCmd->ClipRect.Z - PCmd->ClipRect.X), (int)(PCmd->ClipRect.W - PCmd->ClipRect.Y)); + ushort[] indices = new ushort[PCmd->ElemCount]; + for (int i = 0; i < indices.Length; i++) indices[i] = IdxBuffer[i]; + GL.DrawElements(PrimitiveType.Triangles, (int)PCmd->ElemCount, DrawElementsType.UnsignedShort, new IntPtr(IdxBuffer)); } + IdxBuffer += PCmd->ElemCount; } } // Restore modified state GL.DisableClientState(ArrayCap.ColorArray); + GL.DisableClientState(ArrayCap.TextureCoordArray); + GL.DisableClientState(ArrayCap.VertexArray); + GL.BindTexture(TextureTarget.Texture2D, last_texture); + GL.MatrixMode(MatrixMode.Modelview); + GL.PopMatrix(); + GL.MatrixMode(MatrixMode.Projection); + GL.PopMatrix(); + GL.PopAttrib(); SwapBuffers(); diff --git a/Ryujinx.UI/InputDevice.cs b/Ryujinx.UI/InputDevice.cs index 013f51b1ef..62fd600f78 100644 --- a/Ryujinx.UI/InputDevice.cs +++ b/Ryujinx.UI/InputDevice.cs @@ -7,10 +7,10 @@ namespace Ryujinx.UI { public struct InputDevice { - public int Index; + public int Index; + public string Name; public IInputDevice Device; - public DeviceType DeviceType; - public string Name; + public DeviceType DeviceType; } public enum DeviceType diff --git a/Ryujinx.UI/Program.cs b/Ryujinx.UI/Program.cs index cdb4b21755..bdf2f57dc8 100644 --- a/Ryujinx.UI/Program.cs +++ b/Ryujinx.UI/Program.cs @@ -6,9 +6,9 @@ namespace Ryujinx.UI { static void Main(string[] args) { - EmulationWindow mainUI = new EmulationWindow(); + EmulationWindow MainUI = new EmulationWindow(); - mainUI.Run(60.0, 60.0); + MainUI.MainLoop(); Environment.Exit(0); }