Implemented WindowsWindow and EventCallback

This commit is contained in:
Simon Lübeß
2020-11-08 18:21:54 +01:00
parent 634f310b7f
commit aa2165ef77
4 changed files with 331 additions and 44 deletions
+17 -3
View File
@@ -1,11 +1,12 @@
using GlitchyEngine.Platform.Windows; using GlitchyEngine.Platform.Windows;
using GlitchyEngine.Events;
namespace GlitchyEngine namespace GlitchyEngine
{ {
public class Application public class Application
{ {
private Window _window ~ delete _; private Window _window ~ delete _;
private bool _running; private bool _running = true;
public bool IsRunning => _running; public bool IsRunning => _running;
@@ -13,16 +14,29 @@ namespace GlitchyEngine
{ {
// Todo: make Platform independent // Todo: make Platform independent
_window = new WindowsWindow(WindowDescription()); _window = new WindowsWindow(WindowDescription());
_window.EventCallback = new => OnEvent;
} }
public void Run() public void Run()
{ {
_running = true;
while(_running) while(_running)
{ {
_window.Update(); _window.Update();
} }
} }
public void OnEvent(Event e)
{
EventDispatcher dispatcher = scope .(e);
dispatcher.Dispatch<WindowCloseEvent>(scope => OnWindowClose);
Log.EngineLogger.Trace("{}", e);
}
public bool OnWindowClose(WindowCloseEvent e)
{
_running = false;
return true;
}
} }
} }
@@ -4,28 +4,11 @@ using DirectX.Windows;
using DirectX.Windows.Winuser; using DirectX.Windows.Winuser;
using DirectX.Windows.Kernel32; using DirectX.Windows.Kernel32;
using DirectX.Windows.WindowMessages; using DirectX.Windows.WindowMessages;
using GlitchyEngine.Events;
using System.Diagnostics;
namespace GlitchyEngine.Platform.Windows namespace GlitchyEngine.Platform.Windows
{ {
[CRepr]
public struct WindowRectangle
{
public int32 X;
public int32 Y;
public int32 Width;
public int32 Height;
public this() => this = default;
public this(int32 x, int32 y, int32 width, int32 height)
{
X = x;
Y = y;
Width = width;
Height = height;
}
}
public class WindowsWindow : Window public class WindowsWindow : Window
{ {
private Windows.HInstance _instanceHandle; private Windows.HInstance _instanceHandle;
@@ -33,31 +16,78 @@ namespace GlitchyEngine.Platform.Windows
private WindowClassExW _windowClass; private WindowClassExW _windowClass;
private WindowRectangle _rect; private WindowRectangle _clientRect;
private MinMaxInfo _minMaxInfo;
private String _title ~ delete _;
public override int32 MinWidth
{
get => _minMaxInfo.MinimumTrackingSize.x;
set => _minMaxInfo.MinimumTrackingSize.x = value;
}
public override int32 MinHeight
{
get => _minMaxInfo.MinimumTrackingSize.y;
set => _minMaxInfo.MinimumTrackingSize.y = value;
}
public override int32 MaxWidth
{
get => _minMaxInfo.MaximumTrackingSize.x;
set => _minMaxInfo.MaximumTrackingSize.x = value;
}
public override int32 MaxHeight
{
get => _minMaxInfo.MaximumTrackingSize.y;
set => _minMaxInfo.MaximumTrackingSize.y = value;
}
public override int32 Width public override int32 Width
{ {
get => _rect.Width; get => _clientRect.Width;
set set
{ {
_rect.Width = value; _clientRect.Width = value;
ApplyRectangle(); ApplyRectangle();
} }
} }
public override int32 Height public override int32 Height
{ {
get => _rect.Height; get => _clientRect.Height;
set set
{ {
_rect.Height = value; _clientRect.Height = value;
ApplyRectangle(); ApplyRectangle();
} }
} }
private String _title; public override int32 PositionX
{
get => _clientRect.X;
set
{
_clientRect.X = value;
ApplyRectangle();
}
}
public override int32 PositionY
{
get => _clientRect.Y;
set
{
_clientRect.Y = value;
ApplyRectangle();
}
}
public override StringView Title public override StringView Title
{ {
@@ -80,14 +110,12 @@ namespace GlitchyEngine.Platform.Windows
public this(WindowDescription desc) public this(WindowDescription desc)
{ {
_minMaxInfo.MaximumTrackingSize.x = int32.MaxValue;
_minMaxInfo.MaximumTrackingSize.y = int32.MaxValue;
Init(desc); Init(desc);
} }
public ~this()
{
}
private void Init(WindowDescription desc) private void Init(WindowDescription desc)
{ {
Log.EngineLogger.Trace("Creating window \"{}\" ({}, {})...", desc.Title, desc.Width, desc.Height); Log.EngineLogger.Trace("Creating window \"{}\" ({}, {})...", desc.Title, desc.Width, desc.Height);
@@ -97,7 +125,7 @@ namespace GlitchyEngine.Platform.Windows
_windowClass = .(); _windowClass = .();
_windowClass.Style = .HorizontalRedrawOnChange | .VerticalRedrawOnChange; _windowClass.Style = .HorizontalRedrawOnChange | .VerticalRedrawOnChange;
_windowClass.WindowProcedure = => MessageHandler; _windowClass.WindowProcedure = => MessageHandler;
_windowClass.HInstance = _instanceHandle; _windowClass.HInstance = (.)_instanceHandle;
if(desc.Icon.Ptr != null) if(desc.Icon.Ptr != null)
_windowClass.Icon = LoadImageW(0, desc.Icon.ToScopedNativeWChar!(), .Icon, 0, 0, .LoadFromFile); _windowClass.Icon = LoadImageW(0, desc.Icon.ToScopedNativeWChar!(), .Icon, 0, 0, .LoadFromFile);
@@ -115,7 +143,7 @@ namespace GlitchyEngine.Platform.Windows
} }
_windowHandle = CreateWindowExW(.None, _windowClass.ClassName, desc.Title.ToScopedNativeWChar!(), .WS_OVERLAPPEDWINDOW | .WS_VISIBLE, _windowHandle = CreateWindowExW(.None, _windowClass.ClassName, desc.Title.ToScopedNativeWChar!(), .WS_OVERLAPPEDWINDOW | .WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, desc.Width, desc.Height, 0, 0, _instanceHandle, null); CW_USEDEFAULT, CW_USEDEFAULT, desc.Width, desc.Height, 0, 0, (.)_instanceHandle, null);
void* myPtr = Internal.UnsafeCastToPtr(this); void* myPtr = Internal.UnsafeCastToPtr(this);
@@ -126,13 +154,189 @@ namespace GlitchyEngine.Platform.Windows
Log.EngineLogger.Trace("Created window \"{}\" ({}, {})", Title, Width, Height); Log.EngineLogger.Trace("Created window \"{}\" ({}, {})", Title, Width, Height);
} }
private bool _isResizingOrMoving;
private bool _isMinimized;
private static LRESULT MessageHandler(HWND hwnd, uint32 uMsg, WPARAM wParam, LPARAM lParam) private static LRESULT MessageHandler(HWND hwnd, uint32 uMsg, WPARAM wParam, LPARAM lParam)
{ {
void* windowPtr = (void*)GetWindowLongPtrW(hwnd, GWL_USERDATA); void* windowPtr = (void*)GetWindowLongPtrW(hwnd, GWL_USERDATA);
WindowsWindow window = (WindowsWindow)Internal.UnsafeCastToObject(windowPtr); WindowsWindow window = (WindowsWindow)Internal.UnsafeCastToObject(windowPtr);
if(window == null)
{
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
switch(uMsg) switch(uMsg)
{ {
////
//// Sizing and Moving
////
// Window min/max size requested
case WM_GETMINMAXINFO:
{
MinMaxInfo *info = (.)(void*)lParam;
info.MinimumTrackingSize = window._minMaxInfo.MinimumTrackingSize;
info.MaximumTrackingSize = window._minMaxInfo.MaximumTrackingSize;
}
// Window size changed
case WM_SIZE:
{
if(wParam == (.)ResizingType.Minimized)
{
window._isMinimized = true;
}
else if (window._isMinimized)
{
window._isMinimized = false;
}
else
{
SplitHighAndLowOrder!(lParam, out window._clientRect.Width, out window._clientRect.Height);
WindowResizeEvent event = scope WindowResizeEvent(window._clientRect.Width, window._clientRect.Height, window._isResizingOrMoving);
window._eventCallback(event);
}
}
// Window position changed
case WM_MOVE:
{
if(wParam == (.)ResizingType.Minimized)
{
window._isMinimized = true;
}
else if (window._isMinimized)
{
window._isMinimized = false;
}
else
{
SplitHighAndLowOrder!(lParam, out window._clientRect.X, out window._clientRect.Y);
var event = scope WindowMoveEvent(window._clientRect.X, window._clientRect.Y, window._isResizingOrMoving);
window._eventCallback(event);
}
}
// Window resizing/moving started
case WM_ENTERSIZEMOVE:
window._isResizingOrMoving = true;
// Window resizing/moving ended
case WM_EXITSIZEMOVE:
{
window._isResizingOrMoving = false;
var resEvent = scope WindowResizeEvent(window._clientRect.Width, window._clientRect.Height, false);
window._eventCallback(resEvent);
var moveEvent = scope WindowMoveEvent(window._clientRect.X, window._clientRect.Y, false);
window._eventCallback(moveEvent);
}
////
//// Keyboard input
////
case WM_KEYDOWN:
{
var event = scope KeyPressedEvent((int32)wParam, (int32)lParam & 0xFFFF);
window._eventCallback(event);
}
case WM_KEYUP:
{
var event = scope KeyReleasedEvent((int32)wParam);
window._eventCallback(event);
}
////
//// Mouse input
////
// Left mouse button
case WM_LBUTTONDOWN:
{
var event = scope MouseButtonPressedEvent(.LeftButton);
window._eventCallback(event);
}
case WM_LBUTTONUP:
{
var event = scope MouseButtonReleasedEvent(.LeftButton);
window._eventCallback(event);
}
// Right mouse button
case WM_RBUTTONDOWN:
{
var event = scope MouseButtonPressedEvent(.RightButton);
window._eventCallback(event);
}
case WM_RBUTTONUP:
{
var event = scope MouseButtonReleasedEvent(.RightButton);
window._eventCallback(event);
}
// Middle mouse button
case WM_MBUTTONDOWN:
{
var event = scope MouseButtonPressedEvent(.MiddleButton);
window._eventCallback(event);
}
case WM_MBUTTONUP:
{
var event = scope MouseButtonReleasedEvent(.MiddleButton);
window._eventCallback(event);
}
// X button
case WM_XBUTTONDOWN:
{
MouseButton button = .None;
if(HighOrder!((int64)wParam) == 1)
button = .XButton1;
else
button = .XButton2;
var event = scope MouseButtonPressedEvent(button);
window._eventCallback(event);
}
case WM_XBUTTONUP:
{
MouseButton button = .None;
if(HighOrder!((int64)wParam) == 1)
button = .XButton1;
else
button = .XButton2;
var event = scope MouseButtonReleasedEvent(button);
window._eventCallback(event);
}
// Vertical scrolling
case WM_MOUSEWHEEL:
{
int32 rotation = (int16)HighOrder!((int64)wParam) / WHEEL_DELTA;
var event = scope MouseScrolledEvent(0, rotation);
window._eventCallback(event);
}
// Horizontal scrolling
case WM_MOUSEHWHEEL:
{
int32 rotation = (int16)HighOrder!((int64)wParam) / WHEEL_DELTA;
var event = scope MouseScrolledEvent(rotation, 0);
window._eventCallback(event);
}
case WM_MOUSEMOVE:
{
SplitHighAndLowOrder!(lParam, let x, let y);
var event = scope MouseMovedEvent(x, y);
window._eventCallback(event);
}
// Todo: DirectInput
////
//// Application
////
// Window title changed // Window title changed
case WM_SETTEXT: case WM_SETTEXT:
{ {
@@ -140,12 +344,21 @@ namespace GlitchyEngine.Platform.Windows
delete window._title; delete window._title;
window._title = null; window._title = null;
} }
case WM_SYSCOMMAND:
{
/* Remove beeping sound when ALT + some key is pressed. */
if ( wParam == SC_KEYMENU )
{
return 0;
}
}
// Window closing // Window closing
case WM_CLOSE, WM_DESTROY: case WM_CLOSE:
{ {
// Todo: fire closing event!
PostQuitMessage(0); PostQuitMessage(0);
Environment.Exit(0);
var event = scope WindowCloseEvent();
window._eventCallback(event);
} }
} }
@@ -166,15 +379,15 @@ namespace GlitchyEngine.Platform.Windows
{ {
GetWindowRect(_windowHandle, let rectangle); GetWindowRect(_windowHandle, let rectangle);
_rect.X = rectangle.Left; _clientRect.X = rectangle.Left;
_rect.Y = rectangle.Top; _clientRect.Y = rectangle.Top;
_rect.Width = rectangle.Right - rectangle.Left; _clientRect.Width = rectangle.Right - rectangle.Left;
_rect.Height = rectangle.Bottom - rectangle.Top; _clientRect.Height = rectangle.Bottom - rectangle.Top;
} }
private void ApplyRectangle() private void ApplyRectangle()
{ {
SetWindowPos(_windowHandle, 0, _rect.X, _rect.Y, _rect.Width, _rect.Height, 0); SetWindowPos(_windowHandle, 0, _clientRect.X, _clientRect.Y, _clientRect.Width, _clientRect.Height, 0);
} }
/** /**
+38 -1
View File
@@ -1,4 +1,6 @@
using System; using System;
using GlitchyEngine.Events;
namespace GlitchyEngine namespace GlitchyEngine
{ {
public struct WindowDescription public struct WindowDescription
@@ -28,7 +30,27 @@ namespace GlitchyEngine
// Todo: interface? // Todo: interface?
public abstract class Window public abstract class Window
{ {
// Todo: callback/events? public delegate void EventCallback(Event e);
protected EventCallback _eventCallback ~ delete _;
/**
* Gets or Sets the minimum width of the window.
*/
public abstract int32 MinWidth {get; set;}
/**
* Gets or Sets the minimum height of the window.
*/
public abstract int32 MinHeight {get; set;}
/**
* Gets or Sets the maximum width of the window.
*/
public abstract int32 MaxWidth {get; set;}
/**
* Gets or Sets the maximum height of the window.
*/
public abstract int32 MaxHeight {get; set;}
/** /**
* Gets or Sets the width of the window. * Gets or Sets the width of the window.
@@ -38,6 +60,15 @@ namespace GlitchyEngine
* Gets or Sets the height of the window. * Gets or Sets the height of the window.
*/ */
public abstract int32 Height {get; set;} public abstract int32 Height {get; set;}
/**
* Gets or Sets the x-coordinate of the upper-left corner of the client area of the window.
*/
public abstract int32 PositionX {get; set;}
/**
* Gets or Sets the y-coordinate of the upper-left corner of the client area of the window.
*/
public abstract int32 PositionY {get; set;}
/** /**
* Gets or Sets the windows title. * Gets or Sets the windows title.
*/ */
@@ -48,6 +79,12 @@ namespace GlitchyEngine
*/ */
public abstract bool IsVSync {get; set;} public abstract bool IsVSync {get; set;}
public EventCallback EventCallback
{
get => _eventCallback;
set => _eventCallback = value;
}
public abstract void Update(); public abstract void Update();
} }
} }
+23
View File
@@ -0,0 +1,23 @@
using System;
namespace GlitchyEngine
{
[CRepr]
public struct WindowRectangle
{
public int32 X;
public int32 Y;
public int32 Width;
public int32 Height;
public this() => this = default;
public this(int32 x, int32 y, int32 width, int32 height)
{
X = x;
Y = y;
Width = width;
Height = height;
}
}
}