diff options
| author | Yong He <yonghe@outlook.com> | 2021-03-08 10:01:20 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-08 10:01:20 -0800 |
| commit | fc9968dc4fd58fab37476f48e4405c2743c5349c (patch) | |
| tree | 6119b293a5a5cc24401dde5ff54287beb28fe63b /tools | |
| parent | 95ca93938f5d45f4eaf340867965bd77a1724d6c (diff) | |
Refactor window library. (#1739)
* Refactor window library.
* Fix project file
* Fix warnings.
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/graphics-app-framework/gui.h | 31 | ||||
| -rw-r--r-- | tools/graphics-app-framework/window.h | 133 | ||||
| -rw-r--r-- | tools/graphics-app-framework/windows/win-window.cpp | 416 | ||||
| -rw-r--r-- | tools/platform/gui.cpp (renamed from tools/graphics-app-framework/gui.cpp) | 8 | ||||
| -rw-r--r-- | tools/platform/gui.h | 34 | ||||
| -rw-r--r-- | tools/platform/model.cpp (renamed from tools/graphics-app-framework/model.cpp) | 2 | ||||
| -rw-r--r-- | tools/platform/model.h (renamed from tools/graphics-app-framework/model.h) | 0 | ||||
| -rw-r--r-- | tools/platform/performance-counter.h | 30 | ||||
| -rw-r--r-- | tools/platform/vector-math.h (renamed from tools/graphics-app-framework/vector-math.h) | 0 | ||||
| -rw-r--r-- | tools/platform/window.h | 235 | ||||
| -rw-r--r-- | tools/platform/windows/win-window.cpp | 442 |
11 files changed, 747 insertions, 584 deletions
diff --git a/tools/graphics-app-framework/gui.h b/tools/graphics-app-framework/gui.h deleted file mode 100644 index 680cea14b..000000000 --- a/tools/graphics-app-framework/gui.h +++ /dev/null @@ -1,31 +0,0 @@ -// gui.h -#pragma once - -#include "slang-gfx.h" -#include "vector-math.h" -#include "window.h" -#include "slang-com-ptr.h" -#include "external/imgui/imgui.h" -#include "source/core/slang-basic.h" - -namespace gfx { - -struct GUI : Slang::RefObject -{ - GUI(Window* window, IRenderer* renderer, ICommandQueue* queue, IFramebufferLayout* framebufferLayout); - ~GUI(); - - void beginFrame(); - void endFrame(IFramebuffer* framebuffer); - -private: - Slang::ComPtr<IRenderer> renderer; - Slang::ComPtr<ICommandQueue> queue; - Slang::ComPtr<IRenderPassLayout> renderPass; - Slang::ComPtr<IPipelineState> pipelineState; - Slang::ComPtr<IDescriptorSetLayout> descriptorSetLayout; - Slang::ComPtr<IPipelineLayout> pipelineLayout; - Slang::ComPtr<ISamplerState> samplerState; -}; - -} // gfx diff --git a/tools/graphics-app-framework/window.h b/tools/graphics-app-framework/window.h deleted file mode 100644 index 2e216aacf..000000000 --- a/tools/graphics-app-framework/window.h +++ /dev/null @@ -1,133 +0,0 @@ -// window.h -#pragma once - -#include <stdint.h> - -namespace gfx { - -struct Window; - -enum class KeyCode -{ - Unknown, - - // TODO: extend this to cover at least a standard US-English keyboard - - A, B, C, D, E, F, G, H, I, J, - K, L, M, N, O, P, Q, R, S, T, - U, V, W, X, Y, Z, - - Space, -}; - -enum class EventCode : uint32_t -{ - MouseDown, - MouseUp, - MouseMoved, - KeyDown, - KeyUp, -}; - -struct Event -{ - EventCode code; - Window* window; - union - { - struct - { - float x; - float y; - } mouse; - - KeyCode key; - } u; -}; - -typedef void (*EventHandler)(Event const&); - -struct WindowDesc -{ - char const* title = nullptr; - void* userData = nullptr; - int width = 0; - int height = 0; - EventHandler eventHandler = nullptr; -}; - -Window* createWindow(WindowDesc const& desc); -void destroyWindow(Window* window); -void showWindow(Window* window); - -void* getPlatformWindowHandle(Window* window); -void* getUserData(Window* window); - -/// Opaque state provided by platform for a running application. -typedef struct ApplicationContext ApplicationContext; - -/// User-defined application entry-point function. -typedef void(*ApplicationFunc)(ApplicationContext* context); - -/// Dispatch any pending events for application. -/// -/// @returns `true` if application should keep running. -bool dispatchEvents(ApplicationContext* context); - -/// Exit the application with a given result code -void exitApplication(ApplicationContext* context, int resultCode); - -/// Log a message to an appropriate logging destination. -void log(char const* message, ...); - -/// Report an error to an appropriate logging destination. -int reportError(char const* message, ...); - -uint64_t getCurrentTime(); - -uint64_t getTimerFrequency(); - -/// Run an application given the specified callback and command-line arguments. -int runApplication( - ApplicationFunc func, - int argc, - char const* const* argv); - -#define GFX_CONSOLE_MAIN(APPLICATION_ENTRY) \ - int main(int argc, char** argv) { \ - return gfx::runApplication(&(APPLICATION_ENTRY), argc, argv); \ - } - -#ifdef _WIN32 - -int runWindowsApplication( - ApplicationFunc func, - void* instance, - int showCommand); - -#ifdef _MSC_VER -#ifdef _DEBUG -# define GFX_DUMP_LEAK _CrtDumpMemoryLeaks(); -#endif -#endif -#ifndef GFX_DUMP_LEAK -#define GFX_DUMP_LEAK -#endif -#define GFX_UI_MAIN(APPLICATION_ENTRY) \ - int __stdcall WinMain( \ - void* instance, \ - void* /* prevInstance */, \ - void* /* commandLine */, \ - int showCommand) { \ - auto result = gfx::runWindowsApplication(&(APPLICATION_ENTRY), instance, showCommand); \ - GFX_DUMP_LEAK \ - return result; \ - } - -#else - -#define GFX_UI_MAIN(APPLICATION_ENTRY) GFX_CONSOLE_MAIN(APPLICATION_ENTRY) - -#endif - -} // gfx diff --git a/tools/graphics-app-framework/windows/win-window.cpp b/tools/graphics-app-framework/windows/win-window.cpp deleted file mode 100644 index 2beb65d70..000000000 --- a/tools/graphics-app-framework/windows/win-window.cpp +++ /dev/null @@ -1,416 +0,0 @@ -// win-window.cpp -#include "../window.h" - -#include "core/slang-smart-pointer.h" - -#include <stdio.h> - -#ifdef _MSC_VER -#include <stddef.h> -#if (_MSC_VER < 1900) -#define snprintf sprintf_s -#endif -#endif - -#include <stdint.h> - -#if _WIN32 -#include <Windows.h> -#include <Windowsx.h> -#else -#error "The slang-graphics library currently only supports Windows platforms" -#endif - -namespace gfx { - -#if _WIN32 - -struct OSString -{ - OSString(char const* begin, char const* end) - { - _initialize(begin, end - begin); - } - - OSString(char const* begin) - { - _initialize(begin, strlen(begin)); - } - - ~OSString() - { - free(mBegin); - } - - operator WCHAR const*() - { - return mBegin; - } - -private: - WCHAR* mBegin; - WCHAR* mEnd; - - void _initialize(char const* input, size_t inputSize) - { - const DWORD dwFlags = 0; - int outputCodeUnitCount = ::MultiByteToWideChar(CP_UTF8, dwFlags, input, int(inputSize), nullptr, 0); - - WCHAR* buffer = (WCHAR*)malloc(sizeof(WCHAR) * (outputCodeUnitCount + 1)); - - ::MultiByteToWideChar(CP_UTF8, dwFlags, input, int(inputSize), buffer, outputCodeUnitCount); - buffer[outputCodeUnitCount] = 0; - - mBegin = buffer; - mEnd = buffer + outputCodeUnitCount; - } -}; - -struct ApplicationContext : public Slang::RefObject -{ - HINSTANCE instance; - int showCommand = SW_SHOWDEFAULT; - int resultCode = 0; -}; - -static uint64_t gTimerFrequency; - - -static void initApplication(ApplicationContext* context) -{ - LARGE_INTEGER timerFrequency; - QueryPerformanceFrequency(&timerFrequency); - gTimerFrequency = timerFrequency.QuadPart; -} - -/// Run an application given the specified callback and command-line arguments. -int runApplication( - ApplicationFunc func, - int argc, - char const* const* argv) -{ - ApplicationContext context; - context.instance = (HINSTANCE) GetModuleHandle(0); - initApplication(&context); - func(&context); - return context.resultCode; -} - -int runWindowsApplication( - ApplicationFunc func, - void* instance, - int showCommand) -{ - ApplicationContext context; - context.instance = (HINSTANCE) instance; - context.showCommand = showCommand; - initApplication(&context); - func(&context); - return context.resultCode; -} - -struct Window -{ - HWND handle; - WNDPROC nativeHook; - EventHandler eventHandler; - void* userData; -}; - -void setNativeWindowHook(Window* window, WNDPROC proc) -{ - window->nativeHook = proc; -} - -static KeyCode translateKeyCode(int vkey) -{ - switch( vkey ) - { - default: - return KeyCode::Unknown; - -#define CASE(FROM, TO) case FROM: return KeyCode::TO; - CASE('A', A); CASE('B', B); CASE('C', C); CASE('D', D); CASE('E', E); - CASE('F', F); CASE('G', G); CASE('H', H); CASE('I', I); CASE('J', J); - CASE('K', K); CASE('L', M); CASE('M', M); CASE('N', N); CASE('O', O); - CASE('P', P); CASE('Q', Q); CASE('R', R); CASE('S', S); CASE('T', T); - CASE('U', U); CASE('V', V); CASE('W', W); CASE('X', X); CASE('Y', Y); - CASE('Z', Z); -#undef CASE - -#define CASE(FROM, TO) case VK_##FROM: return KeyCode::TO; - CASE(SPACE, Space); -#undef CASE - } -} - -static LRESULT CALLBACK windowProc( - HWND windowHandle, - UINT message, - WPARAM wParam, - LPARAM lParam) -{ - Window* window = (Window*) GetWindowLongPtrW(windowHandle, GWLP_USERDATA); - - // Give the installed filter a chance to intercept messages. - // (This is used for ImGui) - if( window ) - { - if(auto nativeHook = window->nativeHook) - { - auto result = nativeHook(windowHandle, message, wParam, lParam); - if(result) - return result; - } - } - - auto eventHandler = window ? window->eventHandler : nullptr; - - switch (message) - { - case WM_CREATE: - { - auto createInfo = (CREATESTRUCTW*) lParam; - window = (Window*) createInfo->lpCreateParams; - window->handle = windowHandle; - - SetWindowLongPtrW(windowHandle, GWLP_USERDATA, (LONG_PTR) window); - } - break; - - case WM_KEYDOWN: - case WM_KEYUP: - { - int virtualKey = (int) wParam; - auto keyCode = translateKeyCode(virtualKey); - if(eventHandler) - { - Event event; - event.window = window; - event.code = message == WM_KEYDOWN ? EventCode::KeyDown : EventCode::KeyUp; - event.u.key = keyCode; - eventHandler(event); - } - } - break; - - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - { - if(eventHandler) - { - Event event; - event.window = window; - event.code = message == WM_LBUTTONDOWN ? EventCode::MouseDown : EventCode::MouseUp; - event.u.mouse.x = (float) GET_X_LPARAM(lParam); - event.u.mouse.y = (float) GET_Y_LPARAM(lParam); - eventHandler(event); - } - } - break; - - case WM_MOUSEMOVE: - { - if(eventHandler) - { - Event event; - event.window = window; - event.code = EventCode::MouseMoved; - event.u.mouse.x = (float) GET_X_LPARAM(lParam); - event.u.mouse.y = (float) GET_Y_LPARAM(lParam); - eventHandler(event); - } - } - break; - - case WM_CLOSE: - PostQuitMessage(0); - return 0; - } - - - return DefWindowProcW(windowHandle, message, wParam, lParam); -} - - -static ATOM createWindowClassAtom() -{ - WNDCLASSEXW windowClassDesc; - windowClassDesc.cbSize = sizeof(windowClassDesc); - windowClassDesc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; - windowClassDesc.lpfnWndProc = &windowProc; - windowClassDesc.cbClsExtra = 0; - windowClassDesc.cbWndExtra = 0; - windowClassDesc.hInstance = (HINSTANCE) GetModuleHandle(0); - windowClassDesc.hIcon = 0; - windowClassDesc.hCursor = LoadCursorW(NULL, IDC_ARROW); - windowClassDesc.hbrBackground = 0; - windowClassDesc.lpszMenuName = 0; - windowClassDesc.lpszClassName = L"SlangGraphicsWindow"; - windowClassDesc.hIconSm = 0; - ATOM windowClassAtom = RegisterClassExW(&windowClassDesc); - return windowClassAtom; -} - -static ATOM getWindowClassAtom() -{ - static ATOM windowClassAtom = createWindowClassAtom(); - return windowClassAtom; -} - -Window* createWindow(WindowDesc const& desc) -{ - Window* window = new Window(); - window->handle = nullptr; - window->nativeHook = nullptr; - window->eventHandler = desc.eventHandler; - window->userData = desc.userData; - - OSString windowTitle(desc.title); - - DWORD windowExtendedStyle = 0; - DWORD windowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; - - HINSTANCE instance = (HINSTANCE) GetModuleHandle(0); - - RECT windowRect; - windowRect.left = 0; - windowRect.top = 0; - windowRect.bottom = desc.height; - windowRect.right = desc.width; - AdjustWindowRect(&windowRect, windowStyle, FALSE); - - HWND windowHandle = CreateWindowExW( - windowExtendedStyle, - (LPWSTR) getWindowClassAtom(), - windowTitle, - windowStyle, - CW_USEDEFAULT, - 0, // x, y - windowRect.right - windowRect.left, - windowRect.bottom - windowRect.top, - NULL, // parent - NULL, // menu - instance, - window); - - - if(!windowHandle) - { - delete window; - return nullptr; - } - - window->handle = windowHandle; - return window; -} - -void destroyWindow(Window* window) -{ - DestroyWindow(window->handle); - delete window; -} - -void showWindow(Window* window) -{ - ShowWindow(window->handle, SW_SHOW); -} - -void* getPlatformWindowHandle(Window* window) -{ - return window->handle; -} - -void* getUserData(Window* window) -{ - return window->userData; -} - -bool dispatchEvents(ApplicationContext* context) -{ - for(;;) - { - MSG message; - - int result = PeekMessageW(&message, NULL, 0, 0, PM_REMOVE); - if (result != 0) - { - if (message.message == WM_QUIT) - { - context->resultCode = (int)message.wParam; - return false; - } - - TranslateMessage(&message); - DispatchMessageW(&message); - } - else - { - return true; - } - } - -} - -void exitApplication(ApplicationContext* context, int resultCode) -{ - ExitProcess(resultCode); -} - -void log(char const* message, ...) -{ - va_list args; - va_start(args, message); - - static const int kBufferSize = 1024; - char messageBuffer[kBufferSize]; - vsnprintf(messageBuffer, kBufferSize - 1, message, args); - messageBuffer[kBufferSize - 1] = 0; - - va_end(args); - - fputs(messageBuffer, stderr); - - OSString wideMessageBuffer(messageBuffer); - OutputDebugStringW(wideMessageBuffer); -} - -int reportError(char const* message, ...) -{ - va_list args; - va_start(args, message); - - static const int kBufferSize = 1024; - char messageBuffer[kBufferSize]; - vsnprintf(messageBuffer, kBufferSize - 1, message, args); - messageBuffer[kBufferSize - 1] = 0; - - va_end(args); - - fputs(messageBuffer, stderr); - - OSString wideMessageBuffer(messageBuffer); - OutputDebugStringW(wideMessageBuffer); - - return 1; -} - -uint64_t getCurrentTime() -{ - LARGE_INTEGER counter; - QueryPerformanceCounter(&counter); - return counter.QuadPart; -} - -uint64_t getTimerFrequency() -{ - return gTimerFrequency; -} - -#else - -// TODO: put an SDL version here - -#endif - -} // gfx diff --git a/tools/graphics-app-framework/gui.cpp b/tools/platform/gui.cpp index 3d4283131..cf7e74acc 100644 --- a/tools/graphics-app-framework/gui.cpp +++ b/tools/platform/gui.cpp @@ -7,8 +7,10 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); #endif +using namespace gfx; -namespace gfx { +namespace platform +{ #ifdef _WIN32 LRESULT CALLBACK guiWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) @@ -48,7 +50,7 @@ GUI::GUI( ImGuiIO& io = ImGui::GetIO(); #ifdef _WIN32 - ImGui_ImplWin32_Init(getPlatformWindowHandle(window)); + ImGui_ImplWin32_Init((HWND)window->getNativeHandle().handleValues[0]); setNativeWindowHook(window, &guiWindowProc); #endif @@ -113,7 +115,7 @@ GUI::GUI( const SlangResult compileRes = spCompile(slangRequest); if(auto diagnostics = spGetDiagnosticOutput(slangRequest)) { - reportError("%s", diagnostics); + printf("%s", diagnostics); } if(SLANG_FAILED(compileRes)) { diff --git a/tools/platform/gui.h b/tools/platform/gui.h new file mode 100644 index 000000000..d22da3299 --- /dev/null +++ b/tools/platform/gui.h @@ -0,0 +1,34 @@ +// gui.h +#pragma once + +#include "slang-gfx.h" +#include "vector-math.h" +#include "window.h" +#include "slang-com-ptr.h" +#include "external/imgui/imgui.h" +#include "source/core/slang-basic.h" + +namespace platform { + +struct GUI : Slang::RefObject +{ + GUI(Window* window, + gfx::IRenderer* renderer, + gfx::ICommandQueue* queue, + gfx::IFramebufferLayout* framebufferLayout); + ~GUI(); + + void beginFrame(); + void endFrame(gfx::IFramebuffer* framebuffer); + +private: + Slang::ComPtr<gfx::IRenderer> renderer; + Slang::ComPtr<gfx::ICommandQueue> queue; + Slang::ComPtr<gfx::IRenderPassLayout> renderPass; + Slang::ComPtr<gfx::IPipelineState> pipelineState; + Slang::ComPtr<gfx::IDescriptorSetLayout> descriptorSetLayout; + Slang::ComPtr<gfx::IPipelineLayout> pipelineLayout; + Slang::ComPtr<gfx::ISamplerState> samplerState; +}; + +} // gfx diff --git a/tools/graphics-app-framework/model.cpp b/tools/platform/model.cpp index 6984a6818..f28577631 100644 --- a/tools/graphics-app-framework/model.cpp +++ b/tools/platform/model.cpp @@ -231,7 +231,7 @@ Result ModelLoader::load( if(!diagnostics.empty()) { - log("%s", diagnostics.c_str()); + printf("%s", diagnostics.c_str()); } if(!success) { diff --git a/tools/graphics-app-framework/model.h b/tools/platform/model.h index 412f10a1d..412f10a1d 100644 --- a/tools/graphics-app-framework/model.h +++ b/tools/platform/model.h diff --git a/tools/platform/performance-counter.h b/tools/platform/performance-counter.h new file mode 100644 index 000000000..e9e990f45 --- /dev/null +++ b/tools/platform/performance-counter.h @@ -0,0 +1,30 @@ +#ifndef PLATFORM_PERFORMANCE_COUNTER_H +#define PLATFORM_PERFORMANCE_COUNTER_H + +#include <chrono> + +namespace platform +{ +typedef std::chrono::high_resolution_clock::time_point TimePoint; +typedef std::chrono::high_resolution_clock::duration Duration; + +class PerformanceCounter +{ +public: + static inline TimePoint now() + { + return std::chrono::high_resolution_clock::now(); + } + static inline Duration getElapsedTime(TimePoint counter) { return now() - counter; } + static inline float getElapsedTimeInSeconds(TimePoint counter) + { + return (float)toSeconds(now() - counter); + } + static inline double toSeconds(Duration duration) + { + return std::chrono::duration<float>(duration).count(); + } +}; +} // namespace platform + +#endif diff --git a/tools/graphics-app-framework/vector-math.h b/tools/platform/vector-math.h index e35cb46ac..e35cb46ac 100644 --- a/tools/graphics-app-framework/vector-math.h +++ b/tools/platform/vector-math.h diff --git a/tools/platform/window.h b/tools/platform/window.h new file mode 100644 index 000000000..c776c3ffa --- /dev/null +++ b/tools/platform/window.h @@ -0,0 +1,235 @@ +// window.h +#pragma once + +#include "slang-com-ptr.h" +#include "source/core/slang-basic.h" +#include "source/core/slang-func-ptr.h" + +namespace platform { + +enum class KeyCode : uint32_t +{ + None = 0, + Left = 0x25, + Up = 0x26, + Down = 0x28, + Right = 0x27, + Escape = 0x1B, + Return = 0x0D, + Space = 0x20, + Shift = 0x10, + Ctrl = 0x11, + Alt = 0x12, + Backspace = 0x08, + Delete = 0x2E, + Home = 0x24, + End = 0x23, + PageUp = 0x21, + PageDown = 0x22, + Insert = 0x2D, + Tab = 0x09, + A = 0x41, + B = 0x42, + C = 0x43, + D = 0x44, + E = 0x45, + F = 0x46, + G = 0x47, + H = 0x48, + I = 0x49, + J = 0x4A, + K = 0x4B, + L = 0x4C, + M = 0x4D, + N = 0x4E, + O = 0x4F, + P = 0x50, + Q = 0x51, + R = 0x52, + S = 0x53, + T = 0x54, + U = 0x55, + V = 0x56, + W = 0x57, + X = 0x58, + Y = 0x59, + Z = 0x5A, + Semicolon = 0xBA, + Comma = 0xBC, + Dot = 0xBE, + Slash = 0xBF, + Quote = 0xDE, + LBracket = 0xDB, + RBracket = 0xDD, + Backslash = 0xDC, + Minus = 0xBD, + Plus = 0xBB, + Tilde = 0xC0, + Key0 = 0x30, + Key1 = 0x31, + Key2 = 0x32, + Key3 = 0x33, + Key4 = 0x34, + Key5 = 0x35, + Key6 = 0x36, + Key7 = 0x37, + Key8 = 0x38, + Key9 = 0x39, + F1 = 0x70, + F2 = 0x71, + F3 = 0x72, + F4 = 0x73, + F5 = 0x74, + F6 = 0x75, + F7 = 0x76, + F8 = 0x77, + F9 = 0x78, + F10 = 0x79, + F11 = 0x7A, + F12 = 0x7B, +}; + +struct WindowHandle +{ + enum class Type + { + Unknown, + Win32Handle, + XLibHandle, + }; + Type type; + intptr_t handleValues[2]; + static WindowHandle FromHwnd(void* hwnd) + { + WindowHandle handle = {}; + handle.type = WindowHandle::Type::Win32Handle; + handle.handleValues[0] = (intptr_t)(hwnd); + return handle; + } + static WindowHandle FromXWindow(void* xdisplay, uint32_t xwindow) + { + WindowHandle handle = {}; + handle.type = WindowHandle::Type::XLibHandle; + handle.handleValues[0] = (intptr_t)(xdisplay); + handle.handleValues[1] = xwindow; + return handle; + } +}; + +struct ButtonState +{ + enum Enum + { + None = 0, LeftButton = 1, RightButton = 2, MiddleButton = 4, + Shift = 8, Control = 16, Alt = 32 + }; +}; + +struct KeyEventArgs +{ + KeyCode key; + wchar_t keyChar; // For KeyPress event + ButtonState::Enum buttons; + bool cancelEvent; +}; + +struct MouseEventArgs +{ + int x, y; + int delta; + ButtonState::Enum buttons; +}; + +struct Rect +{ + int x, y; + int width, height; +}; + +struct WindowDesc +{ + char const* title = nullptr; + int width = 0; + int height = 0; +}; + +class Window : public Slang::RefObject +{ +public: + struct Events + { + Slang::Action<> mainLoop; + Slang::Action<> sizeChanged; + Slang::Action<> focus; + Slang::Action<> lostFocus; + Slang::Action<KeyEventArgs&> keyDown; + Slang::Action<KeyEventArgs&> keyUp; + Slang::Action<KeyEventArgs&> keyPress; + Slang::Action<MouseEventArgs> mouseMove; + Slang::Action<MouseEventArgs> mouseUp; + Slang::Action<MouseEventArgs> mouseDown; + }; + + Events events; + + virtual void setClientSize(uint32_t width, uint32_t height) = 0; + virtual Rect getClientRect() = 0; + virtual void centerScreen() = 0; + virtual void close() = 0; + virtual bool getFocused() = 0; + virtual bool getVisible() = 0; + virtual WindowHandle getNativeHandle() = 0; + virtual void setText(Slang::String text) = 0; + virtual void show() = 0; + virtual void hide() = 0; + virtual int getCurrentDpi() = 0; +}; + +class Application +{ +public: + static Window* createWindow(const WindowDesc& desc); + static void init(); + static void run(Window* mainWindow, bool waitForEvents = false); + static void quit(); + static void doEvents(); + static void dispose(); +}; + +} // namespace platform + +#ifdef _WIN32 + +# ifdef _MSC_VER +# ifdef _DEBUG +# define GFX_DUMP_LEAK _CrtDumpMemoryLeaks(); +# endif +# endif +# ifndef GFX_DUMP_LEAK +# define GFX_DUMP_LEAK +# endif +# define PLATFORM_UI_MAIN(APPLICATION_ENTRY) \ + int __stdcall WinMain( \ + void* /*instance*/, \ + void* /* prevInstance */, \ + void* /* commandLine */, \ + int /*showCommand*/) \ + { \ + platform::Application::init(); \ + auto result = APPLICATION_ENTRY(); \ + platform::Application::dispose(); \ + GFX_DUMP_LEAK \ + return result; \ + } + +#else + +# define PLATFORM_UI_MAIN(APPLICATION_ENTRY) \ + int main() \ + { \ + platform::Application::init(); \ + auto rs - APPLICATION_ENTRY(); \ + platform::Application::dispose(); \ + } + +#endif diff --git a/tools/platform/windows/win-window.cpp b/tools/platform/windows/win-window.cpp new file mode 100644 index 000000000..0362a6839 --- /dev/null +++ b/tools/platform/windows/win-window.cpp @@ -0,0 +1,442 @@ +#ifdef _WIN32 + +#include "../window.h" + +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> +#include <windowsx.h> +using namespace Slang; + +namespace platform +{ + +static const wchar_t* kWindowClassName = L"slang-platform-window"; + +typedef BOOL(WINAPI* EnableNonClientDpiScalingProc)(_In_ HWND hwnd); + +class Win32AppContext +{ +public: + static EnableNonClientDpiScalingProc enableNonClientDpiScaling; + static RefPtr<Window> mainWindow; + static OrderedDictionary<HWND, Window*> windows; + static HWND mainWindowHandle; + static bool isTerminated; + static bool isWindows81OrGreater; +}; + +EnableNonClientDpiScalingProc Win32AppContext::enableNonClientDpiScaling = nullptr; +HWND Win32AppContext::mainWindowHandle = nullptr; +RefPtr<Window> Win32AppContext::mainWindow; +OrderedDictionary<HWND, Window*> Win32AppContext::windows; +bool Win32AppContext::isTerminated = false; +bool Win32AppContext::isWindows81OrGreater = false; + + +ButtonState::Enum _addButtonState(ButtonState::Enum val, ButtonState::Enum newState) +{ + return (ButtonState::Enum)((int)val | (int)newState); +} + +ButtonState::Enum getModifierState() +{ + ButtonState::Enum result = ButtonState::Enum::None; + if (GetAsyncKeyState(VK_CONTROL)) + result = _addButtonState(result, ButtonState::Enum::Control); + if (GetAsyncKeyState(VK_SHIFT)) + result = _addButtonState(result, ButtonState::Enum::Shift); + if (GetAsyncKeyState(VK_MENU)) + result = _addButtonState(result, ButtonState::Enum::Alt); + return result; +} + +ButtonState::Enum getModifierState(WPARAM wParam) +{ + ButtonState::Enum result = ButtonState::Enum::None; + if (wParam & MK_CONTROL) + result = _addButtonState(result, ButtonState::Enum::Control); + if (wParam & MK_MBUTTON) + result = _addButtonState(result, ButtonState::Enum::MiddleButton); + if (wParam & MK_RBUTTON) + result = _addButtonState(result, ButtonState::Enum::RightButton); + if (wParam & MK_SHIFT) + result = _addButtonState(result, ButtonState::Enum::Shift); + if (GetAsyncKeyState(VK_MENU)) + result = _addButtonState(result, ButtonState::Enum::Alt); + return result; +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + bool useDefProc = true; + Window* window = nullptr; + Win32AppContext::windows.TryGetValue(hWnd, window); + switch (message) + { + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + int mx = GET_X_LPARAM(lParam); + int my = GET_Y_LPARAM(lParam); + bool processed = false; + if (window) + { + window->events.mouseUp(MouseEventArgs{ + mx, + my, + 0, getModifierState(wParam)}); + } + } + break; + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + { + int mx = GET_X_LPARAM(lParam); + int my = GET_Y_LPARAM(lParam); + bool processed = false; + if (window) + { + window->events.mouseDown(MouseEventArgs{mx, my, 0, getModifierState(wParam)}); + } + } + break; + case WM_MOUSEMOVE: + { + int mx = GET_X_LPARAM(lParam); + int my = GET_Y_LPARAM(lParam); + if (window) + { + window->events.mouseMove(MouseEventArgs{mx, my, 0, getModifierState(wParam)}); + } + } + break; + case WM_MOUSEWHEEL: + { + int delta = GET_WHEEL_DELTA_WPARAM(wParam); + if (window) + { + window->events.mouseMove(MouseEventArgs{0, 0, delta, getModifierState(wParam)}); + } + } + break; + case WM_CHAR: + { + if (window) + { + KeyEventArgs keyEventArgs = { + KeyCode::None, (wchar_t)(wParam), ButtonState::Enum::None, false}; + window->events.keyPress(keyEventArgs); + if (keyEventArgs.cancelEvent) + useDefProc = false; + } + } + break; + case WM_KEYDOWN: + { + if (window) + { + KeyEventArgs keyEventArgs = {(KeyCode)(wParam), 0, getModifierState(), false}; + window->events.keyDown(keyEventArgs); + if (keyEventArgs.cancelEvent) + useDefProc = false; + } + } + break; + case WM_KEYUP: + { + if (window) + { + KeyEventArgs keyEventArgs = {(KeyCode)(wParam), 0, getModifierState(), false}; + window->events.keyUp(keyEventArgs); + if (keyEventArgs.cancelEvent) + useDefProc = false; + } + } + break; + case WM_SETFOCUS: + { + if (window) + { + window->events.focus(); + } + } + break; + case WM_KILLFOCUS: + { + if (window) + { + window->events.lostFocus(); + } + } + break; + case WM_SIZE: + { + if (window) + { + window->events.sizeChanged(); + } + } + break; + case WM_NCCREATE: + { + if (Win32AppContext::enableNonClientDpiScaling) + Win32AppContext::enableNonClientDpiScaling(hWnd); + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + default: + break; + } + if (message == WM_DESTROY && hWnd == Win32AppContext::mainWindowHandle) + { + PostQuitMessage(0); + return 0; + } + if (useDefProc) + return DefWindowProc(hWnd, message, wParam, lParam); + return 0; +} + +void registerWindowClass() +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hIcon = 0; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wcex.lpszMenuName = 0; + wcex.lpszClassName = kWindowClassName; + wcex.hIconSm = 0; + + RegisterClassExW(&wcex); +} + +void unregisterWindowClass() { UnregisterClassW(kWindowClassName, GetModuleHandle(NULL)); } + +HRESULT(WINAPI* getDpiForMonitor) (void* hmonitor, int dpiType, unsigned int* dpiX, unsigned int* dpiY); + +void Application::init() +{ + *(FARPROC*)&Win32AppContext::enableNonClientDpiScaling = + GetProcAddress(GetModuleHandleA("User32"), "EnableNonClientDpiScaling"); + void*(WINAPI * RtlGetVersion)(LPOSVERSIONINFOEXW); + OSVERSIONINFOEXW osInfo; + *(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion"); + + if (RtlGetVersion) + { + osInfo.dwOSVersionInfoSize = sizeof(osInfo); + RtlGetVersion(&osInfo); + if (osInfo.dwMajorVersion > 8 || (osInfo.dwMajorVersion == 8 && osInfo.dwMinorVersion >= 1)) + Win32AppContext::isWindows81OrGreater = true; + } + HRESULT(WINAPI * setProcessDpiAwareness)(int value); + *(FARPROC*)&setProcessDpiAwareness = + GetProcAddress(GetModuleHandleA("Shcore"), "SetProcessDpiAwareness"); + *(FARPROC*)&getDpiForMonitor = GetProcAddress(GetModuleHandleA("Shcore"), "GetDpiForMonitor"); + if (setProcessDpiAwareness) + { + if (Win32AppContext::isWindows81OrGreater) + setProcessDpiAwareness(2); // PROCESS_PER_MONITOR_DPI_AWARE + else + setProcessDpiAwareness(1); // PROCESS_SYSTEM_DPI_AWARE + } + registerWindowClass(); +} + +void doEventsImpl(bool waitForEvents) +{ + int hasMsg = 0; + do + { + MSG msg = {}; + hasMsg = + (waitForEvents ? GetMessage(&msg, NULL, 0, 0) : PeekMessage(&msg, NULL, 0, 0, TRUE)); + if (hasMsg) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if (msg.message == WM_QUIT) + Win32AppContext::isTerminated = true; + } while (!Win32AppContext::isTerminated && hasMsg); +} + +void Application::doEvents() { doEventsImpl(false); } + +void Application::quit() { Win32AppContext::isTerminated = true; } + +void Application::dispose() +{ + Win32AppContext::mainWindow = nullptr; + Win32AppContext::windows = decltype(Win32AppContext::windows)(); + unregisterWindowClass(); +} + +void Application::run(Window* mainWindow, bool waitForEvents) +{ + if (mainWindow) + { + Win32AppContext::mainWindow = mainWindow; + Win32AppContext::mainWindowHandle = (HWND)mainWindow->getNativeHandle().handleValues[0]; + ShowWindow(Win32AppContext::mainWindowHandle, SW_SHOW); + UpdateWindow(Win32AppContext::mainWindowHandle); + } + while (!Win32AppContext::isTerminated) + { + doEventsImpl(waitForEvents); + if (mainWindow) + { + mainWindow->events.mainLoop(); + } + } +} + +class Win32PlatformWindow : public Window +{ +public: + HWND handle; + DWORD style; + bool visible = false; + Win32PlatformWindow(const WindowDesc& desc) + { + DWORD windowExtendedStyle = 0; + DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; + HINSTANCE instance = (HINSTANCE)GetModuleHandle(0); + + RECT windowRect; + windowRect.left = 0; + windowRect.top = 0; + windowRect.bottom = desc.height; + windowRect.right = desc.width; + AdjustWindowRect(&windowRect, style, FALSE); + + handle = CreateWindowExW( + windowExtendedStyle, + (LPWSTR)kWindowClassName, + String(desc.title).toWString().begin(), + style, + CW_USEDEFAULT, + 0, // x, y + windowRect.right, + windowRect.bottom, + NULL, // parent + NULL, // menu + instance, + NULL); + + if (handle) + Win32AppContext::windows[handle] = this; + } + + ~Win32PlatformWindow() + { + if (handle) + { + Win32AppContext::windows.Remove(handle); + } + DestroyWindow(handle); + } + + virtual void setClientSize(uint32_t width, uint32_t height) override + { + RECT currentRect; + GetWindowRect(handle, ¤tRect); + + RECT windowRect; + windowRect.left = currentRect.left; + windowRect.top = currentRect.top; + windowRect.bottom = height; + windowRect.right = width; + AdjustWindowRect(&windowRect, style, FALSE); + + MoveWindow( + handle, + windowRect.left, + windowRect.top, + windowRect.right - windowRect.left, + windowRect.bottom - windowRect.top, + FALSE); + } + + virtual Rect getClientRect() override + { + RECT currentRect; + GetClientRect(handle, ¤tRect); + Rect rect; + rect.x = currentRect.left; + rect.y = currentRect.top; + rect.width = currentRect.right - currentRect.left; + rect.height = currentRect.bottom - currentRect.top; + return rect; + } + + virtual void centerScreen() override + { + RECT screenRect; + GetClientRect(GetDesktopWindow(), &screenRect); + RECT currentRect; + GetWindowRect(handle, ¤tRect); + + auto width = currentRect.right - currentRect.left; + auto height = currentRect.bottom - currentRect.top; + + auto left = (screenRect.right - width) / 2; + auto top = (screenRect.bottom - height) / 2; + + MoveWindow(handle, left, top, width, height, FALSE); + } + + virtual void close() override {} + virtual bool getFocused() override { return GetFocus() == handle; } + virtual bool getVisible() override { return visible; } + virtual WindowHandle getNativeHandle() override + { + return WindowHandle::FromHwnd(handle); + } + virtual void setText(Slang::String text) override + { + SetWindowText(handle, text.toWString().begin()); + } + virtual void show() override + { + ShowWindow(handle, SW_SHOW); + visible = true; + } + virtual void hide() override + { + ShowWindow(handle, SW_HIDE); + visible = false; + } + virtual int getCurrentDpi() override + { + int dpi = 96; + if (Win32AppContext::isWindows81OrGreater && getDpiForMonitor) + { + getDpiForMonitor( + MonitorFromWindow(handle, MONITOR_DEFAULTTOPRIMARY), + 0, + (UINT*)&dpi, + (UINT*)&dpi); + return dpi; + } + dpi = GetDeviceCaps(NULL, LOGPIXELSY); + return dpi; + } +}; + +Window* Application::createWindow(const WindowDesc& desc) { return new Win32PlatformWindow(desc); } + + +} // namespace gfx + +#endif |
