minimal gui

This commit is contained in:
emmaus 2018-06-13 20:32:07 +00:00
parent 98e6a34608
commit 5cf8d72c88
10 changed files with 962 additions and 2 deletions

114
Ryujinx.ImGui/Config.cs Normal file
View file

@ -0,0 +1,114 @@
using Ryujinx.HLE.Input;
using Ryujinx.HLE.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Ryujinx
{
public static class Config
{
public static JoyCon FakeJoyCon { get; private set; }
public static void Read(Logger Log)
{
string IniFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string IniPath = Path.Combine(IniFolder, "Ryujinx.conf");
IniParser Parser = new IniParser(IniPath);
AOptimizations.DisableMemoryChecks = !Convert.ToBoolean(Parser.Value("Enable_Memory_Checks"));
Log.SetEnable(LogLevel.Debug, Convert.ToBoolean(Parser.Value("Logging_Enable_Debug")));
Log.SetEnable(LogLevel.Stub, Convert.ToBoolean(Parser.Value("Logging_Enable_Stub")));
Log.SetEnable(LogLevel.Info, Convert.ToBoolean(Parser.Value("Logging_Enable_Info")));
Log.SetEnable(LogLevel.Warning, Convert.ToBoolean(Parser.Value("Logging_Enable_Warn")));
Log.SetEnable(LogLevel.Error, Convert.ToBoolean(Parser.Value("Logging_Enable_Error")));
string[] FilteredLogClasses = Parser.Value("Logging_Filtered_Classes").Split(',', StringSplitOptions.RemoveEmptyEntries);
//When the classes are specified on the list, we only
//enable the classes that are on the list.
//So, first disable everything, then enable
//the classes that the user added to the list.
if (FilteredLogClasses.Length > 0)
{
foreach (LogClass Class in Enum.GetValues(typeof(LogClass)))
{
Log.SetEnable(Class, false);
}
}
foreach (string LogClass in FilteredLogClasses)
{
if (!string.IsNullOrEmpty(LogClass.Trim()))
{
foreach (LogClass Class in Enum.GetValues(typeof(LogClass)))
{
if (Class.ToString().ToLower().Contains(LogClass.Trim().ToLower()))
{
Log.SetEnable(Class, true);
}
}
}
}
FakeJoyCon = new JoyCon
{
Left = new JoyConLeft
{
StickUp = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Up")),
StickDown = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Down")),
StickLeft = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Left")),
StickRight = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Right")),
StickButton = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Button")),
DPadUp = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Up")),
DPadDown = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Down")),
DPadLeft = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Left")),
DPadRight = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Right")),
ButtonMinus = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_Minus")),
ButtonL = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_L")),
ButtonZL = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_ZL"))
},
Right = new JoyConRight
{
StickUp = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Up")),
StickDown = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Down")),
StickLeft = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Left")),
StickRight = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Right")),
StickButton = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Button")),
ButtonA = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_A")),
ButtonB = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_B")),
ButtonX = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_X")),
ButtonY = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_Y")),
ButtonPlus = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_Plus")),
ButtonR = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_R")),
ButtonZR = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_ZR"))
}
};
}
}
// https://stackoverflow.com/a/37772571
public class IniParser
{
private readonly Dictionary<string, string> Values;
public IniParser(string Path)
{
Values = File.ReadLines(Path)
.Where(Line => !string.IsNullOrWhiteSpace(Line) && !Line.StartsWith('#'))
.Select(Line => Line.Split('=', 2))
.ToDictionary(Parts => Parts[0].Trim(), Parts => Parts.Length > 1 ? Parts[1].Trim() : null);
}
public string Value(string Name)
{
return Values.TryGetValue(Name, out string Value) ? Value : null;
}
}
}

View file

