fae097408e
* support reading control data * show game info on titlebar * use first language is default is not available * use seperate language enums for titles * fix hex display
336 lines
9.2 KiB
C#
336 lines
9.2 KiB
C#
using OpenTK;
|
|
using OpenTK.Graphics;
|
|
using OpenTK.Input;
|
|
using Ryujinx.Graphics.Gal;
|
|
using Ryujinx.HLE;
|
|
using Ryujinx.HLE.Input;
|
|
using System;
|
|
using System.Threading;
|
|
|
|
using Stopwatch = System.Diagnostics.Stopwatch;
|
|
|
|
namespace Ryujinx
|
|
{
|
|
public class GLScreen : GameWindow
|
|
{
|
|
private const int TouchScreenWidth = 1280;
|
|
private const int TouchScreenHeight = 720;
|
|
|
|
private const int TargetFPS = 60;
|
|
|
|
private Switch Device;
|
|
|
|
private IGalRenderer Renderer;
|
|
|
|
private KeyboardState? Keyboard = null;
|
|
|
|
private MouseState? Mouse = null;
|
|
|
|
private Thread RenderThread;
|
|
|
|
private bool ResizeEvent;
|
|
|
|
private bool TitleEvent;
|
|
|
|
private string NewTitle;
|
|
|
|
public GLScreen(Switch Device, IGalRenderer Renderer)
|
|
: base(1280, 720,
|
|
new GraphicsMode(), "Ryujinx", 0,
|
|
DisplayDevice.Default, 3, 3,
|
|
GraphicsContextFlags.ForwardCompatible)
|
|
{
|
|
this.Device = Device;
|
|
this.Renderer = Renderer;
|
|
|
|
Location = new Point(
|
|
(DisplayDevice.Default.Width / 2) - (Width / 2),
|
|
(DisplayDevice.Default.Height / 2) - (Height / 2));
|
|
}
|
|
|
|
private void RenderLoop()
|
|
{
|
|
MakeCurrent();
|
|
|
|
Stopwatch Chrono = new Stopwatch();
|
|
|
|
Chrono.Start();
|
|
|
|
long TicksPerFrame = Stopwatch.Frequency / TargetFPS;
|
|
|
|
long Ticks = 0;
|
|
|
|
while (Exists && !IsExiting)
|
|
{
|
|
if (Device.WaitFifo())
|
|
{
|
|
Device.ProcessFrame();
|
|
}
|
|
|
|
Renderer.RunActions();
|
|
|
|
if (ResizeEvent)
|
|
{
|
|
ResizeEvent = false;
|
|
|
|
Renderer.RenderTarget.SetWindowSize(Width, Height);
|
|
}
|
|
|
|
Ticks += Chrono.ElapsedTicks;
|
|
|
|
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.RenderTarget.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;
|
|
}
|
|
}
|
|
|
|
//Polling becomes expensive if it's not slept
|
|
Thread.Sleep(1);
|
|
}
|
|
}
|
|
|
|
private new void UpdateFrame()
|
|
{
|
|
HidControllerButtons CurrentButton = 0;
|
|
HidJoystickPosition LeftJoystick;
|
|
HidJoystickPosition RightJoystick;
|
|
|
|
int LeftJoystickDX = 0;
|
|
int LeftJoystickDY = 0;
|
|
int RightJoystickDX = 0;
|
|
int RightJoystickDY = 0;
|
|
|
|
//Keyboard Input
|
|
if (Keyboard.HasValue)
|
|
{
|
|
KeyboardState Keyboard = this.Keyboard.Value;
|
|
|
|
CurrentButton = Config.JoyConKeyboard.GetButtons(Keyboard);
|
|
|
|
(LeftJoystickDX, LeftJoystickDY) = Config.JoyConKeyboard.GetLeftStick(Keyboard);
|
|
|
|
(RightJoystickDX, RightJoystickDY) = Config.JoyConKeyboard.GetRightStick(Keyboard);
|
|
}
|
|
|
|
//Controller Input
|
|
CurrentButton |= Config.JoyConController.GetButtons();
|
|
|
|
//Keyboard has priority stick-wise
|
|
if (LeftJoystickDX == 0 && LeftJoystickDY == 0)
|
|
{
|
|
(LeftJoystickDX, LeftJoystickDY) = Config.JoyConController.GetLeftStick();
|
|
}
|
|
|
|
if (RightJoystickDX == 0 && RightJoystickDY == 0)
|
|
{
|
|
(RightJoystickDX, RightJoystickDY) = Config.JoyConController.GetRightStick();
|
|
}
|
|
|
|
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?.LeftButton == ButtonState.Pressed)
|
|
{
|
|
MouseState Mouse = this.Mouse.Value;
|
|
|
|
int ScrnWidth = Width;
|
|
int ScrnHeight = Height;
|
|
|
|
if (Width > (Height * TouchScreenWidth) / TouchScreenHeight)
|
|
{
|
|
ScrnWidth = (Height * TouchScreenWidth) / TouchScreenHeight;
|
|
}
|
|
else
|
|
{
|
|
ScrnHeight = (Width * TouchScreenHeight) / TouchScreenWidth;
|
|
}
|
|
|
|
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 = (ScrnMouseX * TouchScreenWidth) / ScrnWidth;
|
|
int MY = (ScrnMouseY * TouchScreenHeight) / ScrnHeight;
|
|
|
|
HidTouchPoint CurrentPoint = new HidTouchPoint
|
|
{
|
|
X = MX,
|
|
Y = MY,
|
|
|
|
//Placeholder values till more data is acquired
|
|
DiameterX = 10,
|
|
DiameterY = 10,
|
|
Angle = 90
|
|
};
|
|
|
|
HasTouch = true;
|
|
|
|
Device.Hid.SetTouchPoints(CurrentPoint);
|
|
}
|
|
}
|
|
|
|
if (!HasTouch)
|
|
{
|
|
Device.Hid.SetTouchPoints();
|
|
}
|
|
|
|
Device.Hid.SetJoyconButton(
|
|
HidControllerId.CONTROLLER_HANDHELD,
|
|
HidControllerLayouts.Handheld_Joined,
|
|
CurrentButton,
|
|
LeftJoystick,
|
|
RightJoystick);
|
|
|
|
Device.Hid.SetJoyconButton(
|
|
HidControllerId.CONTROLLER_HANDHELD,
|
|
HidControllerLayouts.Main,
|
|
CurrentButton,
|
|
LeftJoystick,
|
|
RightJoystick);
|
|
}
|
|
|
|
private new void RenderFrame()
|
|
{
|
|
Renderer.RenderTarget.Render();
|
|
|
|
Device.Statistics.RecordSystemFrameTime();
|
|
|
|
double HostFps = Device.Statistics.GetSystemFrameRate();
|
|
double GameFps = Device.Statistics.GetGameFrameRate();
|
|
|
|
string TitleSection = string.IsNullOrWhiteSpace(Device.System.CurrentTitle) ? string.Empty
|
|
: " | " + Device.System.CurrentTitle;
|
|
|
|
NewTitle = $"Ryujinx{TitleSection} | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0} | " +
|
|
$"Game Vsync: {(Device.EnableDeviceVsync ? "On" : "Off")}";
|
|
|
|
TitleEvent = true;
|
|
|
|
SwapBuffers();
|
|
|
|
Device.System.SignalVsync();
|
|
|
|
Device.VsyncEvent.Set();
|
|
}
|
|
|
|
protected override void OnUnload(EventArgs e)
|
|
{
|
|
RenderThread.Join();
|
|
|
|
base.OnUnload(e);
|
|
}
|
|
|
|
protected override void OnResize(EventArgs e)
|
|
{
|
|
ResizeEvent = true;
|
|
}
|
|
|
|
protected override void OnKeyDown(KeyboardKeyEventArgs e)
|
|
{
|
|
bool ToggleFullscreen = e.Key == Key.F11 ||
|
|
(e.Modifiers.HasFlag(KeyModifiers.Alt) && e.Key == Key.Enter);
|
|
|
|
if (WindowState == WindowState.Fullscreen)
|
|
{
|
|
if (e.Key == Key.Escape || ToggleFullscreen)
|
|
{
|
|
WindowState = WindowState.Normal;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (e.Key == Key.Escape)
|
|
{
|
|
Exit();
|
|
}
|
|
|
|
if (ToggleFullscreen)
|
|
{
|
|
WindowState = WindowState.Fullscreen;
|
|
}
|
|
}
|
|
|
|
Keyboard = e.Keyboard;
|
|
}
|
|
|
|
protected override void OnKeyUp(KeyboardKeyEventArgs e)
|
|
{
|
|
Keyboard = e.Keyboard;
|
|
}
|
|
|
|
protected override void OnMouseDown(MouseButtonEventArgs e)
|
|
{
|
|
Mouse = e.Mouse;
|
|
}
|
|
|
|
protected override void OnMouseUp(MouseButtonEventArgs e)
|
|
{
|
|
Mouse = e.Mouse;
|
|
}
|
|
|
|
protected override void OnMouseMove(MouseMoveEventArgs e)
|
|
{
|
|
Mouse = e.Mouse;
|
|
}
|
|
}
|
|
} |