From be005c791fcac5d9329c1fbf4fe33388e19d7676 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 21 Jan 2016 21:09:41 +1100 Subject: [PATCH] Abstract away platform specific window/input handling. --- ClassicalSharp/ClassicalSharp.csproj | 1 + ClassicalSharp/Game/Game.Properties.cs | 36 ++++++++++- ClassicalSharp/Game/Game.cs | 30 ++++----- ClassicalSharp/Game/InputHandler.cs | 6 +- ClassicalSharp/GraphicsAPI/Direct3D9Api.cs | 12 ++-- ClassicalSharp/GraphicsAPI/IGraphicsApi.cs | 8 +-- ClassicalSharp/Platform/IPlatformWindow.cs | 72 ++++++++++++++++++++++ 7 files changed, 137 insertions(+), 28 deletions(-) create mode 100644 ClassicalSharp/Platform/IPlatformWindow.cs diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index 6439c88f0..c0119e238 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -222,6 +222,7 @@ + diff --git a/ClassicalSharp/Game/Game.Properties.cs b/ClassicalSharp/Game/Game.Properties.cs index 750d757c9..6f3ed2353 100644 --- a/ClassicalSharp/Game/Game.Properties.cs +++ b/ClassicalSharp/Game/Game.Properties.cs @@ -13,10 +13,11 @@ using ClassicalSharp.Renderers; using ClassicalSharp.Selections; using ClassicalSharp.TexturePack; using OpenTK; +using OpenTK.Input; namespace ClassicalSharp { - public partial class Game : GameWindow { + public partial class Game { /// Abstracts the underlying 3D graphics rendering API. public IGraphicsApi Graphics; @@ -190,5 +191,38 @@ namespace ClassicalSharp { Options.Set( OptionsKey.DefaultTexturePack, value ); } } + + internal IPlatformWindow window; + public MouseDevice Mouse; + public KeyboardDevice Keyboard; + + public int Width { get { return window.Width; } } + + public int Height { get { return window.Height; } } + + public Size ClientSize { get { return window.ClientSize; } } + + public bool Focused { get { return window.Focused; } } + + public bool Exists { get { return window.Exists; } } + + public Point PointToScreen( Point coords ) { + return window.PointToScreen( coords ); + } + + public bool VSync { + get { return window.VSync; } + set { window.VSync = value; } + } + + public bool CursorVisible { + get { return window.CursorVisible; } + set { window.CursorVisible = value; } + } + + public Point DesktopCursorPos { + get { return window.DesktopCursorPos; } + set { window.DesktopCursorPos = value; } + } } } \ No newline at end of file diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs index 32e4ea9bd..c72c0e3f7 100644 --- a/ClassicalSharp/Game/Game.cs +++ b/ClassicalSharp/Game/Game.cs @@ -14,7 +14,6 @@ using ClassicalSharp.Renderers; using ClassicalSharp.Selections; using ClassicalSharp.TexturePack; using OpenTK; -using OpenTK.Graphics; using OpenTK.Input; #if ANDROID using Android.Graphics; @@ -22,7 +21,7 @@ using Android.Graphics; namespace ClassicalSharp { - public partial class Game : GameWindow { + public partial class Game : IDisposable { void LoadAtlas( Bitmap bmp ) { TerrainAtlas1D.Dispose(); @@ -36,7 +35,14 @@ namespace ClassicalSharp { Events.RaiseTerrainAtlasChanged(); } - protected override void OnLoad( EventArgs e ) { + public void Run() { window.Run(); } + + public void Exit() { window.Exit(); } + + + internal void OnLoad() { + Mouse = window.Mouse; + Keyboard = window.Keyboard; #if !USE_DX Graphics = new OpenGLApi(); #else @@ -151,12 +157,11 @@ namespace ClassicalSharp { void LoadIcon() { string launcherPath = Path.Combine( Program.AppDirectory, "Launcher2.exe" ); if( File.Exists( launcherPath ) ) { - Icon = Icon.ExtractAssociatedIcon( launcherPath ); - return; + window.Icon = Icon.ExtractAssociatedIcon( launcherPath ); return; } launcherPath = Path.Combine( Program.AppDirectory, "Launcher.exe" ); if( File.Exists( launcherPath ) ) { - Icon = Icon.ExtractAssociatedIcon( launcherPath ); + window.Icon = Icon.ExtractAssociatedIcon( launcherPath ); } } @@ -185,7 +190,7 @@ namespace ClassicalSharp { } Stopwatch frameTimer = new Stopwatch(); - protected override void OnRenderFrame( FrameEventArgs e ) { + internal void RenderFrame( FrameEventArgs e ) { frameTimer.Reset(); frameTimer.Start(); @@ -196,7 +201,6 @@ namespace ClassicalSharp { if( !Focused && !ScreenLockedInput ) SetNewScreen( new PauseScreen( this ) ); - base.OnRenderFrame( e ); CheckScheduledTasks( e.Time ); float t = (float)( ticksAccumulator / ticksPeriod ); LocalPlayer.SetInterpPosition( t ); @@ -308,8 +312,7 @@ namespace ClassicalSharp { Graphics.SetMatrixMode( MatrixType.Modelview ); } - protected override void OnResize( object sender, EventArgs e ) { - base.OnResize( sender, e ); + internal void OnResize() { Graphics.OnWindowResize( this ); UpdateProjection(); if( activeScreen != null ) @@ -426,7 +429,7 @@ namespace ClassicalSharp { public Key Mapping( KeyBinding mapping ) { return InputHandler.Keys[mapping]; } - public override void Dispose() { + public void Dispose() { MapRenderer.Dispose(); MapBordersRenderer.Dispose(); EnvRenderer.Dispose(); @@ -459,7 +462,6 @@ namespace ClassicalSharp { if( Options.HasChanged ) Options.Save(); - base.Dispose(); } internal bool CanPick( byte block ) { @@ -472,8 +474,8 @@ namespace ClassicalSharp { } public Game( string username, string mppass, string skinServer, - bool nullContext, int width, int height ) - : base( width, height, GraphicsMode.Default, Program.AppName + " (" + username + ")", nullContext, 0, DisplayDevice.Default ) { + bool nullContext, int width, int height ) { + window = new DesktopWindow( this, username, nullContext, width, height ); Username = username; Mppass = mppass; this.skinServer = skinServer; diff --git a/ClassicalSharp/Game/InputHandler.cs b/ClassicalSharp/Game/InputHandler.cs index c37f4cf51..31b26701f 100644 --- a/ClassicalSharp/Game/InputHandler.cs +++ b/ClassicalSharp/Game/InputHandler.cs @@ -20,7 +20,7 @@ namespace ClassicalSharp { void RegisterInputHandlers() { game.Keyboard.KeyDown += KeyDownHandler; game.Keyboard.KeyUp += KeyUpHandler; - game.KeyPress += KeyPressHandler; + game.window.KeyPress += KeyPressHandler; game.Mouse.WheelChanged += MouseWheelChanged; game.Mouse.Move += MouseMove; game.Mouse.ButtonDown += MouseButtonDown; @@ -328,9 +328,9 @@ namespace ClassicalSharp { } else if( key == Keys[KeyBinding.HideFps] ) { game.ShowFPS = !game.ShowFPS; } else if( key == Keys[KeyBinding.Fullscreen] ) { - WindowState state = game.WindowState; + WindowState state = game.window.WindowState; if( state != WindowState.Minimized ) { - game.WindowState = state == WindowState.Fullscreen ? + game.window.WindowState = state == WindowState.Fullscreen ? WindowState.Normal : WindowState.Fullscreen; } } else if( key == Keys[KeyBinding.ShowAxisLines] ) { diff --git a/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs b/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs index 2b9fe6871..32b0c4015 100644 --- a/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs +++ b/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs @@ -32,7 +32,7 @@ namespace ClassicalSharp.GraphicsAPI { public Direct3D9Api( Game game ) { MinZNear = 0.05f; - IntPtr windowHandle = ((WinWindowInfo)game.WindowInfo).WindowHandle; + IntPtr windowHandle = ((WinWindowInfo)game.window.WindowInfo).WindowHandle; d3d = new Direct3D(); int adapter = d3d.Adapters[0].Adapter; InitFields(); @@ -395,11 +395,11 @@ namespace ClassicalSharp.GraphicsAPI { #endregion - public override void BeginFrame( GameWindow game ) { + public override void BeginFrame( Game game ) { device.BeginScene(); } - public override void EndFrame( GameWindow game ) { + public override void EndFrame( Game game ) { device.EndScene(); int code = device.Present(); if( code >= 0 ) return; @@ -426,17 +426,17 @@ namespace ClassicalSharp.GraphicsAPI { } bool vsync = false; - public override void SetVSync( GameWindow game, bool value ) { + public override void SetVSync( Game game, bool value ) { vsync = value; game.VSync = value; RecreateDevice( game ); } - public override void OnWindowResize( GameWindow game ) { + public override void OnWindowResize( Game game ) { RecreateDevice( game ); } - void RecreateDevice( GameWindow game ) { + void RecreateDevice( Game game ) { PresentParameters args = GetPresentArgs( game.Width, game.Height ); for( int i = 0; i < dynamicvBuffers.Length; i++ ) { DynamicDataBuffer buffer = dynamicvBuffers[i]; diff --git a/ClassicalSharp/GraphicsAPI/IGraphicsApi.cs b/ClassicalSharp/GraphicsAPI/IGraphicsApi.cs index 49c4df128..f07b77008 100644 --- a/ClassicalSharp/GraphicsAPI/IGraphicsApi.cs +++ b/ClassicalSharp/GraphicsAPI/IGraphicsApi.cs @@ -218,17 +218,17 @@ namespace ClassicalSharp.GraphicsAPI { } /// Informs the graphic api to update its state in preparation for a new frame. - public abstract void BeginFrame( GameWindow game ); + public abstract void BeginFrame( Game game ); /// Informs the graphic api to update its state in preparation for the end of a frame, /// and to prepare that frame for display on the monitor. - public abstract void EndFrame( GameWindow game ); + public abstract void EndFrame( Game game ); /// Sets whether the graphics api should tie frame rendering to the refresh rate of the monitor. - public abstract void SetVSync( GameWindow game, bool value ); + public abstract void SetVSync( Game game, bool value ); /// Raised when the dimensions of the game's window have changed. - public abstract void OnWindowResize( GameWindow game ); + public abstract void OnWindowResize( Game game ); /// Delegate that is invoked when the current context is lost, /// and is repeatedly invoked until the context can be retrieved. diff --git a/ClassicalSharp/Platform/IPlatformWindow.cs b/ClassicalSharp/Platform/IPlatformWindow.cs new file mode 100644 index 000000000..fe02c7245 --- /dev/null +++ b/ClassicalSharp/Platform/IPlatformWindow.cs @@ -0,0 +1,72 @@ +using System; +using System.Drawing; +using OpenTK; +using OpenTK.Graphics; +using OpenTK.Input; +using OpenTK.Platform; + +namespace ClassicalSharp { + + /// Abstracts away a platform specific window, and input handler mechanism. + public interface IPlatformWindow { + + int Width { get; } + + int Height { get; } + + Size ClientSize { get; } + + bool VSync { get; set; } + + bool Exists { get; } + + bool Focused { get; } + + bool CursorVisible { get; set; } + + Point DesktopCursorPos { get; set; } + + MouseDevice Mouse { get; } + + KeyboardDevice Keyboard { get; } + + Icon Icon { get; set; } + + Point PointToScreen( Point coords ); + + WindowState WindowState { get; set; } + + IWindowInfo WindowInfo { get; } + + void Run(); + + void Exit(); + + event EventHandler KeyPress; + } + + /// Implementation of a native window and native input handling mechanism on Windows, OSX, and Linux. + public sealed class DesktopWindow : GameWindow, IPlatformWindow { + + Game game; + public DesktopWindow( Game game, string username, bool nullContext, int width, int height ) : + base( width, height, GraphicsMode.Default, Program.AppName + " (" + username + ")", nullContext, 0, DisplayDevice.Default ) { + this.game = game; + } + + protected override void OnLoad( EventArgs e ) { + game.OnLoad(); + base.OnLoad( e ); + } + + public override void Dispose() { + game.Dispose(); + base.Dispose(); + } + + protected override void OnRenderFrame( FrameEventArgs e ) { + game.RenderFrame( e ); + base.OnRenderFrame( e ); + } + } +}