diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Texture.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Texture.bf new file mode 100644 index 0000000..153547b --- /dev/null +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Texture.bf @@ -0,0 +1,48 @@ +using System; +using DirectX.D3D11; +using DirectX.Common; +using DirectXTK; + +using internal GlitchyEngine.Renderer; + +namespace GlitchyEngine.Renderer +{ + extension Texture2D + { + internal ID3D11Texture2D* nativeTexture ~ _?.Release(); + internal ID3D11ShaderResourceView* nativeView ~ _?.Release(); + internal Texture2DDescription nativeDesc; + + public override uint32 Width => nativeDesc.Width; + public override uint32 Height => nativeDesc.Height; + public override uint32 ArraySize => nativeDesc.ArraySize; + public override uint32 MipLevels => nativeDesc.MipLevels; + + protected override void LoadTexturePlatform() + { + nativeTexture?.Release(); + nativeView?.Release(); + + HResult loadResult = DDSTextureLoader.CreateDDSTextureFromFile(_context.nativeDevice, _path.ToScopedNativeWChar!(), + (.)&nativeTexture, &nativeView); + + if(loadResult.Failed) + { + Log.EngineLogger.Error($"Failed to load texture \"{_path}\". Error({(int)loadResult}): {loadResult}"); + + nativeTexture?.Release(); + nativeView?.Release(); + + // TODO: load fallback texture + } + + nativeTexture.GetDescription(out nativeDesc); + } + + public override void Bind(uint32 slot) + { + _context.nativeContext.VertexShader.SetShaderResources(slot, 1, &nativeView); + _context.nativeContext.PixelShader.SetShaderResources(slot, 1, &nativeView); + } + } +} diff --git a/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf b/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf index faa1c6b..a9c5ca2 100644 --- a/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf +++ b/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf @@ -1,491 +1,491 @@ -#if GE_WINDOWS -using System; -using DirectX.Common; -using DirectX.Windows; -using DirectX.Windows.Winuser; -using DirectX.Windows.Kernel32; -using DirectX.Windows.WindowMessages; -using GlitchyEngine.Events; -using System.Diagnostics; -using GlitchyEngine.Math; -using GlitchyEngine.Renderer; -using static System.Windows; - -namespace GlitchyEngine -{ - /// The windows specific Window implementation - public extension Window - { - const String WindowClassName = "GlitchyEngineWindow"; - - private Windows.HInstance _instanceHandle; - private Windows.HWnd _windowHandle; - - private WindowClassExW _windowClass; - - private WindowRectangle _clientRect; - - private MinMaxInfo _minMaxInfo; - - private String _title ~ delete _; - - private bool _isVSync = true; - - private GraphicsContext _graphicsContext ~ _?.ReleaseRef(); - - public override GraphicsContext Context => _graphicsContext; - - 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; - } - - // - // Size - // - public override Point Size - { - get => *(Point*)&_clientRect.Width; - - set - { - *(Point*)&_clientRect.Width = value; - ApplyRectangle(); - } - } - - public override int32 Width - { - get => _clientRect.Width; - - set - { - _clientRect.Width = value; - ApplyRectangle(); - } - } - - public override int32 Height - { - get => _clientRect.Height; - - set - { - _clientRect.Height = value; - ApplyRectangle(); - } - } - - // - // Position - // - public override Point Position - { - get => *(Point*)&_clientRect; - - set - { - *(Point*)&_clientRect = value; - ApplyRectangle(); - } - } - - 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 - { - get - { - if (_title == null) - LoadTitle(); - - return _title; - } - - set => SetWindowTextW(_windowHandle, value.ToScopedNativeWChar!()); - } - - public override bool IsVSync - { - get => _isVSync; - set => _isVSync = value; - } - - public override void* NativeWindow => (void*)(int)_windowHandle; - - public override this(WindowDescription desc) - { - _minMaxInfo.MaximumTrackingSize.x = int32.MaxValue; - _minMaxInfo.MaximumTrackingSize.y = int32.MaxValue; - - Init(desc); - } - - [LinkName(.C)] - static extern Windows.IntBool DestroyWindow(Windows.HWnd hWnd); - - [LinkName("UnregisterClassW")] - static extern Windows.IntBool UnregisterClass(char16* className, Windows.HInstance hInstance); - - public ~this() - { - if(!DestroyWindow(_windowHandle)) - { - HResult res = (.)GetLastError(); - Log.EngineLogger.Error($"Failed to destroy window: Message ({(int)res}): {res}"); - } - - UnregisterClass(WindowClassName.ToScopedNativeWChar!(), _instanceHandle); - } - - private void Init(WindowDescription desc) - { - Log.EngineLogger.Trace($"Creating window \"{desc.Title}\" ({desc.Width}, {desc.Height})..."); - - _instanceHandle = (.)GetModuleHandleW(null); - - _windowClass = .(); - _windowClass.Style = .HorizontalRedrawOnChange | .VerticalRedrawOnChange; - _windowClass.WindowProcedure = => MessageHandler; - _windowClass.HInstance = (.)_instanceHandle; - - if (desc.Icon.Ptr != null) - _windowClass.Icon = LoadImageW(0, desc.Icon.ToScopedNativeWChar!(), .Icon, 0, 0, .LoadFromFile); - else - _windowClass.Icon = 0; - - _windowClass.Cursor = LoadCursorW(0, IDC_ARROW); - _windowClass.BackgroundBrush = (HBRUSH)SystemColor.WindowFrame; - _windowClass.ClassName = WindowClassName.ToScopedNativeWChar!(); - - if (RegisterClassExW(ref _windowClass) == 0) - { - uint32 lastError = GetLastError(); - Log.EngineLogger.Error($"Failed to register window class. Message({(int)lastError}): {(HResult)lastError}"); - Runtime.FatalError("Failed to register window class"); - } - - _windowHandle = CreateWindowExW(.None, _windowClass.ClassName, desc.Title.ToScopedNativeWChar!(), .WS_OVERLAPPEDWINDOW | .WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, desc.Width, desc.Height, 0, 0, (.)_instanceHandle, null); - - _graphicsContext = new GraphicsContext(_windowHandle); - _graphicsContext.Init(); - - void* myPtr = Internal.UnsafeCastToPtr(this); - SetWindowLongPtrW(_windowHandle, GWL_USERDATA, (int)myPtr); - - LoadWindowRectangle(); - - Log.EngineLogger.Trace($"Created window \"{Title}\" ({Width}, {Height})"); - } - - private bool _isResizingOrMoving; - private bool _isMinimized; - - [CLink] - static extern IntBool IsWindowUnicode(HWND whnd); - - private static LRESULT MessageHandler(HWND hwnd, uint32 uMsg, WPARAM wParam, LPARAM lParam) - { - void* windowPtr = (void*)GetWindowLongPtrW(hwnd, GWL_USERDATA); - Window window = (Window)Internal.UnsafeCastToObject(windowPtr); - - if (window == null) - { - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } - - ImGui.ImGuiImplWin32.WndProcHandler(hwnd, uMsg, wParam, lParam); - - 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); - - window._graphicsContext.SwapChain.Width = (.)window._clientRect.Width; - window._graphicsContext.SwapChain.Height = (.)window._clientRect.Height; - - window._graphicsContext.SwapChain.ApplyChanges(); - - 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((Key)wParam, (int32)lParam & 0xFFFF); - window._eventCallback(event); - } - case WM_KEYUP: - { - var event = scope KeyReleasedEvent((Key)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 - //// - case WM_CHAR: - { - var event = scope KeyTypedEvent((char16)wParam); - window._eventCallback(event); - - return 0; - } - - // Window title changed - case WM_SETTEXT: - { - // Deletes and nulls _title so that it will be reloaded on the next call of Title.get - delete window._title; - window._title = null; - } - case WM_SYSCOMMAND: - { - /* Remove beeping sound when ALT + some key is pressed. */ - if (wParam == SC_KEYMENU) - return 0; - } - // Window closing - case WM_CLOSE: - { - var event = scope WindowCloseEvent(); - window._eventCallback(event); - - return 0; - } - } - - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } - - public override void Update() - { - Message message = .(); - while (PeekMessageW(&message, 0, 0, 0, .Remove)) - { - TranslateMessage(&message); - DispatchMessageW(&message); - } - } - - private void LoadWindowRectangle() - { - GetClientRect(_windowHandle, let rectangle); - - _clientRect.X = rectangle.Left; - _clientRect.Y = rectangle.Top; - _clientRect.Width = rectangle.Right - rectangle.Left; - _clientRect.Height = rectangle.Bottom - rectangle.Top; - } - - private void ApplyRectangle() - { - SetWindowPos(_windowHandle, 0, _clientRect.X, _clientRect.Y, _clientRect.Width, _clientRect.Height, 0); - } - - [LinkName(.C)] - private static extern IntBool SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int32 X, int32 Y, int32 cx, int32 cy, uint32 uFlags); - - /** - * Gets the window title via WinApi and stores it in _title. - */ - private void LoadTitle() - { - int32 length = GetWindowTextLengthW(_windowHandle) + 1; - - char16[] chars = scope char16[length]; - - Span titleSpan = .(chars, 0, length - 1); - - GetWindowTextW(_windowHandle, chars.CArray(), length); - - _title = new String(titleSpan); - } - } -} +#if GE_WINDOWS +using System; +using DirectX.Common; +using DirectX.Windows; +using DirectX.Windows.Winuser; +using DirectX.Windows.Kernel32; +using DirectX.Windows.WindowMessages; +using GlitchyEngine.Events; +using System.Diagnostics; +using GlitchyEngine.Math; +using GlitchyEngine.Renderer; +using static System.Windows; + +namespace GlitchyEngine +{ + /// The windows specific Window implementation + public extension Window + { + const String WindowClassName = "GlitchyEngineWindow"; + + private Windows.HInstance _instanceHandle; + private Windows.HWnd _windowHandle; + + private WindowClassExW _windowClass; + + private WindowRectangle _clientRect; + + private MinMaxInfo _minMaxInfo; + + private String _title ~ delete _; + + private bool _isVSync = true; + + private GraphicsContext _graphicsContext ~ _?.ReleaseRef(); + + public override GraphicsContext Context => _graphicsContext; + + 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; + } + + // + // Size + // + public override Point Size + { + get => *(Point*)&_clientRect.Width; + + set + { + *(Point*)&_clientRect.Width = value; + ApplyRectangle(); + } + } + + public override int32 Width + { + get => _clientRect.Width; + + set + { + _clientRect.Width = value; + ApplyRectangle(); + } + } + + public override int32 Height + { + get => _clientRect.Height; + + set + { + _clientRect.Height = value; + ApplyRectangle(); + } + } + + // + // Position + // + public override Point Position + { + get => *(Point*)&_clientRect; + + set + { + *(Point*)&_clientRect = value; + ApplyRectangle(); + } + } + + 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 + { + get + { + if (_title == null) + LoadTitle(); + + return _title; + } + + set => SetWindowTextW(_windowHandle, value.ToScopedNativeWChar!()); + } + + public override bool IsVSync + { + get => _isVSync; + set => _isVSync = value; + } + + public override void* NativeWindow => (void*)(int)_windowHandle; + + public override this(WindowDescription desc) + { + _minMaxInfo.MaximumTrackingSize.x = int32.MaxValue; + _minMaxInfo.MaximumTrackingSize.y = int32.MaxValue; + + Init(desc); + } + + [LinkName(.C)] + static extern Windows.IntBool DestroyWindow(Windows.HWnd hWnd); + + [LinkName("UnregisterClassW")] + static extern Windows.IntBool UnregisterClass(char16* className, Windows.HInstance hInstance); + + public ~this() + { + if(!DestroyWindow(_windowHandle)) + { + HResult res = (.)GetLastError(); + Log.EngineLogger.Error($"Failed to destroy window: Message ({(int)res}): {res}"); + } + + UnregisterClass(WindowClassName.ToScopedNativeWChar!(), _instanceHandle); + } + + private void Init(WindowDescription desc) + { + Log.EngineLogger.Trace($"Creating window \"{desc.Title}\" ({desc.Width}, {desc.Height})..."); + + _instanceHandle = (.)GetModuleHandleW(null); + + _windowClass = .(); + _windowClass.Style = .HorizontalRedrawOnChange | .VerticalRedrawOnChange; + _windowClass.WindowProcedure = => MessageHandler; + _windowClass.HInstance = (.)_instanceHandle; + + if (desc.Icon.Ptr != null) + _windowClass.Icon = LoadImageW(0, desc.Icon.ToScopedNativeWChar!(), .Icon, 0, 0, .LoadFromFile); + else + _windowClass.Icon = 0; + + _windowClass.Cursor = LoadCursorW(0, IDC_ARROW); + _windowClass.BackgroundBrush = (HBRUSH)SystemColor.WindowFrame; + _windowClass.ClassName = WindowClassName.ToScopedNativeWChar!(); + + if (RegisterClassExW(ref _windowClass) == 0) + { + uint32 lastError = GetLastError(); + Log.EngineLogger.Error($"Failed to register window class. Message({(int)lastError}): {(HResult)lastError}"); + Runtime.FatalError("Failed to register window class"); + } + + _windowHandle = CreateWindowExW(.None, _windowClass.ClassName, desc.Title.ToScopedNativeWChar!(), .WS_OVERLAPPEDWINDOW | .WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, desc.Width, desc.Height, 0, 0, (.)_instanceHandle, null); + + _graphicsContext = new GraphicsContext(_windowHandle); + _graphicsContext.Init(); + + void* myPtr = Internal.UnsafeCastToPtr(this); + SetWindowLongPtrW(_windowHandle, GWL_USERDATA, (int)myPtr); + + LoadWindowRectangle(); + + Log.EngineLogger.Trace($"Created window \"{Title}\" ({Width}, {Height})"); + } + + private bool _isResizingOrMoving; + private bool _isMinimized; + + [CLink] + static extern IntBool IsWindowUnicode(HWND whnd); + + private static LRESULT MessageHandler(HWND hwnd, uint32 uMsg, WPARAM wParam, LPARAM lParam) + { + void* windowPtr = (void*)GetWindowLongPtrW(hwnd, GWL_USERDATA); + Window window = (Window)Internal.UnsafeCastToObject(windowPtr); + + if (window == null) + { + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + + ImGui.ImGuiImplWin32.WndProcHandler(hwnd, uMsg, wParam, lParam); + + 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); + + window._graphicsContext.SwapChain.Width = (.)window._clientRect.Width; + window._graphicsContext.SwapChain.Height = (.)window._clientRect.Height; + + window._graphicsContext.SwapChain.ApplyChanges(); + + 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((Key)wParam, (int32)lParam & 0xFFFF); + window._eventCallback(event); + } + case WM_KEYUP: + { + var event = scope KeyReleasedEvent((Key)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 + //// + case WM_CHAR: + { + var event = scope KeyTypedEvent((char16)wParam); + window._eventCallback(event); + + return 0; + } + + // Window title changed + case WM_SETTEXT: + { + // Deletes and nulls _title so that it will be reloaded on the next call of Title.get + delete window._title; + window._title = null; + } + case WM_SYSCOMMAND: + { + /* Remove beeping sound when ALT + some key is pressed. */ + if (wParam == SC_KEYMENU) + return 0; + } + // Window closing + case WM_CLOSE: + { + var event = scope WindowCloseEvent(); + window._eventCallback(event); + + return 0; + } + } + + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + + public override void Update() + { + Message message = .(); + while (PeekMessageW(&message, 0, 0, 0, .Remove)) + { + TranslateMessage(&message); + DispatchMessageW(&message); + } + } + + private void LoadWindowRectangle() + { + GetClientRect(_windowHandle, let rectangle); + + _clientRect.X = rectangle.Left; + _clientRect.Y = rectangle.Top; + _clientRect.Width = rectangle.Right - rectangle.Left; + _clientRect.Height = rectangle.Bottom - rectangle.Top; + } + + private void ApplyRectangle() + { + SetWindowPos(_windowHandle, 0, _clientRect.X, _clientRect.Y, _clientRect.Width, _clientRect.Height, 0); + } + + [LinkName(.C)] + private static extern IntBool SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int32 X, int32 Y, int32 cx, int32 cy, uint32 uFlags); + + /** + * Gets the window title via WinApi and stores it in _title. + */ + private void LoadTitle() + { + int32 length = GetWindowTextLengthW(_windowHandle) + 1; + + char16[] chars = scope char16[length]; + + Span titleSpan = .(chars, 0, length - 1); + + GetWindowTextW(_windowHandle, chars.CArray(), length); + + _title = new String(titleSpan); + } + } +} #endif \ No newline at end of file diff --git a/GlitchyEngine/src/Renderer/Texture.bf b/GlitchyEngine/src/Renderer/Texture.bf new file mode 100644 index 0000000..5cc05a2 --- /dev/null +++ b/GlitchyEngine/src/Renderer/Texture.bf @@ -0,0 +1,45 @@ +using System; + +namespace GlitchyEngine.Renderer +{ + public abstract class Texture : RefCounted + { + protected GraphicsContext _context ~ _?.ReleaseRef(); + + public GraphicsContext Context => _context; + + public abstract uint32 Width {get;} + public abstract uint32 Height {get;} + public abstract uint32 Depth {get;} + public abstract uint32 ArraySize {get;} + public abstract uint32 MipLevels {get;} + + public abstract void Bind(uint32 slot = 0); + + protected this(GraphicsContext context) + { + _context = context..AddRef(); + } + } + + public class Texture2D : Texture + { + protected String _path ~ delete _; + + public override extern uint32 Width {get;} + public override extern uint32 Height {get;} + public override uint32 Depth => 1; + public override extern uint32 ArraySize {get;} + public override extern uint32 MipLevels {get;} + + public override extern void Bind(uint32 slot = 0); + + public this(GraphicsContext context, String path) : base(context) + { + this._path = new String(path); + LoadTexturePlatform(); + } + + protected extern void LoadTexturePlatform(); + } +} diff --git a/GlitchyEngine/vendor/DirectXTK b/GlitchyEngine/vendor/DirectXTK index 8fc6870..b53d2f1 160000 --- a/GlitchyEngine/vendor/DirectXTK +++ b/GlitchyEngine/vendor/DirectXTK @@ -1 +1 @@ -Subproject commit 8fc6870ac07d0fd7d0ef9e62bc104316f8bf4ad6 +Subproject commit b53d2f196e0ac3e7f80ace135199e80a682d79c4 diff --git a/Sandbox/content/Textures/Checkerboard.dds b/Sandbox/content/Textures/Checkerboard.dds new file mode 100644 index 0000000..3b90b02 Binary files /dev/null and b/Sandbox/content/Textures/Checkerboard.dds differ diff --git a/Sandbox/content/basicShader.hlsl b/Sandbox/content/basicShader.hlsl index 9ab791a..3d9d8df 100644 --- a/Sandbox/content/basicShader.hlsl +++ b/Sandbox/content/basicShader.hlsl @@ -11,7 +11,6 @@ cbuffer ObjectConstants float4x4 Transform; } - cbuffer Constants { float4 BaseColor; diff --git a/Sandbox/content/textureShader.hlsl b/Sandbox/content/textureShader.hlsl new file mode 100644 index 0000000..b2feb65 --- /dev/null +++ b/Sandbox/content/textureShader.hlsl @@ -0,0 +1,53 @@ +Texture2D ColorTexture; + +SamplerState TextureSampler; + +cbuffer SceneConstants +{ + float4x4 ViewProjection = float4x4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); +} + +cbuffer ObjectConstants +{ + float4x4 Transform; +} + +cbuffer Constants +{ + float4 BaseColor; +} + +struct VS_IN +{ + float3 Position : POSITION; + float4 Color : COLOR; + float2 TexCoord : TEXCOORD; +}; + +struct PS_IN +{ + float4 Position : SV_POSITION; + float4 Color : COLOR; + float2 TexCoord : TEXCOORD; +}; + +PS_IN VS(VS_IN input) +{ + PS_IN output; + + float4 worldPosition = mul(Transform, float4(input.Position, 1)); + + output.Position = mul(ViewProjection, worldPosition); + output.Color = input.Color; + output.TexCoord = input.TexCoord; + + return output; +} + +float4 PS(PS_IN input) : SV_TARGET +{ + return input.Color * ColorTexture.Sample(TextureSampler, input.TexCoord); +} \ No newline at end of file diff --git a/Sandbox/src/SandboxApp.bf b/Sandbox/src/SandboxApp.bf index a9c6079..3cd88a3 100644 --- a/Sandbox/src/SandboxApp.bf +++ b/Sandbox/src/SandboxApp.bf @@ -13,11 +13,13 @@ namespace Sandbox class ExampleLayer : Layer { private OrthographicCamera _camera ~ delete _; // PerspectiveCamera - - struct VertexColor : IVertexData + + [Ordered] + struct VertexColorTexture : IVertexData { public Vector3 Position; public Color Color; + public Vector2 TexCoord; public this() => this = default; @@ -25,6 +27,14 @@ namespace Sandbox { Position = pos; Color = color; + TexCoord = .(); + } + + public this(Vector3 pos, Color color, Vector2 texCoord) + { + Position = pos; + Color = color; + TexCoord = texCoord; } //public static readonly InputElementDescription[] InputLayout ~ delete _; @@ -52,11 +62,14 @@ namespace Sandbox RasterizerState _rasterizerState ~ delete _; Effect _effect ~ _?.ReleaseRef(); + Effect _textureEffect ~ _?.ReleaseRef(); ConstantBuffer _cBuffer ~ _?.ReleaseRef(); GraphicsContext _context ~ _?.ReleaseRef(); + Texture2D _texture ~ _?.ReleaseRef(); + private Vector3 CircleCoord(float angle) { return .(Math.Cos(angle), Math.Sin(angle), 0); @@ -79,12 +92,25 @@ namespace Sandbox ps.ReleaseRef(); } + { + _textureEffect = new Effect(); + + let vs = Shader.FromFile!(_context, "content\\textureShader.hlsl", "VS"); + _textureEffect.VertexShader = vs; + vs.ReleaseRef(); + + let ps = Shader.FromFile!(_context, "content\\textureShader.hlsl", "PS"); + _textureEffect.PixelShader = ps; + ps.ReleaseRef(); + } + // Create Input Layout _vertexLayout = new VertexLayout(_context, new .( VertexElement(.R32G32B32_Float, "POSITION"), VertexElement(.R8G8B8A8_UNorm, "COLOR"), - ), _effect.VertexShader); + VertexElement(.R32G32_Float, "TEXCOORD"), + ), _textureEffect.VertexShader); _cBuffer = _effect.PixelShader.Buffers["Constants"] as ConstantBuffer; @@ -97,17 +123,17 @@ namespace Sandbox _geometryBinding.SetVertexLayout(_vertexLayout); float pO3 = Math.PI_f / 3.0f; - VertexColor[?] vertices = .( - VertexColor(.Zero, Color(255,255,255)), - VertexColor(CircleCoord(0), Color(255, 0, 0)), - VertexColor(CircleCoord(pO3), Color(255,255, 0)), - VertexColor(CircleCoord(pO3*2), Color( 0,255, 0)), - VertexColor(CircleCoord(Math.PI_f), Color( 0,255,255)), - VertexColor(CircleCoord(-pO3*2), Color( 0, 0,255)), - VertexColor(CircleCoord(-pO3), Color(255, 0,255)), + VertexColorTexture[?] vertices = .( + VertexColorTexture(.Zero, Color(255,255,255)), + VertexColorTexture(CircleCoord(0), Color(255, 0, 0)), + VertexColorTexture(CircleCoord(pO3), Color(255,255, 0)), + VertexColorTexture(CircleCoord(pO3*2), Color( 0,255, 0)), + VertexColorTexture(CircleCoord(Math.PI_f), Color( 0,255,255)), + VertexColorTexture(CircleCoord(-pO3*2), Color( 0, 0,255)), + VertexColorTexture(CircleCoord(-pO3), Color(255, 0,255)), ); - _vertexBuffer = new VertexBuffer(_context, typeof(VertexColor), (.)vertices.Count, .Immutable); + _vertexBuffer = new VertexBuffer(_context, typeof(VertexColorTexture), (.)vertices.Count, .Immutable); _vertexBuffer.SetData(vertices); _geometryBinding.SetVertexBufferSlot(_vertexBuffer, 0); @@ -130,14 +156,14 @@ namespace Sandbox _quadGeometryBinding.SetPrimitiveTopology(.TriangleList); _quadGeometryBinding.SetVertexLayout(_vertexLayout); - VertexColor[?] vertices = .( - VertexColor(Vector3(-0.75f, 0.75f, 0), Color.White), - VertexColor(Vector3(-0.75f, -0.75f, 0), Color.White), - VertexColor(Vector3(0.75f, -0.75f, 0), Color.White), - VertexColor(Vector3(0.75f, 0.75f, 0), Color.White), + VertexColorTexture[?] vertices = .( + VertexColorTexture(Vector3(-0.75f, 0.75f, 0), Color.White, .(0, 0)), + VertexColorTexture(Vector3(-0.75f, -0.75f, 0), Color.White, .(0, 1)), + VertexColorTexture(Vector3(0.75f, -0.75f, 0), Color.White, .(1, 1)), + VertexColorTexture(Vector3(0.75f, 0.75f, 0), Color.White, .(1, 0)), ); - _quadVertexBuffer = new VertexBuffer(_context, typeof(VertexColor), (.)vertices.Count, .Immutable); + _quadVertexBuffer = new VertexBuffer(_context, typeof(VertexColorTexture), (.)vertices.Count, .Immutable); _quadVertexBuffer.SetData(vertices); _quadGeometryBinding.SetVertexBufferSlot(_quadVertexBuffer, 0); @@ -165,6 +191,8 @@ namespace Sandbox _camera.FovY = Math.PI_f / 4; _camera.Position = .(0, -1, -5); */ + + _texture = new Texture2D(_context, "content/Textures/Checkerboard.dds"); } public override void Update(GameTime gameTime) @@ -216,12 +244,6 @@ namespace Sandbox Renderer.BeginScene(_camera); - _cBuffer["BaseColor"].SetData(ColorRGBA.White); - _cBuffer.Update(); - - Renderer.Submit(_geometryBinding, _effect); - Renderer.Submit(_quadGeometryBinding, _effect, .Translation(2, 0, 0)); - for(int x < 20) for(int y < 20) { @@ -235,6 +257,14 @@ namespace Sandbox Matrix transform = Matrix.Translation(x * 0.2f, y * 0.2f, 0) * Matrix.Scaling(0.1f); Renderer.Submit(_quadGeometryBinding, _effect, transform); } + + _cBuffer["BaseColor"].SetData(ColorRGBA.White); + _cBuffer.Update(); + + _texture.Bind(); + + Renderer.Submit(_geometryBinding, _effect); + Renderer.Submit(_quadGeometryBinding, _textureEffect, .Scaling(1.5f)); Renderer.EndScene(); }