summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2021-03-08 10:01:20 -0800
committerGitHub <noreply@github.com>2021-03-08 10:01:20 -0800
commitfc9968dc4fd58fab37476f48e4405c2743c5349c (patch)
tree6119b293a5a5cc24401dde5ff54287beb28fe63b /tools
parent95ca93938f5d45f4eaf340867965bd77a1724d6c (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.h31
-rw-r--r--tools/graphics-app-framework/window.h133
-rw-r--r--tools/graphics-app-framework/windows/win-window.cpp416
-rw-r--r--tools/platform/gui.cpp (renamed from tools/graphics-app-framework/gui.cpp)8
-rw-r--r--tools/platform/gui.h34
-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.h30
-rw-r--r--tools/platform/vector-math.h (renamed from tools/graphics-app-framework/vector-math.h)0
-rw-r--r--tools/platform/window.h235
-rw-r--r--tools/platform/windows/win-window.cpp442
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, &currentRect);
+
+ 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, &currentRect);
+ 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, &currentRect);
+
+ 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