@ -0,0 +1,51 @@
using Ryujinx.HLE.Logging;
using System;
using System.Collections.Generic;
using System.Threading;
namespace Ryujinx
{
static class ConsoleLog
{
private static Dictionary<LogLevel, ConsoleColor> LogColors;
private static object ConsoleLock;
static ConsoleLog()
{
LogColors = new Dictionary<LogLevel, ConsoleColor>()
{
{ LogLevel.Stub, ConsoleColor.DarkGray },
{ LogLevel.Info, ConsoleColor.White },
{ LogLevel.Warning, ConsoleColor.Yellow },
{ LogLevel.Error, ConsoleColor.Red }
};
ConsoleLock = new object();
}
public static void PrintLog(object sender, LogEventArgs e)
{
string FormattedTime = e.Time.ToString(@"hh\:mm\:ss\.fff");
string CurrentThread = Thread.CurrentThread.ManagedThreadId.ToString("d4");
string Message = FormattedTime + " | " + CurrentThread + " " + e.Message;
if (LogColors.TryGetValue(e.Level, out ConsoleColor Color))
{
lock (ConsoleLock)
{
Console.ForegroundColor = Color;
Console.WriteLine(Message);
Console.ResetColor();
}
}
else
{
Console.WriteLine(Message);
}
}
}
}

312
Ryujinx.ImGui/GUI/MainUI.cs Normal file
View file

