11#define WIN32_LEAN_AND_MEAN
18#define WM_GRAPHNOTIFY (WM_APP + 1)
23 return GetKeyState(int32_t(key)) & 0x8000;
28 GetWindowRect(game_state.
win_ptr->hwnd, &getRect);
29 width = (getRect.right - getRect.left);
30 height = (getRect.bottom - getRect.top);
38 if(game_state.
win_ptr && game_state.
win_ptr->hwnd && game_state.
win_ptr->in_fullscreen != fullscreen) {
41 auto monitor_handle = MonitorFromWindow(game_state.
win_ptr->hwnd, MONITOR_DEFAULTTOPRIMARY);
43 mi.cbSize =
sizeof(mi);
44 GetMonitorInfoW(monitor_handle, &mi);
46 int left = (mi.rcWork.right - mi.rcWork.left) / 2 - game_state.
win_ptr->creation_x_size / 2;
47 int top = (mi.rcWork.bottom - mi.rcWork.top) / 2 - game_state.
win_ptr->creation_y_size / 2;
49 DWORD win32Style = WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_SYSMENU |
50 WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
52 RECT rectangle = {left, top, left + game_state.
win_ptr->creation_x_size, top + game_state.
win_ptr->creation_y_size};
53 AdjustWindowRectExForDpi(&rectangle, win32Style,
false, 0, GetDpiForWindow(game_state.
win_ptr->hwnd));
54 int32_t final_width = rectangle.right - rectangle.left;
55 int32_t final_height = rectangle.bottom - rectangle.top;
57 SetWindowLongW(game_state.
win_ptr->hwnd, GWL_STYLE, win32Style);
58 SetWindowPos(game_state.
win_ptr->hwnd, HWND_NOTOPMOST, rectangle.left, rectangle.top, final_width, final_height,
60 SetWindowRgn(game_state.
win_ptr->hwnd, NULL, TRUE);
61 ShowWindow(game_state.
win_ptr->hwnd, SW_MAXIMIZE);
63 game_state.
win_ptr->in_fullscreen =
false;
67 auto monitor_handle = MonitorFromWindow(game_state.
win_ptr->hwnd, MONITOR_DEFAULTTOPRIMARY);
69 mi.cbSize =
sizeof(mi);
70 GetMonitorInfoW(monitor_handle, &mi);
72 DWORD win32Style = WS_VISIBLE | WS_BORDER | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
74 RECT rectangle = mi.rcMonitor;
75 AdjustWindowRectExForDpi(&rectangle, win32Style,
false, WS_EX_TOPMOST, GetDpiForWindow(game_state.
win_ptr->hwnd));
76 int32_t win_width = (rectangle.right - rectangle.left);
77 int32_t win_height = (rectangle.bottom - rectangle.top);
79 SetWindowLongW(game_state.
win_ptr->hwnd, GWL_STYLE, win32Style);
80 SetWindowPos(game_state.
win_ptr->hwnd, HWND_TOPMOST, rectangle.left, rectangle.top, win_width, win_height, SWP_NOREDRAW);
82 game_state.
win_ptr->in_fullscreen =
true;
89 PostMessageW(game_state.
win_ptr->hwnd, WM_CLOSE, 0, 0);
100LRESULT CALLBACK
WndProc(
HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
102 static int drag_x_start = 0;
103 static int drag_y_start = 0;
105 if(message == WM_CREATE) {
106 CREATESTRUCTW* cptr = (CREATESTRUCTW*)lParam;
109 create_state->
win_ptr->hwnd = hwnd;
110 create_state->
win_ptr->opengl_window_dc = GetDC(hwnd);
116 GetClientRect(hwnd, &crect);
117 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)create_state);
123 if(!state || !(state->win_ptr))
124 return DefWindowProcW(hwnd, message, wParam, lParam);
129 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)
nullptr);
133 ReleaseDC(hwnd, state->win_ptr->opengl_window_dc);
137 if(state->win_ptr->in_fullscreen)
138 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOREDRAW | SWP_NOSIZE | SWP_NOMOVE);
139 if(state->user_settings.mute_on_focus_lost) {
144 if(state->win_ptr->in_fullscreen)
145 SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
146 if(state->user_settings.mute_on_focus_lost) {
150 case WM_LBUTTONDOWN: {
152 auto x = GET_X_LPARAM(lParam);
153 auto y = GET_Y_LPARAM(lParam);
155 state->mouse_x_position = x;
156 state->mouse_y_position = y;
157 state->win_ptr->left_mouse_down =
true;
162 auto x = GET_X_LPARAM(lParam);
163 auto y = GET_Y_LPARAM(lParam);
165 state->mouse_x_position = x;
166 state->mouse_y_position = y;
167 state->win_ptr->left_mouse_down =
false;
171 auto x = GET_X_LPARAM(lParam);
172 auto y = GET_Y_LPARAM(lParam);
175 if(wParam & MK_LBUTTON)
178 state->mouse_x_position = x;
179 state->mouse_y_position = y;
183 case WM_RBUTTONDOWN: {
184 auto x = GET_X_LPARAM(lParam);
185 auto y = GET_Y_LPARAM(lParam);
187 state->mouse_x_position = x;
188 state->mouse_y_position = y;
192 auto x = GET_X_LPARAM(lParam);
193 auto y = GET_Y_LPARAM(lParam);
195 state->mouse_x_position = x;
196 state->mouse_y_position = y;
199 case WM_MBUTTONDOWN: {
200 auto x = GET_X_LPARAM(lParam);
201 auto y = GET_Y_LPARAM(lParam);
203 state->mouse_x_position = x;
204 state->mouse_y_position = y;
208 auto x = GET_X_LPARAM(lParam);
209 auto y = GET_Y_LPARAM(lParam);
211 state->mouse_x_position = x;
212 state->mouse_y_position = y;
218 if(wParam == SIZE_MAXIMIZED) {
220 }
else if(wParam == SIZE_MINIMIZED) {
222 }
else if(wParam == SIZE_RESTORED) {
229 state->on_resize(LOWORD(lParam), HIWORD(lParam), t);
230 state->x_size = LOWORD(lParam);
231 state->y_size = HIWORD(lParam);
239 case WM_MOUSEWHEEL: {
240 state->on_mouse_wheel(state->mouse_x_position, state->mouse_y_position,
get_current_modifiers(), (
float)(GET_WHEEL_DELTA_WPARAM(wParam)) / 120.0f);
257 if((HIWORD(lParam) & KF_REPEAT) != 0)
268 if(state->ui_state.edit_target) {
269 state->on_text(
char32_t(wParam));
275 case WM_DISPLAYCHANGE: {
277 BeginPaint(hwnd, &ps);
289 case WM_GETMINMAXINFO:
290 LPMINMAXINFO info = (LPMINMAXINFO)lParam;
291 info->ptMinTrackSize.x = 640;
292 info->ptMinTrackSize.y = 400;
294 return DefWindowProcW(hwnd, message, wParam, lParam);
298 game_state.
win_ptr = std::make_unique<window_data_impl>();
299 game_state.
win_ptr->creation_x_size = params.size_x;
300 game_state.
win_ptr->creation_y_size = params.size_y;
301 game_state.
win_ptr->in_fullscreen = params.borderless_fullscreen;
304 WNDCLASSEXW wcex = {};
306 wcex.cbSize =
sizeof(WNDCLASSEXW);
307 wcex.style = CS_OWNDC;
310 wcex.cbWndExtra =
sizeof(LONG_PTR);
311 wcex.hInstance = GetModuleHandleW(
nullptr);
312 wcex.hbrBackground = NULL;
313 wcex.lpszMenuName = NULL;
314 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
315 wcex.hIcon = (HICON)LoadImage(GetModuleHandleW(
nullptr), MAKEINTRESOURCE(
IDI_ICON1), IMAGE_ICON,
316 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0);
317 wcex.lpszClassName =
L"project_alice_class";
318 if(RegisterClassExW(&wcex) == 0) {
322 DWORD win32Style = !params.borderless_fullscreen ? (WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_THICKFRAME | WS_MAXIMIZEBOX |
323 WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS)
324 : WS_VISIBLE | WS_BORDER | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
326 game_state.
win_ptr->hwnd = CreateWindowExW(0, L
"project_alice_class", L
"Project Alice", win32Style, CW_USEDEFAULT,
327 CW_USEDEFAULT, 0, 0, NULL, NULL, GetModuleHandleW(
nullptr), &game_state);
332 SetCursor(LoadCursor(NULL, IDC_ARROW));
334 if(!params.borderless_fullscreen) {
336 auto monitor_handle = MonitorFromWindow(game_state.
win_ptr->hwnd, MONITOR_DEFAULTTOPRIMARY);
338 mi.cbSize =
sizeof(mi);
339 GetMonitorInfoW(monitor_handle, &mi);
341 int left = (mi.rcWork.right - mi.rcWork.left) / 2 - game_state.
win_ptr->creation_x_size / 2;
342 int top = (mi.rcWork.bottom - mi.rcWork.top) / 2 - game_state.
win_ptr->creation_y_size / 2;
344 RECT rectangle = {
left, top,
left + game_state.
win_ptr->creation_x_size, top + game_state.
win_ptr->creation_y_size};
345 AdjustWindowRectExForDpi(&rectangle, win32Style,
false, 0, GetDpiForWindow(game_state.
win_ptr->hwnd));
346 int32_t final_width = rectangle.right - rectangle.left;
347 int32_t final_height = rectangle.bottom - rectangle.top;
349 SetWindowLongW(game_state.
win_ptr->hwnd, GWL_STYLE, win32Style);
350 SetWindowPos(game_state.
win_ptr->hwnd, HWND_NOTOPMOST, rectangle.left, rectangle.top, final_width, final_height,
352 SetWindowRgn(game_state.
win_ptr->hwnd, NULL, TRUE);
355 ShowWindow(game_state.
win_ptr->hwnd, SW_MAXIMIZE);
357 ShowWindow(game_state.
win_ptr->hwnd, SW_MINIMIZE);
359 ShowWindow(game_state.
win_ptr->hwnd, SW_SHOWNORMAL);
362 auto monitor_handle = MonitorFromWindow(game_state.
win_ptr->hwnd, MONITOR_DEFAULTTOPRIMARY);
364 mi.cbSize =
sizeof(mi);
365 GetMonitorInfoW(monitor_handle, &mi);
367 RECT rectangle = mi.rcMonitor;
368 AdjustWindowRectExForDpi(&rectangle, win32Style,
false, WS_EX_TOPMOST, GetDpiForWindow(game_state.
win_ptr->hwnd));
369 int32_t win_width = (rectangle.right - rectangle.left);
370 int32_t win_height = (rectangle.bottom - rectangle.top);
372 SetWindowLongW(game_state.
win_ptr->hwnd, GWL_STYLE, win32Style);
373 SetWindowPos(game_state.
win_ptr->hwnd, HWND_TOPMOST, rectangle.left, rectangle.top, win_width, win_height, SWP_FRAMECHANGED);
374 ShowWindow(game_state.
win_ptr->hwnd, SW_SHOWNORMAL);
377 UpdateWindow(game_state.
win_ptr->hwnd);
389 if(PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) {
390 if(msg.message == WM_QUIT) {
394 TranslateMessage(&msg);
395 DispatchMessageW(&msg);
400 SwapBuffers(game_state.
win_ptr->opengl_window_dc);
410 if(
state.win_ptr->cursors[
uint8_t(type)] == HCURSOR(NULL)) {
414 fname =
NATIVE(
"normal.cur");
417 fname =
NATIVE(
"busy.ani");
420 fname =
NATIVE(
"dragselect.ani");
423 fname =
NATIVE(
"attack_move.ani");
426 fname =
NATIVE(
"friendly_move.ani");
429 fname =
NATIVE(
"no_move.ani");
432 fname =
NATIVE(
"normal.cur");
439 auto response = RegOpenKeyExW(HKEY_CURRENT_USER,
NATIVE(
"Software\\Microsoft\\Accessibility"), 0, KEY_READ, &hKey);
440 bool exists = (response == ERROR_SUCCESS);
441 auto cursor_size_key =
NATIVE(
"CursorSize");
446 DWORD dwBufferSize(
sizeof(DWORD));
448 LONG get_cursor_size_error = RegQueryValueExW(hKey,
452 reinterpret_cast<LPBYTE
>(&nResult),
454 if(get_cursor_size_error == ERROR_SUCCESS) {
455 cursor_size = nResult;
463 state.win_ptr->cursors[
uint8_t(type)] = (HCURSOR)LoadImageW(
nullptr, path.c_str(), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
465 if(
state.win_ptr->cursors[
uint8_t(type)] == HCURSOR(NULL)) {
466 state.win_ptr->cursors[
uint8_t(type)] = LoadCursor(
nullptr, IDC_ARROW);
467 state.ui_state.cursor_size = GetSystemMetrics(SM_CXCURSOR) * cursor_size / 2;
469 state.ui_state.cursor_size = GetSystemMetrics(SM_CXCURSOR) * cursor_size / 2;
472 state.win_ptr->cursors[
uint8_t(type)] = LoadCursor(
nullptr, IDC_ARROW);
473 state.ui_state.cursor_size = GetSystemMetrics(SM_CXCURSOR) * cursor_size / 2;
477 SetClassLongPtr(
state.win_ptr->hwnd, GCLP_HCURSOR,
reinterpret_cast<LONG_PTR
>(
state.win_ptr->cursors[
uint8_t(type)]));
481 static const char* msg1 =
"Project Alice has encountered a fatal error";
482 static const char* msg2 =
"Project Alice has encountered the following problems";
483 MessageBoxA(
nullptr, content.c_str(), fatal ? msg1 : msg2, MB_OK | (fatal ? MB_ICONERROR : MB_ICONWARNING));
485 std::exit(EXIT_FAILURE);
void initialize_opengl(sys::state &state)
void shutdown_opengl(sys::state &state)
directory open_directory(directory const &dir, native_string_view directory_name)
directory get_root(file_system const &fs)
native_string get_full_name(directory const &f)
std::optional< unopened_file > peek_file(directory const &dir, native_string_view file_name)
void pause_all(sys::state &state)
void initialize_sound_system(sys::state &state)
void resume_all(sys::state &state)
void update_music_track(sys::state &state)
void start_music(sys::state &state, float v)
void set_borderless_full_screen(sys::state &game_state, bool fullscreen)
void get_window_size(sys::state const &game_state, int &width, int &height)
bool is_key_depressed(sys::state const &game_state, sys::virtual_key key)
bool is_in_fullscreen(sys::state const &game_state)
sys::key_modifiers get_current_modifiers()
void emit_error_message(std::string const &content, bool fatal)
void close_window(sys::state &game_state)
void change_cursor(sys::state &state, cursor_type type)
void create_window(sys::state &game_state, creation_parameters const ¶ms)
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
std::string_view native_string_view
user_settings_s user_settings
std::unique_ptr< window::window_data_impl > win_ptr
element_base * edit_target