cae  0.0.0
Cross-API graphics engine
Loading...
Searching...
No Matches
win32.cpp
Go to the documentation of this file.
1#include "Win32/Win32.hpp"
2
3#include "Utils/Image.hpp"
4#include "Utils/Logger.hpp"
5
6#include <windowsx.h>
7
8#include <cstring>
9#include <unordered_map>
10#include <utility>
11
12constexpr wchar_t WINDOW_CLASS_NAME[] = L"CAE_WindowsWindowClass";
13
14cae::KeyCode cae::Win32::mapWinKey(const WPARAM key)
15{
16 static const std::unordered_map<WPARAM, KeyCode> keyMap = {
17 {'A', KeyCode::A},
18 {'B', KeyCode::B},
19 {'C', KeyCode::C},
20 {'D', KeyCode::D},
21 {'E', KeyCode::E},
22 {'F', KeyCode::F},
23 {'G', KeyCode::G},
24 {'H', KeyCode::H},
25 {'I', KeyCode::I},
26 {'J', KeyCode::J},
27 {'K', KeyCode::K},
28 {'L', KeyCode::L},
29 {'M', KeyCode::M},
30 {'N', KeyCode::N},
31 {'O', KeyCode::O},
32 {'P', KeyCode::P},
33 {'Q', KeyCode::Q},
34 {'R', KeyCode::R},
35 {'S', KeyCode::S},
36 {'T', KeyCode::T},
37 {'U', KeyCode::U},
38 {'V', KeyCode::V},
39 {'W', KeyCode::W},
40 {'X', KeyCode::X},
41 {'Y', KeyCode::Y},
42 {'Z', KeyCode::Z},
43
44 {'0', KeyCode::Num0},
45 {'1', KeyCode::Num1},
46 {'2', KeyCode::Num2},
47 {'3', KeyCode::Num3},
48 {'4', KeyCode::Num4},
49 {'5', KeyCode::Num5},
50 {'6', KeyCode::Num6},
51 {'7', KeyCode::Num7},
52 {'8', KeyCode::Num8},
53 {'9', KeyCode::Num9},
54
55 {VK_ESCAPE, KeyCode::Escape},
56 {VK_LEFT, KeyCode::Left},
57 {VK_RIGHT, KeyCode::Right},
58 {VK_UP, KeyCode::Up},
59 {VK_DOWN, KeyCode::Down},
60 {VK_SPACE, KeyCode::Space},
61 {VK_RETURN, KeyCode::Enter},
62 {VK_BACK, KeyCode::Backspace},
63 {VK_TAB, KeyCode::Tab},
64 {VK_LSHIFT, KeyCode::LShift},
65 {VK_RSHIFT, KeyCode::RShift},
66 {VK_LCONTROL, KeyCode::LCtrl},
67 {VK_RCONTROL, KeyCode::RCtrl},
68 {VK_LMENU, KeyCode::LAlt},
69 {VK_RMENU, KeyCode::RAlt}
70 // ...
71 };
72
73 const auto it = keyMap.find(key);
74 return it != keyMap.end() ? it->second : KeyCode::Count;
75}
76
77LRESULT CALLBACK cae::Win32::WindowProc(const HWND hwnd, const UINT msg, const WPARAM wParam, const LPARAM lParam)
78{
79 Win32 *self = nullptr;
80
81 if (msg == WM_NCCREATE)
82 {
83 const auto *cs = reinterpret_cast<CREATESTRUCTW *>(lParam);
84 self = static_cast<Win32 *>(cs->lpCreateParams);
85 SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self));
86 return TRUE;
87 }
88
89 self = reinterpret_cast<Win32 *>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
90 if (self == nullptr)
91 {
92 return DefWindowProcW(hwnd, msg, wParam, lParam);
93 }
94
95 WindowEvent e{};
96 switch (msg)
97 {
98 case WM_SIZE:
99 self->m_frameBufferResized = true;
100 self->m_frameBufferSize = {.width = LOWORD(lParam), .height = HIWORD(lParam)};
101 e.type = WindowEventType::Resize;
102 e.resize = {.w = LOWORD(lParam), .h = HIWORD(lParam)};
103 self->m_eventQueue.push(e);
104 return 0;
105
106 case WM_DESTROY:
107 PostQuitMessage(0);
108 e.type = WindowEventType::Close;
109 self->m_eventQueue.push(e);
110 return 0;
111
112 case WM_KEYDOWN:
113 case WM_SYSKEYDOWN:
114 e.type = WindowEventType::KeyDown;
115 e.key.key = mapWinKey(wParam);
116 self->m_eventQueue.push(e);
117 return 0;
118
119 case WM_KEYUP:
120 case WM_SYSKEYUP:
121 e.type = WindowEventType::KeyUp;
122 e.key.key = mapWinKey(wParam);
123 self->m_eventQueue.push(e);
124 return 0;
125
126 // mouse, scroll, ...
127 }
128
129 return DefWindowProcW(hwnd, msg, wParam, lParam);
130}
131
132bool cae::Win32::create(const std::string &name, const WindowSize size)
133{
134 m_hInstance = GetModuleHandleW(nullptr);
135 m_frameBufferSize = size;
136 m_shouldClose = false;
137 m_frameBufferResized = false;
138
139 const int len = MultiByteToWideChar(CP_UTF8, 0, name.c_str(), -1, nullptr, 0);
140
141 m_title.resize(len);
142
143 MultiByteToWideChar(CP_UTF8, 0, name.c_str(), -1, m_title.data(), len);
144
145 if (!m_title.empty() && m_title.back() == L'\0')
146 {
147 m_title.pop_back();
148 }
149
150 static bool classRegistered = false;
151 if (!classRegistered)
152 {
153 WNDCLASSW wc{};
154 wc.lpfnWndProc = WindowProc;
155 wc.hInstance = m_hInstance;
156 wc.lpszClassName = WINDOW_CLASS_NAME;
157 wc.hCursor = LoadCursorW(nullptr, IDC_ARROW);
158 wc.hIcon = LoadIconW(nullptr, IDI_APPLICATION);
159 wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
160
161 if (RegisterClassW(&wc) == 0U)
162 {
163 utl::Logger::log("Failed to register Win32 window class", utl::LogLevel::WARNING);
164 return false;
165 }
166 classRegistered = true;
167 }
168 m_hwnd = CreateWindowExW(0, WINDOW_CLASS_NAME, L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, size.width,
169 size.height, nullptr, nullptr, m_hInstance, this);
170
171 if (m_hwnd == nullptr)
172 {
173 return false;
174 }
175
176 SetWindowTextW(m_hwnd, m_title.c_str());
177
178 ShowWindow(m_hwnd, SW_SHOW);
179 UpdateWindow(m_hwnd);
180 return true;
181}
182
183void cae::Win32::close()
184{
185 if (m_hwnd != nullptr)
186 {
187 DestroyWindow(m_hwnd);
188 m_hwnd = nullptr;
189 }
190 UnregisterClassW(WINDOW_CLASS_NAME, m_hInstance);
191}
192
193cae::NativeWindowHandle cae::Win32::getNativeHandle() const { return {.window = m_hwnd, .display = m_hInstance}; }
194
195cae::WindowSize cae::Win32::getWindowSize() const
196{
197 RECT rect{};
198 GetClientRect(m_hwnd, &rect);
199 return {.width = static_cast<uint16_t>(rect.right - rect.left),
200 .height = static_cast<uint16_t>(rect.bottom - rect.top)};
201}
202
203void cae::Win32::setIcon(const std::string &path) const
204{
205 try
206 {
207 const utl::Image image(path);
208
209 for (size_t i = 0; std::cmp_less(i, image.width * image.height); ++i)
210 {
211 std::swap(image.pixels[(i * 4) + 0], image.pixels[(i * 4) + 2]);
212 }
213
214 ICONINFO iconInfo{};
215 iconInfo.fIcon = TRUE;
216
217 BITMAPV5HEADER bi{};
218 bi.bV5Size = sizeof(BITMAPV5HEADER);
219 bi.bV5Width = image.width;
220 bi.bV5Height = -static_cast<LONG>(image.height);
221 bi.bV5Planes = 1;
222 bi.bV5BitCount = 32;
223 bi.bV5Compression = BI_BITFIELDS;
224 bi.bV5RedMask = 0x00FF0000;
225 bi.bV5GreenMask = 0x0000FF00;
226 bi.bV5BlueMask = 0x000000FF;
227 bi.bV5AlphaMask = 0xFF000000;
228
229 void *pBits = nullptr;
230 const HDC hdc = GetDC(nullptr);
231 const HBITMAP hBitmap =
232 CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO *>(&bi), DIB_RGB_COLORS, &pBits, nullptr, 0);
233 ReleaseDC(nullptr, hdc);
234
235 if (hBitmap == nullptr)
236 {
237 utl::Logger::log("Failed to create window icon.", utl::LogLevel::WARNING);
238 return;
239 }
240
241 std::memcpy(pBits, image.pixels, static_cast<size_t>(image.width * image.height * 4));
242
243 iconInfo.hbmColor = hBitmap;
244 iconInfo.hbmMask = CreateBitmap(image.width, image.height, 1, 1, nullptr);
245
246 HICON hIcon = CreateIconIndirect(&iconInfo);
247
248 DeleteObject(hBitmap);
249 DeleteObject(iconInfo.hbmMask);
250
251 if (hIcon == nullptr)
252 {
253 utl::Logger::log("Failed to create window icon", utl::LogLevel::WARNING);
254 return;
255 }
256
257 SendMessageW(m_hwnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hIcon));
258 SendMessageW(m_hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hIcon));
259 }
260 catch (const std::exception &e)
261 {
262 utl::Logger::log("Failed to load icon: " + std::string(e.what()), utl::LogLevel::WARNING);
263 }
264}
265
266void cae::Win32::pollEvents()
267{
268 MSG msg{};
269 while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
270 {
271 if (msg.message == WM_QUIT)
272 {
273 m_shouldClose = true;
274 }
275 TranslateMessage(&msg);
276 DispatchMessage(&msg);
277 }
278}
279
280bool cae::Win32::pollEvent(WindowEvent &event)
281{
282 MSG msg{};
283 while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
284 {
285 TranslateMessage(&msg);
286 DispatchMessage(&msg);
287 }
288
289 if (!m_eventQueue.empty())
290 {
291 event = m_eventQueue.front();
292 m_eventQueue.pop();
293 return true;
294 }
295
296 return false;
297}
This file contains image struct.
This file contains the Logger class.
static void log(const std::string &message, const LogLevel &logLevel)
Log a message with a specific log level.
Definition Logger.hpp:71
KeyCode
Definition Keyboard.hpp:23
Struct for native window handle.
Definition IWindow.hpp:34
Struct for window size.
Definition IWindow.hpp:23
Struct for image.
Definition Image.hpp:20
constexpr wchar_t WINDOW_CLASS_NAME[]
Definition win32.cpp:12