@ -0,0 +1,312 @@
using ImGuiNET;
using OpenTK;
using Ryujinx.Audio;
using Ryujinx.Audio.OpenAL;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Gal.OpenGL;
using Ryujinx.HLE;
using Ryujinx.HLE.Input;
using OpenTK.Graphics;
using OpenTK.Input;
using System;
using System.IO;
namespace Ryujinx.UI
{
class MainUI : WindowHelper
{
//toggles
private bool ShowUI = true;
private bool ShowFileDialog = false;
private bool _isRunning = false;
private bool IsRunning
{
get => _isRunning;
set
{
_isRunning = value;
if (!value)
{
ShowUI = true;
}
}
}
private string CurrentPath = Environment.CurrentDirectory;
private string PackagePath = string.Empty;
private const int TouchScreenWidth = 1280;
private const int TouchScreenHeight = 720;
private const float TouchScreenRatioX = (float)TouchScreenWidth / TouchScreenHeight;
private const float TouchScreenRatioY = (float)TouchScreenHeight / TouchScreenWidth;
FilePicker FileDialog;
IGalRenderer Renderer;
IAalOutput AudioOut;
Switch Ns;
public MainUI() : base("Test")
{
FileDialog = FilePicker.GetFilePicker("rom",null);
Renderer = new OpenGLRenderer();
AudioOut = new OpenALAudioOut();
Ns = new Switch(Renderer, AudioOut);
Config.Read(Ns.Log);
Ns.Log.Updated += ConsoleLog.PrintLog;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
VSync = VSyncMode.On;
Renderer.SetWindowSize(Width, Height);
}
protected override void OnRenderFrame(FrameEventArgs e)
{
_deltaTime = (float)e.Time;
if (ShowUI)
{
StartFrame();
RenderUI();
EndFrame();
}
else
{
Ns.Statistics.StartSystemFrame();
Title = $"Ryujinx Screen - (Vsync: {VSync} - FPS: {Ns.Statistics.SystemFrameRate:0} - Guest FPS: " +
$"{Ns.Statistics.GameFrameRate:0})";
Renderer.RunActions();
Renderer.Render();
SwapBuffers();
Ns.Statistics.EndSystemFrame();
Ns.Os.SignalVsync();
}
}
protected override void OnUpdateFrame(FrameEventArgs e)
{
if (!ShowUI)
{
HidControllerButtons CurrentButton = 0;
HidJoystickPosition LeftJoystick;
HidJoystickPosition RightJoystick;
int LeftJoystickDX = 0;
int LeftJoystickDY = 0;
int RightJoystickDX = 0;
int RightJoystickDY = 0;
//RightJoystick
if (Keyboard[(Key)Config.FakeJoyCon.Left.StickUp]) LeftJoystickDY = short.MaxValue;
if (Keyboard[(Key)Config.FakeJoyCon.Left.StickDown]) LeftJoystickDY = -short.MaxValue;
if (Keyboard[(Key)Config.FakeJoyCon.Left.StickLeft]) LeftJoystickDX = -short.MaxValue;
if (Keyboard[(Key)Config.FakeJoyCon.Left.StickRight]) LeftJoystickDX = short.MaxValue;
//LeftButtons
if (Keyboard[(Key)Config.FakeJoyCon.Left.StickButton]) CurrentButton |= HidControllerButtons.KEY_LSTICK;
if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadUp]) CurrentButton |= HidControllerButtons.KEY_DUP;
if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadDown]) CurrentButton |= HidControllerButtons.KEY_DDOWN;
if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadLeft]) CurrentButton |= HidControllerButtons.KEY_DLEFT;
if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadRight]) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonMinus]) CurrentButton |= HidControllerButtons.KEY_MINUS;
if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonL]) CurrentButton |= HidControllerButtons.KEY_L;
if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonZL]) CurrentButton |= HidControllerButtons.KEY_ZL;
//RightJoystick
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickUp]) RightJoystickDY = short.MaxValue;
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickDown]) RightJoystickDY = -short.MaxValue;
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickLeft]) RightJoystickDX = -short.MaxValue;
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickRight]) RightJoystickDX = short.MaxValue;
//RightButtons
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickButton]) CurrentButton |= HidControllerButtons.KEY_RSTICK;
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonA]) CurrentButton |= HidControllerButtons.KEY_A;
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonB]) CurrentButton |= HidControllerButtons.KEY_B;
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonX]) CurrentButton |= HidControllerButtons.KEY_X;
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonY]) CurrentButton |= HidControllerButtons.KEY_Y;
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonPlus]) CurrentButton |= HidControllerButtons.KEY_PLUS;
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonR]) CurrentButton |= HidControllerButtons.KEY_R;
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonZR]) CurrentButton |= HidControllerButtons.KEY_ZR;
LeftJoystick = new HidJoystickPosition
{
DX = LeftJoystickDX,
DY = LeftJoystickDY
};
RightJoystick = new HidJoystickPosition
{
DX = RightJoystickDX,
DY = RightJoystickDY
};
bool HasTouch = false;
//Get screen touch position from left mouse click
//OpenTK always captures mouse events, even if out of focus, so check if window is focused.
if (Focused && Mouse?.GetState().LeftButton == ButtonState.Pressed)
{
int ScrnWidth = Width;
int ScrnHeight = Height;
if (Width > Height * TouchScreenRatioX)
{
ScrnWidth = (int)(Height * TouchScreenRatioX);
}
else
{
ScrnHeight = (int)(Width * TouchScreenRatioY);
}
int StartX = (Width - ScrnWidth) >> 1;
int StartY = (Height - ScrnHeight) >> 1;
int EndX = StartX + ScrnWidth;
int EndY = StartY + ScrnHeight;
if (Mouse.X >= StartX &&
Mouse.Y >= StartY &&
Mouse.X < EndX &&
Mouse.Y < EndY)
{
int ScrnMouseX = Mouse.X - StartX;
int ScrnMouseY = Mouse.Y - StartY;
int MX = (int)(((float)ScrnMouseX / ScrnWidth) * TouchScreenWidth);
int MY = (int)(((float)ScrnMouseY / ScrnHeight) * TouchScreenHeight);
HidTouchPoint CurrentPoint = new HidTouchPoint
{
X = MX,
Y = MY,
//Placeholder values till more data is acquired
DiameterX = 10,
DiameterY = 10,
Angle = 90
};
HasTouch = true;
Ns.Hid.SetTouchPoints(CurrentPoint);
}
}
if (!HasTouch)
{
Ns.Hid.SetTouchPoints();
}
Ns.Hid.SetJoyconButton(
HidControllerId.CONTROLLER_HANDHELD,
HidControllerLayouts.Handheld_Joined,
CurrentButton,
LeftJoystick,
RightJoystick);
Ns.Hid.SetJoyconButton(
HidControllerId.CONTROLLER_HANDHELD,
HidControllerLayouts.Main,
CurrentButton,
LeftJoystick,
RightJoystick);
}
}
private void RenderUI()
{
if (ShowUI)
{
ImGui.SetNextWindowPos(System.Numerics.Vector2.Zero, Condition.Always,
System.Numerics.Vector2.Zero);
ImGui.SetNextWindowSize(new System.Numerics.Vector2(Width, Height),Condition.Always);
if (ImGui.BeginWindow("MainWindow",ref ShowUI, WindowFlags.NoTitleBar
| WindowFlags.NoMove | WindowFlags.AlwaysAutoResize))
{
if(ImGui.BeginChildFrame(0, new System.Numerics.Vector2(-1,-1),
WindowFlags.AlwaysAutoResize))
{
ImGuiNative.igBeginGroup();
if(ImGui.Button("Load Package", new System.Numerics.Vector2(Values.ButtonWidth,
Values.ButtonHeight))){
ShowFileDialog = true;
}
ImGuiNative.igEndGroup();
ImGui.SameLine();
if(ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable(),
WindowFlags.AlwaysAutoResize))
{
if (ShowFileDialog)
{
string output = CurrentPath;
if (FileDialog.Draw(ref output, false))
{
if (!string.IsNullOrWhiteSpace(output))
{
PackagePath = output;
ShowFileDialog = false;
LoadPackage(PackagePath);
}
}
}
ImGui.EndChildFrame();
}
ImGui.EndChildFrame();
}
ImGui.EndWindow();
}
}
}
public void LoadPackage(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);
}
IsRunning = true;
ShowUI = false;
}
}
}

