diff --git a/README.md b/README.md index d6e2306..3d8afb7 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Module build order: ## Milestone -Day 39 : Basic Bitmap Rendering Cleanup +Day 40 : Cursor Hiding and Fullscreen Support Features Done so far: @@ -44,14 +44,17 @@ Features Done so far: * Will automatically not run if app process is found (for engine module). * Can emit exported mangled symbols for the engine module for hot-reload with the platform module without needing to use C linkage symbols or a complex hot-reload library (Live++, etc). * Platform Layer: + * Block Memory allocation via VirtualAlloc for engine module + * Memory mapped files for engine & game snapshots. + * Instantaneous hot reload of engine module + * Software rendering via Win32 GDI * Direct Sound audio * Keyboard & Mouse Input via GetAsyncKeyState & Win32 window messagng * XInput controller support * Dualsense controller support via joyshock library - * Software rendering via Win32 GDI - * Instantaneous hot reload of engine module - * Block Memory allocation via VirtualAlloc for engine module - * Memory mapped files for engine & game snapshots. + * Fullscreen toggle + * Can't change refresh rate + * Auto-hide cursor in client region (painted surface), not using editor tools * Engine Layer: * Take & load snapshots of either the engine's or game's memory state. * Allows for engine or game state to be restored even if a crash occurs to exact memory state it was before. @@ -68,6 +71,7 @@ Features Done so far: ## Gallery +![img](docs/imgs/10x_2023-10-22_01-44-21.gif) ![img](docs/imgs/handmade_win32_2023-10-21_22-18-47.gif) ![img](docs/imgs/handmade_win32_2023-10-21_02-16-43.png) ![img](docs/imgs/handmade_win32_2023-10-20_23-14-37.png) diff --git a/docs/imgs/10x_2023-10-22_01-44-21.gif b/docs/imgs/10x_2023-10-22_01-44-21.gif new file mode 100644 index 0000000..f06c1b7 Binary files /dev/null and b/docs/imgs/10x_2023-10-22_01-44-21.gif differ diff --git a/project/platform/compiler_ignores.hpp b/project/platform/compiler_ignores.hpp index 2668919..f76eb73 100644 --- a/project/platform/compiler_ignores.hpp +++ b/project/platform/compiler_ignores.hpp @@ -1,3 +1,5 @@ +#pragma once + #ifdef _MSC_VER #pragma warning( disable: 4201 ) // Support for non-standard nameless struct or union extesnion #pragma warning( disable: 4100 ) // Support for unreferenced formal parameters diff --git a/project/platform/win32/win32.hpp b/project/platform/win32/win32.hpp index 7ad4f86..5c22351 100644 --- a/project/platform/win32/win32.hpp +++ b/project/platform/win32/win32.hpp @@ -59,7 +59,7 @@ enum CS : UINT CS_Horizontal_Redraw = CS_HREDRAW, CS_Vertical_Redraw = CS_VREDRAW, }; - + enum CW : s32 { CW_Use_Default = CW_USEDEFAULT, diff --git a/project/platform/win32/win32_platform.cpp b/project/platform/win32/win32_platform.cpp index c7b33ae..052beb1 100644 --- a/project/platform/win32/win32_platform.cpp +++ b/project/platform/win32/win32_platform.cpp @@ -14,10 +14,7 @@ - Asset loading path - Threading (launch a thread) - Raw Input (support for multiple keyboards) - - Sleep / timeBeginPeriod - ClipCursor() (for multimonitor support) - - Fullscreen support - - WM_SETCURSOR (control cursor visibility) - QueryCancelAutoplay - WM_ACTIVATEAPP (for when not active) - Blit speed improvemnts (BitBlt) @@ -64,6 +61,10 @@ global StrPath Path_Scratch; // TODO(Ed) : This is a global for now. global b32 Running = false; +global b32 Show_Windows_Cursor; +global HCURSOR Windows_Cursor; +global WINDOWPLACEMENT Window_Position; + global WinDimensions Window_Dimensions; global OffscreenBuffer Surface_Back_Buffer; @@ -145,6 +146,37 @@ NS_PLATFORM_END NS_PLATFORM_BEGIN #pragma region Windows Sandbox Interface +internal +void toggle_fullscreen( HWND window_handle ) +{ + // Note(Ed) : Follows: https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353 + DWORD style = GetWindowLongA( window_handle, GWL_STYLE ); + if ( style & WS_OVERLAPPEDWINDOW ) + { + MONITORINFO info = { sizeof(MONITORINFO) }; + HMONITOR monitor_handle = MonitorFromWindow( window_handle, MONITOR_DEFAULTTOPRIMARY ); + + if ( GetWindowPlacement( window_handle, & Window_Position ) + && GetMonitorInfoA( monitor_handle, & info ) ) + { + SetWindowLongA( window_handle, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW ); + SetWindowPos( window_handle, HWND_TOP + , info.rcMonitor.left, info.rcMonitor.top + , info.rcWork.right - info.rcMonitor.left, info.rcMonitor.bottom - info.rcMonitor.top + , SWP_NOOWNERZORDER | SWP_FRAMECHANGED + ); + } + } + else + { + SetWindowLongA( window_handle, GWL_STYLE , style | WS_OVERLAPPEDWINDOW ); + SetWindowPlacement( window_handle, & Window_Position ); + SetWindowPos( window_handle, NULL + , 0, 0, 0, 0 + , SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED ); + } +} + internal WinDimensions get_window_dimensions( HWND window_handle ) { @@ -161,6 +193,19 @@ display_buffer_in_window( HDC device_context, s32 window_width, s32 window_heigh , s32 x, s32 y , s32 width, s32 height ) { + if ( (window_width % buffer->width ) == 0 + && (window_height % buffer->height) == 0 ) + { + // TODO(Ed) : Aspect ratio correction + StretchDIBits( device_context + , 0, 0, window_width, window_height + , 0, 0, buffer->width, buffer->height + , buffer->memory, & buffer->info + , DIB_ColorTable_RGB, RO_Source_To_Dest ); + + return; + } + s32 offset_x = 0; s32 offset_y = 0; @@ -259,7 +304,7 @@ main_window_callback( HWND handle } else { - // SetLayeredWindowAttributes( handle, RGB(0, 0, 0), 120, LWA_Alpha ); +// SetLayeredWindowAttributes( handle, RGB(0, 0, 0), 120, LWA_Alpha ); } } break; @@ -296,21 +341,31 @@ main_window_callback( HWND handle } break; + // TODO(Ed) : Expose cursor toggling to engine via platform api (lets game control it for its ux purposes) case WM_MOUSEMOVE: { - RECT rect; - POINT pt = { LOWORD(l_param), HIWORD(l_param) }; - GetClientRect(handle, &rect); - if (PtInRect(&rect, pt)) + while (ShowCursor(FALSE) >= 0); + } + break; + + case WM_NCMOUSEMOVE: + { + // Show the cursor when it's outside the window's client area (i.e., on the frame or elsewhere) + while (ShowCursor(TRUE) < 0); + } + break; + + case WM_SETCURSOR: + { + if ( Show_Windows_Cursor ) { - // Hide the cursor when it's inside the window - // while (ShowCursor(FALSE) >= 0); +// SetCursor( Windows_Cursor ); + result = DefWindowProc( handle, system_messages, w_param, l_param ); } else { - // Show the cursor when it's outside the window - // while (ShowCursor(TRUE) < 0); + SetCursor(NULL); } } break; @@ -330,7 +385,7 @@ main_window_callback( HWND handle } internal void -process_pending_window_messages( engine::KeyboardState* keyboard, engine::MousesState* mouse ) +process_pending_window_messages( HWND window_handle, engine::KeyboardState* keyboard, engine::MousesState* mouse ) { MSG window_msg_info; while ( PeekMessageA( & window_msg_info, 0, 0, 0, PM_Remove_Messages_From_Queue ) ) @@ -342,7 +397,7 @@ process_pending_window_messages( engine::KeyboardState* keyboard, engine::Mouses } // Keyboard input handling - switch (window_msg_info.message) + switch (window_msg_info.message) { // I rather do this with GetAsyncKeyState... case WM_SYSKEYDOWN: @@ -361,6 +416,13 @@ process_pending_window_messages( engine::KeyboardState* keyboard, engine::Mouses Running = false; } break; + case VK_F10: + { + // TODO(Ed) : Expose this feature via platform_api to engine. Let the game toggle via the its action binds. + if ( is_down ) + toggle_fullscreen( window_handle ); + } + break; } } break; @@ -622,10 +684,14 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho // window_class.cbWndExtra = ; window_class.hInstance = instance; // window_class.hIcon = ; - // window_class.hCursor = ; + window_class.hCursor = LoadCursorW( 0, IDC_ARROW ); // window_class.hbrBackground = ; window_class.lpszMenuName = L"Handmade Hero!"; window_class.lpszClassName = L"HandmadeHeroWindowClass"; + + Show_Windows_Cursor = true; + Windows_Cursor = LoadCursorW( 0, IDC_CROSS ); + Window_Position = {sizeof(WINDOWPLACEMENT)}; if ( ! RegisterClassW( & window_class ) ) { @@ -895,7 +961,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho } } - process_pending_window_messages( new_keyboard, new_mouse ); + process_pending_window_messages( window_handle, new_keyboard, new_mouse ); // f32 delta_time = timing_get_seconds_elapsed( last_frame_clock, timing_get_wall_clock() ); diff --git a/scripts/build.ps1 b/scripts/build.ps1 index d421f8f..1ac548c 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -64,7 +64,7 @@ function check-FileForChanges return $false } $file_name = Split-Path $path_file -Leaf - $path_csv = Join-Path $path_build ($file_name + "_file_hash.csv") + $path_csv = Join-Path $path_build ($file_name + "_file_hash.csv") $csv_file_hash = $null if (Test-Path $path_csv) { @@ -385,6 +385,9 @@ function build-platform } write-host "Building Platform Module" -ForegroundColor Green + $local:includes = $script:includes + $includes += $path_platform + # CodeGen Pre-Build $path_engine_symbols = Join-Path $path_engine_gen 'engine_symbols.gen.hpp' $unit = Join-Path $path_codegen 'platform_gen.cpp' @@ -404,9 +407,6 @@ function build-platform New-Item $path_platform_gen -ItemType Directory > $null } - $local:includes = $script:includes - $includes += $path_platform - $local:compiler_args = @() $compiler_args += ( $flag_define + 'GEN_TIME' )