Skip to content

Commit

Permalink
Initial SDL2 window implementation (#3013)
Browse files Browse the repository at this point in the history
Initial SDL2 window implementation

Co-authored-by: Dean Herbert <pe@ppy.sh>
  • Loading branch information
peppy authored Jan 9, 2020
2 parents 5576dd0 + 26eb5b2 commit 6fcaeaf
Show file tree
Hide file tree
Showing 25 changed files with 1,677 additions and 82 deletions.
1 change: 1 addition & 0 deletions osu-framework.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PM/@EntryIndexedValue">PM</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RGB/@EntryIndexedValue">RGB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RNG/@EntryIndexedValue">RNG</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SDL/@EntryIndexedValue">SDL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SHA/@EntryIndexedValue">SHA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RGB/@EntryIndexedValue">RGB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SRGB/@EntryIndexedValue">SRGB</s:String>
Expand Down
3 changes: 2 additions & 1 deletion osu.Framework.Android/AndroidGameHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ protected override void SetupForRun()
{
base.SetupForRun();
AndroidGameWindow.View = gameView;
Window = new AndroidGameWindow();
}

protected override IWindow CreateWindow() => new AndroidGameWindow();

protected override bool LimitedMemoryEnvironment => true;

public override bool CanExit => false;
Expand Down
3 changes: 2 additions & 1 deletion osu.Framework.Tests/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ public static void Main(string[] args)
{
bool benchmark = args.Contains(@"--benchmark");
bool portable = args.Contains(@"--portable");
bool useSdl = args.Contains(@"--sdl");

using (GameHost host = Host.GetSuitableHost(@"visual-tests", portableInstallation: portable))
using (GameHost host = Host.GetSuitableHost(@"visual-tests", portableInstallation: portable, useSdl: useSdl))
{
if (benchmark)
host.Run(new AutomatedVisualTestGame());
Expand Down
3 changes: 2 additions & 1 deletion osu.Framework.iOS/IOSGameHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@ protected override void SetupForRun()
{
base.SetupForRun();
IOSGameWindow.GameView = gameView;
Window = new IOSGameWindow();
}

protected override IWindow CreateWindow() => new IOSGameWindow();

protected override void SetupConfig(IDictionary<FrameworkSetting, object> gameDefaults)
{
base.SetupConfig(gameDefaults);
Expand Down
1 change: 1 addition & 0 deletions osu.Framework.iOS/Input/IOSTextInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public event Action<string> OnNewImeComposition
add { }
remove { }
}

public event Action<string> OnNewImeResult
{
add { }
Expand Down
92 changes: 92 additions & 0 deletions osu.Framework/Extensions/BridgingExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using TKVector2 = osuTK.Vector2;
using SNVector2 = System.Numerics.Vector2;
using SDPoint = System.Drawing.Point;
using VPoint = Veldrid.Point;
using SDSize = System.Drawing.Size;
using VWindowState = Veldrid.WindowState;
using TKWindowState = osuTK.WindowState;

namespace osu.Framework.Extensions
{
/// <summary>
/// Temporary extension functions for bridging between osuTK, Veldrid, and System.Numerics
/// </summary>
public static class BridgingExtensions
{
public static TKVector2 ToOsuTK(this SNVector2 vec) =>
new TKVector2(vec.X, vec.Y);

public static SNVector2 ToSystemNumerics(this TKVector2 vec) =>
new SNVector2(vec.X, vec.Y);

public static SNVector2 ToSystemNumerics(this SDSize size) =>
new SNVector2(size.Width, size.Height);

public static SNVector2 ToSystemNumerics(this SDPoint point) =>
new SNVector2(point.X, point.Y);

public static SDSize ToSystemDrawingSize(this SNVector2 vec) =>
new SDSize((int)vec.X, (int)vec.Y);

public static SDPoint ToSystemDrawingPoint(this SNVector2 vec) =>
new SDPoint((int)vec.X, (int)vec.Y);

public static VPoint ToVeldridPoint(this SNVector2 vec) =>
new VPoint((int)vec.X, (int)vec.Y);

public static SNVector2 ToSystemNumerics(this VPoint point) =>
new SNVector2(point.X, point.Y);

public static TKWindowState ToOsuTK(this VWindowState state)
{
switch (state)
{
case VWindowState.Normal:
return TKWindowState.Normal;

case VWindowState.FullScreen:
return TKWindowState.Fullscreen;

case VWindowState.Maximized:
return TKWindowState.Maximized;

case VWindowState.Minimized:
return TKWindowState.Minimized;

case VWindowState.BorderlessFullScreen:
// WARNING: not supported by osuTK.WindowState
return TKWindowState.Fullscreen;

case VWindowState.Hidden:
// WARNING: not supported by osuTK.WindowState
return TKWindowState.Normal;
}

return TKWindowState.Normal;
}

public static VWindowState ToVeldrid(this TKWindowState state)
{
switch (state)
{
case TKWindowState.Normal:
return VWindowState.Normal;

case TKWindowState.Minimized:
return VWindowState.Minimized;

case TKWindowState.Maximized:
return VWindowState.Maximized;

case TKWindowState.Fullscreen:
return VWindowState.FullScreen;
}

// WARNING: some cases not supported by osuTK.WindowState
return VWindowState.Normal;
}
}
}
2 changes: 1 addition & 1 deletion osu.Framework/Graphics/OpenGL/GLWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static class GLWrapper

public static int DefaultFrameBuffer;

public static bool IsEmbedded { get; private set; }
public static bool IsEmbedded { get; internal set; }

/// <summary>
/// Check whether we have an initialised and non-disposed GL context.
Expand Down
8 changes: 4 additions & 4 deletions osu.Framework/Host.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace osu.Framework
{
public static class Host
{
public static DesktopGameHost GetSuitableHost(string gameName, bool bindIPC = false, bool portableInstallation = false)
public static DesktopGameHost GetSuitableHost(string gameName, bool bindIPC = false, bool portableInstallation = false, bool useSdl = false)
{
var toolkitOptions = new ToolkitOptions
{
Expand All @@ -23,13 +23,13 @@ public static DesktopGameHost GetSuitableHost(string gameName, bool bindIPC = fa
switch (RuntimeInfo.OS)
{
case RuntimeInfo.Platform.MacOsx:
return new MacOSGameHost(gameName, bindIPC, toolkitOptions, portableInstallation);
return new MacOSGameHost(gameName, bindIPC, toolkitOptions, portableInstallation, useSdl);

case RuntimeInfo.Platform.Linux:
return new LinuxGameHost(gameName, bindIPC, toolkitOptions, portableInstallation);
return new LinuxGameHost(gameName, bindIPC, toolkitOptions, portableInstallation, useSdl);

case RuntimeInfo.Platform.Windows:
return new WindowsGameHost(gameName, bindIPC, toolkitOptions, portableInstallation);
return new WindowsGameHost(gameName, bindIPC, toolkitOptions, portableInstallation, useSdl);

default:
throw new InvalidOperationException($"Could not find a suitable host for the selected operating system ({Enum.GetName(typeof(RuntimeInfo.Platform), RuntimeInfo.OS)}).");
Expand Down
12 changes: 10 additions & 2 deletions osu.Framework/Input/GameWindowTextInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public GameWindowTextInput(IWindow window)

protected virtual void HandleKeyPress(object sender, osuTK.KeyPressEventArgs e) => pending += e.KeyChar;

protected virtual void HandleKeyTyped(char c) => pending += c;

public bool ImeActive => false;

public string GetPendingText()
Expand All @@ -35,12 +37,18 @@ public string GetPendingText()

public void Deactivate(object sender)
{
window.KeyPress -= HandleKeyPress;
if (window is SDLWindow win)
win.KeyTyped -= HandleKeyTyped;
else
window.KeyPress -= HandleKeyPress;
}

public void Activate(object sender)
{
window.KeyPress += HandleKeyPress;
if (window is SDLWindow win)
win.KeyTyped += HandleKeyTyped;
else
window.KeyPress += HandleKeyPress;
}

private void imeCompose()
Expand Down
45 changes: 45 additions & 0 deletions osu.Framework/Input/Handlers/Keyboard/KeyboardHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Input.StateChanges;
using osu.Framework.Platform;
using osu.Framework.Statistics;
using TKKey = osuTK.Input.Key;

namespace osu.Framework.Input.Handlers.Keyboard
{
public class KeyboardHandler : InputHandler
{
public override bool IsActive => true;

public override int Priority => 0;

public override bool Initialize(GameHost host)
{
if (!(host.Window is SDLWindow window))
return false;

Enabled.BindValueChanged(e =>
{
if (e.NewValue)
{
window.KeyDown += handleKeyboardEvent;
window.KeyUp += handleKeyboardEvent;
}
else
{
window.KeyDown -= handleKeyboardEvent;
window.KeyUp -= handleKeyboardEvent;
}
}, true);

return true;
}

private void handleKeyboardEvent(KeyboardKeyInput keyEvent)
{
PendingInputs.Enqueue(keyEvent);
FrameStatistics.Increment(StatisticsCounterType.KeyEvents);
}
}
}
44 changes: 44 additions & 0 deletions osu.Framework/Input/Handlers/Mouse/MouseHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Platform;

namespace osu.Framework.Input.Handlers.Mouse
{
public class MouseHandler : InputHandler
{
private Window window;

public override bool Initialize(GameHost host)
{
window = host.Window as Window;

if (window == null)
return false;

Enabled.BindValueChanged(e =>
{
if (e.NewValue)
{
window.MouseMove += PendingInputs.Enqueue;
window.MouseDown += PendingInputs.Enqueue;
window.MouseUp += PendingInputs.Enqueue;
window.MouseWheel += PendingInputs.Enqueue;
}
else
{
window.MouseMove -= PendingInputs.Enqueue;
window.MouseDown -= PendingInputs.Enqueue;
window.MouseUp -= PendingInputs.Enqueue;
window.MouseWheel -= PendingInputs.Enqueue;
}
}, true);

return true;
}

public override bool IsActive => true;

public override int Priority => 0;
}
}
5 changes: 3 additions & 2 deletions osu.Framework/Input/Handlers/Mouse/OsuTKMouseHandlerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ public override bool Initialize(GameHost host)
Host = host;

MouseInWindow = host.Window.CursorInWindow;
Host.Window.MouseLeave += (s, e) => MouseInWindow = false;
Host.Window.MouseEnter += (s, e) => MouseInWindow = true;

host.Window.MouseLeave += (s, e) => MouseInWindow = false;
host.Window.MouseEnter += (s, e) => MouseInWindow = true;

return true;
}
Expand Down
52 changes: 36 additions & 16 deletions osu.Framework/Platform/DesktopGameHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ public abstract class DesktopGameHost : GameHost
private readonly bool bindIPCPort;
private Thread ipcThread;

protected DesktopGameHost(string gameName = @"", bool bindIPCPort = false, ToolkitOptions toolkitOptions = default, bool portableInstallation = false)
internal bool UseSdl { get; }

protected DesktopGameHost(string gameName = @"", bool bindIPCPort = false, ToolkitOptions toolkitOptions = default, bool portableInstallation = false, bool useSdl = false)
: base(gameName, toolkitOptions)
{
this.bindIPCPort = bindIPCPort;
IsPortableInstallation = portableInstallation;
UseSdl = useSdl;
}

protected override void SetupForRun()
Expand All @@ -36,6 +39,12 @@ protected override void SetupForRun()
base.SetupForRun();
}

protected override void SetupToolkit()
{
if (!UseSdl)
base.SetupToolkit();
}

private void startIPC()
{
Debug.Assert(ipcProvider == null);
Expand Down Expand Up @@ -73,22 +82,33 @@ private void openUsingShellExecute(string path) => Process.Start(new ProcessStar

protected override IEnumerable<InputHandler> CreateAvailableInputHandlers()
{
var defaultEnabled = new InputHandler[]
switch (Window)
{
new OsuTKMouseHandler(),
new OsuTKKeyboardHandler(),
new OsuTKJoystickHandler(),
};

var defaultDisabled = new InputHandler[]
{
new OsuTKRawMouseHandler(),
};

foreach (var h in defaultDisabled)
h.Enabled.Value = false;

return defaultEnabled.Concat(defaultDisabled);
case GameWindow _:
var defaultEnabled = new InputHandler[]
{
new OsuTKMouseHandler(),
new OsuTKKeyboardHandler(),
new OsuTKJoystickHandler(),
};

var defaultDisabled = new InputHandler[]
{
new OsuTKRawMouseHandler(),
};

foreach (var h in defaultDisabled)
h.Enabled.Value = false;

return defaultEnabled.Concat(defaultDisabled);

default:
return new InputHandler[]
{
new KeyboardHandler(),
new MouseHandler(),
};
}
}

public override Task SendMessageAsync(IpcMessage message) => ipcProvider.SendMessageAsync(message);
Expand Down
Loading

0 comments on commit 6fcaeaf

Please sign in to comment.