View file

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Numerics;
namespace ImGuiNET
{
public struct Values
{
public const float ButtonWidth = 170f;
public const float ButtonHeight = 50f;
public const float DefaultWindowScale = 1.0f;
public const float SelectibleHeight = 20.0f;
public static float CurrentWindowScale = 1.0f;
public static float CurrentFontScale = 1.2f;
public struct Color
{
public static Vector4 Yellow = new Vector4(1.0f, 1.0f, 0, 1.0f);
}
}
}

View file

@ -0,0 +1,148 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Numerics;
namespace ImGuiNET
{
/// <summary>
/// Adapted from Mellinoe's file picker for imgui
/// https://github.com/mellinoe/synthapp/blob/master/src/synthapp/Widgets/FilePicker.cs
/// </summary>
public class FilePicker
{
private const string FilePickerID = "###FilePicker";
private static readonly Dictionary<object, FilePicker> s_filePickers = new Dictionary<object, FilePicker>();
private static readonly Vector2 DefaultFilePickerSize = new Vector2(600, 400);
public string CurrentFolder { get; set; }
public string SelectedFile { get; set; }
public static FilePicker GetFilePicker(object o, string startingPath)
{
if (File.Exists(startingPath))
{
startingPath = new FileInfo(startingPath).DirectoryName;
}
else if (string.IsNullOrEmpty(startingPath) || !Directory.Exists(startingPath))
{
startingPath = Environment.CurrentDirectory;
if (string.IsNullOrEmpty(startingPath))
{
startingPath = AppContext.BaseDirectory;
}
}
if (!s_filePickers.TryGetValue(o, out FilePicker fp))
{
fp = new FilePicker();
fp.CurrentFolder = startingPath;
s_filePickers.Add(o, fp);
}
return fp;
}
public bool Draw(ref string selected, bool returnOnSelection)
{
bool result = false;
result = DrawFolder(ref selected, returnOnSelection);
return result;
}
private bool DrawFolder(ref string selected, bool returnOnSelection = false)
{
ImGui.Text("Current Folder: " + CurrentFolder);
bool result = false;
if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable() - new Vector2(20, Values.ButtonHeight),
WindowFlags.Default))
{
DirectoryInfo di = new DirectoryInfo(CurrentFolder);
if (di.Exists)
{
if (di.Parent != null)
{
ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow);
if (ImGui.Selectable("../", false, SelectableFlags.DontClosePopups
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
{
CurrentFolder = di.Parent.FullName;
}
ImGui.PopStyleColor();
}
foreach (var dir in Directory.EnumerateFileSystemEntries(di.FullName))
{
if (Directory.Exists(dir))
{
string name = Path.GetFileName(dir);
bool isSelected = SelectedFile == dir;
ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow);
if (ImGui.Selectable(name + "/", isSelected, SelectableFlags.DontClosePopups
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
{
SelectedFile = dir;
selected = SelectedFile;
}
if (SelectedFile != null)
if (ImGui.IsMouseDoubleClicked(0) && SelectedFile.Equals(dir))
{
SelectedFile = null;
selected = null;
CurrentFolder = dir;
}
ImGui.PopStyleColor();
}
}
foreach (var file in Directory.EnumerateFiles(di.FullName))
{
string name = Path.GetFileName(file);
bool isSelected = SelectedFile == file;
if (ImGui.Selectable(name, isSelected, SelectableFlags.DontClosePopups
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
{
SelectedFile = file;
if (returnOnSelection)
{
selected = SelectedFile;
}
}
if (SelectedFile != null)
if (ImGui.IsMouseDoubleClicked(0) && SelectedFile.Equals(file))
{
selected = file;
result = true;
}
}
}
}
ImGui.EndChildFrame();
if (ImGui.Button("Cancel", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
{
result = false;
}
if (SelectedFile != null)
{
ImGui.SameLine();
if (ImGui.Button("Open", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
{
result = true;
selected = SelectedFile;
}
}
return result;
}
}
}

View file

@ -0,0 +1,210 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using ImGuiNET;
namespace Ryujinx.UI
{
class WindowHelper : GameWindow
{
protected float _deltaTime;
bool IsWindowOpened = false;
int s_fontTexture;
float _wheelPosition;
public WindowHelper(string title) : base(1280, 720, GraphicsMode.Default, title, GameWindowFlags.Default
, DisplayDevice.Default, 3, 3, GraphicsContextFlags.ForwardCompatible)
{
Title = title;
IsWindowOpened = true;
Location = new Point(
(DisplayDevice.Default.Width / 2) - (Width / 2),
(DisplayDevice.Default.Height / 2) - (Height / 2));
}
public void ShowDemo()
{
ImGuiNative.igShowDemoWindow(ref IsWindowOpened);
}
public void StartFrame()
{
IO io = ImGui.GetIO();
io.DisplaySize = new System.Numerics.Vector2(Width, Height);
io.DisplayFramebufferScale = new System.Numerics.Vector2(Values.CurrentWindowScale);
io.DeltaTime = _deltaTime;
ImGui.NewFrame();
HandleInput(io);
}
public unsafe void EndFrame()
{
ImGui.Render();
DrawData* data = ImGui.GetDrawData();
RenderImDrawData(data);
}
protected unsafe override void OnLoad(EventArgs e)
{
ImGui.GetIO().FontAtlas.AddDefaultFont();
IO io = ImGui.GetIO();
io.FontAllowUserScaling = true;
ImGuiNative.igGetIO()->FontGlobalScale = Values.CurrentFontScale;
// Build texture atlas
FontTextureData texData = io.FontAtlas.GetTexDataAsAlpha8();
// Create OpenGL texture
s_fontTexture = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, s_fontTexture);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexImage2D(
TextureTarget.Texture2D,
0,
PixelInternalFormat.Alpha,
texData.Width,
texData.Height,
0,
PixelFormat.Alpha,
PixelType.UnsignedByte,
new IntPtr(texData.Pixels));
// Store the texture identifier in the ImFontAtlas substructure.
io.FontAtlas.SetTexID(s_fontTexture);
// Cleanup (don't clear the input data if you want to append new fonts later)
//io.Fonts->ClearInputData();
io.FontAtlas.ClearTexData();
GL.BindTexture(TextureTarget.Texture2D, 0);
}
void HandleInput(IO io)
{
MouseState cursorState = Mouse.GetCursorState();
MouseState mouseState = Mouse.GetState();
if (Focused)
{
Point windowPoint = PointToClient(new Point(cursorState.X, cursorState.Y));
io.MousePosition = new System.Numerics.Vector2(windowPoint.X / io.DisplayFramebufferScale.X, windowPoint.Y / io.DisplayFramebufferScale.Y);
}
else
{
io.MousePosition = new System.Numerics.Vector2(-1f, -1f);
}
io.MouseDown[0] = mouseState.LeftButton == ButtonState.Pressed;
io.MouseDown[1] = mouseState.RightButton == ButtonState.Pressed;
io.MouseDown[2] = mouseState.MiddleButton == ButtonState.Pressed;
float newWheelPos = mouseState.WheelPrecise;
float delta = newWheelPos - _wheelPosition;
_wheelPosition = newWheelPos;
io.MouseWheel = delta;
}
private unsafe void RenderImDrawData(DrawData* draw_data)
{
// Rendering
int display_w, display_h;
display_w = Width;
display_h = Height;
Vector4 clear_color = new Vector4(114f / 255f, 144f / 255f, 154f / 255f, 1.0f);
GL.Viewport(0, 0, display_w, display_h);
GL.ClearColor(clear_color.X, clear_color.Y, clear_color.Z, clear_color.W);
GL.Clear(ClearBufferMask.ColorBufferBit);
// We are using the OpenGL fixed pipeline to make the example code simpler to read!
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers.
int last_texture;
GL.GetInteger(GetPName.TextureBinding2D, out last_texture);
GL.PushAttrib(AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.TransformBit);
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.Disable(EnableCap.CullFace);
GL.Disable(EnableCap.DepthTest);
GL.Enable(EnableCap.ScissorTest);
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
GL.EnableClientState(ArrayCap.ColorArray);
GL.Enable(EnableCap.Texture2D);
GL.UseProgram(0);
// Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays)
IO io = ImGui.GetIO();
ImGui.ScaleClipRects(draw_data, io.DisplayFramebufferScale);
// Setup orthographic projection matrix
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
GL.Ortho(
0.0f,
io.DisplaySize.X / io.DisplayFramebufferScale.X,
io.DisplaySize.Y / io.DisplayFramebufferScale.Y,
0.0f,
-1.0f,
1.0f);
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
NativeDrawList* cmd_list = draw_data->CmdLists[n];
byte* vtx_buffer = (byte*)cmd_list->VtxBuffer.Data;
ushort* idx_buffer = (ushort*)cmd_list->IdxBuffer.Data;
GL.VertexPointer(2, VertexPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.PosOffset));
GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.UVOffset));
GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.ColOffset));
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
DrawCmd* pcmd = &(((DrawCmd*)cmd_list->CmdBuffer.Data)[cmd_i]);
if (pcmd->UserCallback != IntPtr.Zero)
{
throw new NotImplementedException();
}
else
{
GL.BindTexture(TextureTarget.Texture2D, pcmd->TextureId.ToInt32());
GL.Scissor(
(int)pcmd->ClipRect.X,
(int)(io.DisplaySize.Y - pcmd->ClipRect.W),
(int)(pcmd->ClipRect.Z - pcmd->ClipRect.X),
(int)(pcmd->ClipRect.W - pcmd->ClipRect.Y));
GL.DrawElements(PrimitiveType.Triangles, (int)pcmd->ElemCount, DrawElementsType.UnsignedShort, new IntPtr(idx_buffer));
}
idx_buffer += pcmd->ElemCount;
}
}
// Restore modified state
GL.DisableClientState(ArrayCap.ColorArray);
GL.DisableClientState(ArrayCap.TextureCoordArray);
GL.DisableClientState(ArrayCap.VertexArray);
GL.BindTexture(TextureTarget.Texture2D, last_texture);
GL.MatrixMode(MatrixMode.Modelview);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.PopAttrib();
SwapBuffers();
}
}
}

15
Ryujinx.ImGui/Program.cs Normal file
View file

@ -0,0 +1,15 @@
using System;
namespace Ryujinx.UI
{
class Program
{
static void Main(string[] args)
{
MainUI mainUI = new MainUI();
mainUI.Run(60.0, 60.0);
Environment.Exit(0);
}
}
}

View file

@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ImGui.NET" Version="0.4.5" />
<PackageReference Include="OpenTK.NETCore" Version="1.1.2749.6433" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics\Ryujinx.Graphics.csproj" />
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Ryujinx.conf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View file

@ -0,0 +1,47 @@
#Enable cpu memory checks (slow)
Enable_Memory_Checks = false
#Enable print debug logs
Logging_Enable_Debug = false
#Enable print stubbed calls logs
Logging_Enable_Stub = true
#Enable print informations logs
Logging_Enable_Info = true
#Enable print warning logs
Logging_Enable_Warn = true
#Enable print error logs
Logging_Enable_Error = true
#Filtered log classes, seperated by ", ", eg. `Logging_Filtered_Classes = Loader, ServiceFS`
Logging_Filtered_Classes =
#https://github.com/opentk/opentk/blob/develop/src/OpenTK/Input/Key.cs
Controls_Left_FakeJoycon_Stick_Up = 105
Controls_Left_FakeJoycon_Stick_Down = 101
Controls_Left_FakeJoycon_Stick_Left = 83
Controls_Left_FakeJoycon_Stick_Right = 86
Controls_Left_FakeJoycon_Stick_Button = 88
Controls_Left_FakeJoycon_DPad_Up = 45
Controls_Left_FakeJoycon_DPad_Down = 46
Controls_Left_FakeJoycon_DPad_Left = 47
Controls_Left_FakeJoycon_DPad_Right = 48
Controls_Left_FakeJoycon_Button_Minus = 120
Controls_Left_FakeJoycon_Button_L = 87
Controls_Left_FakeJoycon_Button_ZL = 99
Controls_Right_FakeJoycon_Stick_Up = 91
Controls_Right_FakeJoycon_Stick_Down = 93
Controls_Right_FakeJoycon_Stick_Left = 92
Controls_Right_FakeJoycon_Stick_Right = 94
Controls_Right_FakeJoycon_Stick_Button = 90
Controls_Right_FakeJoycon_Button_A = 108
Controls_Right_FakeJoycon_Button_B = 106
Controls_Right_FakeJoycon_Button_X = 85
Controls_Right_FakeJoycon_Button_Y = 104
Controls_Right_FakeJoycon_Button_Plus = 121
Controls_Right_FakeJoycon_Button_R = 103
Controls_Right_FakeJoycon_Button_ZR = 97

View file

@ -15,9 +15,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics", "Ryujinx
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "Ryujinx.Audio\Ryujinx.Audio.csproj", "{5C1D818E-682A-46A5-9D54-30006E26C270}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.ShaderTools", "Ryujinx.ShaderTools\Ryujinx.ShaderTools.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.ShaderTools", "Ryujinx.ShaderTools\Ryujinx.ShaderTools.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Luea", "Ryujinx.LLE\Luea.csproj", "{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luea", "Ryujinx.LLE\Luea.csproj", "{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.UI", "Ryujinx.ImGui\Ryujinx.UI.csproj", "{00117502-1661-4C8B-8C07-177C1A8AA455}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -57,6 +59,10 @@ Global
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Release|Any CPU.Build.0 = Release|Any CPU
{00117502-1661-4C8B-8C07-177C1A8AA455}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{00117502-1661-4C8B-8C07-177C1A8AA455}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00117502-1661-4C8B-8C07-177C1A8AA455}.Release|Any CPU.ActiveCfg = Release|Any CPU
{00117502-1661-4C8B-8C07-177C1A8AA455}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE