diff --git a/.vscode/launch.json b/.vscode/launch.json index 30f2117..88c6c82 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,9 +8,9 @@ "type":"cppvsdbg", "request": "launch", "name" : "Debug handmade win32 msvc", - "program": "${workspaceFolder}/data/handmade_win32.exe", + "program": "${workspaceFolder}/data/binaries/handmade_win32.exe", "args": [], - "cwd": "${workspaceFolder}/data", + "cwd": "${workspaceFolder}/data/binaries/", "visualizerFile": "${workspaceFolder}/scripts/handmade.natvis" } ] diff --git a/HandmadeHero.10x b/HandmadeHero.10x index 7e5a044..6867f9e 100644 --- a/HandmadeHero.10x +++ b/HandmadeHero.10x @@ -14,10 +14,10 @@ pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(WorkspaceDirectory)/scripts/clean.ps1 - $(WorkspaceDirectory)/data/handmade_win32.exe - $(WorkspaceDirectory)/data - $(WorkspaceDirectory)/data/handmade_win32.exe - $(WorkspaceDirectory)/data/handmade_win32.exe + $(WorkspaceDirectory)/data/binaries/handmade_win32.exe + $(WorkspaceDirectory)/data/binaries + $(WorkspaceDirectory)/data/binaries/handmade_win32.exe + $(WorkspaceDirectory)/data/binaries/handmade_win32.exe true diff --git a/HandmadeHero.vcxproj b/HandmadeHero.vcxproj index 13e3e2c..35ef6ad 100644 --- a/HandmadeHero.vcxproj +++ b/HandmadeHero.vcxproj @@ -25,34 +25,25 @@ - + + - - - - - - - - - + - - + - @@ -68,6 +59,9 @@ + + + diff --git a/HandmadeHero.vcxproj.user b/HandmadeHero.vcxproj.user index 977a45d..7327b47 100644 --- a/HandmadeHero.vcxproj.user +++ b/HandmadeHero.vcxproj.user @@ -4,8 +4,8 @@ true - $(ProjectDir)data + $(ProjectDir)data\binaries WindowsLocalDebugger - $(ProjectDir)data\handmade_win32.exe + $(ProjectDir)data\binaries\handmade_win32.exe \ No newline at end of file diff --git a/data/binaries/handmade_engine.symbols b/data/binaries/handmade_engine.symbols new file mode 100644 index 0000000..fb9320c --- /dev/null +++ b/data/binaries/handmade_engine.symbols @@ -0,0 +1,5 @@ +?on_module_reload@engine@@YAXPEAUMemory@1@PEAUModuleAPI@platform@@@Z +?startup@engine@@YAXPEAUMemory@1@PEAUModuleAPI@platform@@@Z +?shutdown@engine@@YAXPEAUMemory@1@PEAUModuleAPI@platform@@@Z +?update_and_render@engine@@YAXPEAUInputState@1@PEAUOffscreenBuffer@1@PEAUMemory@1@PEAUModuleAPI@platform@@@Z +?update_audio@engine@@YAXPEAUAudioBuffer@1@PEAUMemory@1@PEAUModuleAPI@platform@@@Z diff --git a/data/binaries/handmade_engine_2023-09-27_00-53-51.pdb b/data/binaries/handmade_engine_2023-09-27_00-53-51.pdb new file mode 100644 index 0000000..984f94a Binary files /dev/null and b/data/binaries/handmade_engine_2023-09-27_00-53-51.pdb differ diff --git a/data/binaries/handmade_win32.exe b/data/binaries/handmade_win32.exe new file mode 100644 index 0000000..aecc82b Binary files /dev/null and b/data/binaries/handmade_win32.exe differ diff --git a/data/binaries/handmade_win32_2023-09-27_00-48-05.pdb b/data/binaries/handmade_win32_2023-09-27_00-48-05.pdb new file mode 100644 index 0000000..db72b65 Binary files /dev/null and b/data/binaries/handmade_win32_2023-09-27_00-48-05.pdb differ diff --git a/docs/Day 022.md b/docs/Day 022.md new file mode 100644 index 0000000..d8aff3a --- /dev/null +++ b/docs/Day 022.md @@ -0,0 +1,2 @@ +# Day 22 + diff --git a/project/engine/engine.cpp b/project/engine/engine.cpp index d8a1e58..64c0387 100644 --- a/project/engine/engine.cpp +++ b/project/engine/engine.cpp @@ -110,7 +110,7 @@ render_weird_graident(OffscreenBuffer* buffer, u32 x_offset, u32 y_offset ) u8 red = 0; #endif - *pixel++ = u32(red << 16) | u32(green << 8) | blue; + *pixel++ = u32(red << 16) | u32(green/2 << 16) | blue/2 << 0; } wildcard += 0.5375f; row += buffer->Pitch; diff --git a/project/engine/engine.hpp b/project/engine/engine.hpp index 17e6d2d..7538d58 100644 --- a/project/engine/engine.hpp +++ b/project/engine/engine.hpp @@ -50,7 +50,6 @@ struct AudioBuffer u32 RunningSampleIndex; s32 SamplesPerSecond; s32 NumSamples; - char _PAD_[4]; }; struct DigitalBtn @@ -190,7 +189,6 @@ struct InputMode { InputBindCallback* Binds; s32 NumBinds; - char _PAD_[4]; }; void input_mode_pop( InputMode* mode ); diff --git a/project/engine/engine_game_api.hpp b/project/engine/engine_game_api.hpp new file mode 100644 index 0000000..a08c78e --- /dev/null +++ b/project/engine/engine_game_api.hpp @@ -0,0 +1,3 @@ +/* + This represents the API only accessible to the engine to fullfill for the game module. +*/ diff --git a/project/engine/win32_engine.cpp b/project/engine/win32_engine.cpp deleted file mode 100644 index 3f7f7a7..0000000 --- a/project/engine/win32_engine.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "platform/win32.hpp" -#include "engine.hpp" - -b32 WINAPI DllMain( - HINSTANCE instance, - DWORD reason_for_call, - LPVOID reserved -) -{ - return true; -} diff --git a/project/handmade.hpp b/project/handmade.hpp index f0bd3b6..f84775b 100644 --- a/project/handmade.hpp +++ b/project/handmade.hpp @@ -27,7 +27,6 @@ struct Actionable char const* Name; engine::InputBindCallback* Binds; s32 NumBinds; - char _PAD_[4]; }; struct ActionableMode diff --git a/project/handmade_engine.cpp b/project/handmade_engine.cpp index 419e824..8925068 100644 --- a/project/handmade_engine.cpp +++ b/project/handmade_engine.cpp @@ -13,7 +13,4 @@ #if Build_Unity # include "engine/engine.cpp" -# if SYSTEM_WINDOWS -# include "engine/win32_engine.cpp" -# endif #endif diff --git a/project/platform/platform.hpp b/project/platform/platform.hpp index 92ac416..50eac50 100644 --- a/project/platform/platform.hpp +++ b/project/platform/platform.hpp @@ -16,6 +16,8 @@ #pragma warning( disable: 4514 ) // Support for unused inline functions #pragma warning( disable: 4505 ) // Support for unused static functions #pragma warning( disable: 5045 ) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +#pragma warning( disable: 5264 ) // Support for 'const' variables unused +#pragma warning( disable: 4820 ) // Support auto-adding padding to structs // TODO(Ed) : REMOVE THESE WHEN HE GETS TO THEM #include // TODO : Implement math ourselves @@ -26,6 +28,7 @@ #include "generics.hpp" #include "math_constants.hpp" #include "types.hpp" +#include "strings.hpp" #define NS_PLATFORM_BEGIN namespace platform { #define NS_PLATFORM_END } @@ -45,7 +48,12 @@ struct Debug_FileContent { void* Data; u32 Size; - char _PAD_[4]; + Byte _PAD_[4]; +}; + +struct BinaryModule +{ + void* OpaqueHandle; }; using DebugFileFreeContentFn = void ( Debug_FileContent* file_content ); @@ -53,9 +61,54 @@ using DebugFileReadContentFn = Debug_FileContent ( char const* file_path ); using DebugFileWriteContentFn = b32 ( char const* file_path, u32 content_size, void* content_memory ); using DebugSetPauseRenderingFn = void (b32 value); + +// TODO(Ed): This also assumes the symbol name is always within size of the provided buffer, needs to fail if not. +// Note: This is a temporary solution until there is more infrastructure for the engine to use. +void get_symbol_from_module_table( Debug_FileContent symbol_table, u32 symbol_ID, char* symbol_name ) +{ + struct Token + { + char const* Ptr; + u32 Len; + char _PAD_[4]; + }; + + Token tokens[256] = {}; + s32 idx = 0; + + char const* scanner = rcast( char const*, symbol_table.Data ); + u32 left = symbol_table.Size; + while ( left ) + { + if ( *scanner == '\n' || *scanner == '\r' ) + { + ++ scanner; + -- left; + } + else + { + tokens[idx].Ptr = scanner; + while ( left && *scanner != '\r' && *scanner != '\n' ) + { + -- left; + ++ scanner; + ++ tokens[idx].Len; + } + ++ idx; + } + } + + Token& token = tokens[symbol_ID]; + while ( token.Len -- ) + { + *symbol_name = *token.Ptr; + ++ symbol_name; + ++ token.Ptr; + } + *symbol_name = '\0'; +} #endif -// TODO(Ed) : Implement this later when settings UI is setup. #pragma region Settings Exposure // Exposing specific properties for user configuration in settings @@ -68,6 +121,13 @@ using SetMonitorRefreshRateFn = void ( u32 rate_in_hz ); using GetEngineFrameTargetFn = u32 (); using SetEngineFrameTargetFn = void ( u32 rate_in_hz ); +// This module api will be used to manage the editor and game modules from the engine side, +// without the platform layer needing to know about it. + +using LoadBinaryModuleFn = BinaryModule ( char const* module_path ); +using UnloadBinaryModuleFn = void ( BinaryModule* module ); +using GetModuleProcedureFn = void* ( BinaryModule module, char const* symbol ); + struct ModuleAPI { #if Build_Development @@ -83,6 +143,10 @@ struct ModuleAPI GetEngineFrameTargetFn* get_engine_frame_target; SetEngineFrameTargetFn* set_engine_frame_target; + + LoadBinaryModuleFn* load_binary_module; + UnloadBinaryModuleFn* unload_binary_module; + GetModuleProcedureFn* get_module_procedure; }; #pragma endregion Settings Exposure diff --git a/project/platform/platform_engine_api.hpp b/project/platform/platform_engine_api.hpp index 0a0cd41..10c629a 100644 --- a/project/platform/platform_engine_api.hpp +++ b/project/platform/platform_engine_api.hpp @@ -42,7 +42,6 @@ struct ModuleAPI UpdateAudioFn* update_audio; b32 IsValid; - char _PAD_[4]; }; NS_ENGINE_END diff --git a/project/platform/platform_game_api.hpp b/project/platform/platform_game_api.hpp deleted file mode 100644 index 9186eab..0000000 --- a/project/platform/platform_game_api.hpp +++ /dev/null @@ -1,3 +0,0 @@ -/* - This represents the API only accessible to the platform layer to fullfill for the game layer. -*/ diff --git a/project/platform/strings.hpp b/project/platform/strings.hpp new file mode 100644 index 0000000..a8bd1f7 --- /dev/null +++ b/project/platform/strings.hpp @@ -0,0 +1,190 @@ +#include "macros.hpp" +#include "types.hpp" + +void str_append( u32 dest_len, char* dest, u32 src_len, char const* src ); +void str_concat( u32 dest_size, char* dest + , u32 str_a_len, char const* str_a + , u32 str_b_len, char const* str_b ); +u32 str_length( char const* str ); + +#define str_ascii( str ) { sizeof( str ) - 1, str } + +// Length tracked raw strings. +struct Str +{ + u32 Len; + char* Data; + + void append( u32 src_len, char const* src ) { + str_append( Len, Data, src_len, src ); + } + void append( Str const src ) { + str_append( Len, Data, src.Len, src.Data ); + } + + static + void concast( u32 dest_size, Str* dest, Str const str_a, Str const str_b ) + { + str_concat( dest_size, dest->Data + , str_a.Len, str_a.Data + , str_b.Len, str_b.Data ); + dest->Len = str_a.Len + str_b.Len; + } + + operator char*() const { + return Data; + } + char& operator []( u32 idx ) { + return Data[idx]; + } + char const& operator []( u32 idx ) const { + return Data[idx]; + } +}; + +template< u32 capacity > +// Fixed length raw strings. +struct StrFixed +{ + constexpr static u32 Capacity = capacity; + + u32 Len; + char Data[capacity]; + + void append( u32 src_len, char const* src ) { + str_append( Len, Data, src_len, src ); + } + void append( Str const src ) { + str_append( Len, Data, src.Len, src.Data ); + } + + void concat( Str const str_a, Str const str_b ) + { + str_concat( Capacity, Data + , str_a.Len, str_a.Data + , str_b.Len, str_b.Data ); + Len = str_a.Len + str_b.Len; + } + + operator char*() { return Data;} + operator char const*() { return Data; } + operator Str() { return { Len, Data }; } + operator Str const() const { return { Len, Data }; } + char& operator []( u32 idx ) { + assert( idx < Capacity ); + return Data[idx]; + } + char const& operator []( u32 idx ) const { + assert( idx < Capacity ); + return Data[idx]; + } +}; + +inline +void str_append( u32 dest_len, char* dest, u32 src_len, char const* src ) +{ + assert( dest_len > 0 ); + assert( dest != nullptr ); + assert( src_len > 0 ); + assert( src != nullptr ); + assert( dest_len >= src_len ); + + char* dest_end = dest + dest_len; + assert( *dest_end == '\0' ); + + u32 left = src_len; + while ( left-- ) + { + *dest = *src; + ++ dest; + ++ src; + } +} + +void str_concat( u32 dest_size, char* dest + , u32 str_a_len, char const* str_a + , u32 str_b_len, char const* str_b ) +{ + assert( dest_size > 0 ); + assert( dest != nullptr ); + assert( *dest == '\0' ); + assert( str_a_len > 0 ); + assert( str_a != nullptr ); + assert( str_b_len > 0 ); + assert( str_b != nullptr ); + assert( str_a_len + str_b_len < dest_size ); + + char* dest_a = dest; + char* dest_b = dest + str_a_len; + if ( str_a_len > str_b_len ) + { + u32 left = str_a_len; + while ( left-- ) + { + *dest_a = *str_a; + *dest_b = *str_b; + + ++ dest_a; + ++ dest_b; + ++ str_a; + ++ str_b; + } + + left = str_a_len - str_b_len; + while ( left-- ) + { + *dest_b = *str_b; + ++ dest_b; + ++ str_b; + } + } + else if ( str_a_len < str_b_len ) + { + u32 left = str_b_len; + while ( left-- ) + { + *dest_a = *str_a; + *dest_b = *str_b; + ++ dest_a; + ++ dest_b; + ++ str_a; + ++ str_b; + } + + left = str_b_len - str_a_len; + while ( left-- ) + { + *dest_a = *str_a; + ++ dest_a; + ++ str_a; + } + } + else + { + u32 left = str_a_len; + while ( left-- ) + { + *dest_a = *str_a; + *dest_b = *str_b; + ++ dest_a; + ++ str_a; + ++ dest_b; + ++ str_b; + } + } +} + +inline +u32 str_length( char const* str ) +{ + assert( str != nullptr ); + + u32 result = 0; + while ( *str != '\0' ) + { + ++ result; + ++ str; + } + + return result; +} diff --git a/project/platform/types.hpp b/project/platform/types.hpp index 2e4f990..4bbcdbf 100644 --- a/project/platform/types.hpp +++ b/project/platform/types.hpp @@ -97,6 +97,9 @@ static_assert( sizeof( uptr ) == sizeof( sptr ), "sizeof(uptr) != sizeof(sptr)" typedef float f32; typedef double f64; +struct Byte {}; +static_assert( sizeof( Byte ) == 1, "Unit type must be 1 byte in size" ); + static_assert( sizeof( f32 ) == 4, "sizeof(f32) != 4" ); static_assert( sizeof( f64 ) == 8, "sizeof(f64) != 8" ); diff --git a/project/platform/win32_platform.cpp b/project/platform/win32_platform.cpp index dd8f8a1..562c818 100644 --- a/project/platform/win32_platform.cpp +++ b/project/platform/win32_platform.cpp @@ -101,6 +101,16 @@ struct DirectSoundBuffer #pragma region Static Data + +global StrFixed< S16_MAX > Path_Root; +global StrFixed< S16_MAX > Path_Binaries; + +constexpr Str FName_Engine_DLL = str_ascii("handmade_engine.dll"); +constexpr Str FName_Engine_DLL_InUse = str_ascii("handmade_engine_in_use.dll"); + +global StrFixed< S16_MAX > Path_Engine_DLL; +global StrFixed< S16_MAX > Path_Engine_DLL_InUse; + // TODO(Ed) : This is a global for now. global b32 Running = false; global b32 Pause_Rendering = false; @@ -130,7 +140,7 @@ global u32 Engine_Refresh_Hz = Monitor_Refresh_Hz / 2; global f32 Engine_Frame_Target_MS = 1000.f / scast(f32, Engine_Refresh_Hz); #pragma endregion Static Data - +#pragma region Internal #if Build_Debug struct DebugTimeMarker { @@ -145,82 +155,6 @@ struct DebugTimeMarker DWORD ExpectedFlipCursor; }; -void debug_file_free_content( Debug_FileContent* content ) -{ - if ( content->Data) - { - VirtualFree( content->Data, 0, MEM_Release); - *content = {}; - } -} - -Debug_FileContent debug_file_read_content( char const* file_path ) -{ - Debug_FileContent result {}; - - HANDLE file_handle = CreateFileA( file_path - , GENERIC_READ, FILE_SHARE_READ, 0 - , OPEN_EXISTING, 0, 0 - ); - if ( file_handle == INVALID_HANDLE_VALUE ) - { - // TODO(Ed) : Logging - return result; - } - - GetFileSizeEx( file_handle, rcast(LARGE_INTEGER*, &result.Size) ); - if ( result.Size == 0 ) - { - // TODO(Ed) : Logging - return result; - } - result.Data = VirtualAlloc( 0, result.Size, MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ); - - u32 bytes_read; - if ( ReadFile( file_handle, result.Data, result.Size, rcast(LPDWORD, &bytes_read), 0 ) == false ) - { - // TODO(Ed) : Logging - return {}; - } - - if ( bytes_read != result.Size ) - { - // TODO : Logging - return {}; - } - - CloseHandle( file_handle ); - return result; -} - -b32 debug_file_write_content( char const* file_path, u32 content_size, void* content_memory ) -{ - HANDLE file_handle = CreateFileA( file_path - , GENERIC_WRITE, 0, 0 - , CREATE_ALWAYS, 0, 0 - ); - if ( file_handle == INVALID_HANDLE_VALUE ) - { - // TODO : Logging - return false; - } - - DWORD bytes_written; - if ( WriteFile( file_handle, content_memory, content_size, & bytes_written, 0 ) == false ) - { - // TODO : Logging - return false; - } - - CloseHandle( file_handle ); - return true; -} - -void debug_set_pause_rendering( b32 value ) -{ - Pause_Rendering = value; -} - internal void debug_draw_vertical( s32 x_pos, s32 top, s32 bottom, s32 color ) { @@ -748,84 +682,144 @@ process_pending_window_messages( engine::KeyboardState* keyboard ) } } } +#pragma endregion Internal #pragma region Platfom API -u32 get_monitor_refresh_rate(); - -#pragma endregion Platform API - -// TODO(Ed): This also assumes the symbol name is always within size of the provided buffer, needs to fail if not. -void get_symbol_from_module_table( Debug_FileContent symbol_table, u32 symbol_ID, char* symbol_name ) +#if Build_Development +void debug_file_free_content( Debug_FileContent* content ) { - struct Token + if ( content->Data) { - char const* Ptr; - u32 Len; - char _PAD_[4]; - }; - - Token tokens[256] = {}; - s32 idx = 0; - - char const* scanner = rcast( char const*, symbol_table.Data ); - u32 left = symbol_table.Size; - while ( left ) - { - if ( *scanner == '\n' || *scanner == '\r' ) - { - ++ scanner; - -- left; - } - else - { - tokens[idx].Ptr = scanner; - while ( left && *scanner != '\r' && *scanner != '\n' ) - { - -- left; - ++ scanner; - ++ tokens[idx].Len; - } - ++ idx; - } + VirtualFree( content->Data, 0, MEM_Release); + *content = {}; } - - Token& token = tokens[symbol_ID]; - while ( token.Len -- ) - { - *symbol_name = *token.Ptr; - ++ symbol_name; - ++ token.Ptr; - } - *symbol_name = '\0'; } -// Right now they are just the data directory -#define Path_To_Symbol_Tables +Debug_FileContent debug_file_read_content( char const* file_path ) +{ + Debug_FileContent result {}; + HANDLE file_handle = CreateFileA( file_path + , GENERIC_READ, FILE_SHARE_READ, 0 + , OPEN_EXISTING, 0, 0 + ); + if ( file_handle == INVALID_HANDLE_VALUE ) + { + // TODO(Ed) : Logging + return result; + } + + GetFileSizeEx( file_handle, rcast(LARGE_INTEGER*, &result.Size) ); + if ( result.Size == 0 ) + { + // TODO(Ed) : Logging + return result; + } + result.Data = VirtualAlloc( 0, result.Size, MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ); + + u32 bytes_read; + if ( ReadFile( file_handle, result.Data, result.Size, rcast(LPDWORD, &bytes_read), 0 ) == false ) + { + // TODO(Ed) : Logging + return {}; + } + + if ( bytes_read != result.Size ) + { + // TODO : Logging + return {}; + } + + CloseHandle( file_handle ); + return result; +} + +b32 debug_file_write_content( char const* file_path, u32 content_size, void* content_memory ) +{ + HANDLE file_handle = CreateFileA( file_path + , GENERIC_WRITE, 0, 0 + , CREATE_ALWAYS, 0, 0 + ); + if ( file_handle == INVALID_HANDLE_VALUE ) + { + // TODO : Logging + return false; + } + + DWORD bytes_written; + if ( WriteFile( file_handle, content_memory, content_size, & bytes_written, 0 ) == false ) + { + // TODO : Logging + return false; + } + + CloseHandle( file_handle ); + return true; +} + +void debug_set_pause_rendering( b32 value ) +{ + Pause_Rendering = value; +} +#endif + +u32 get_monitor_refresh_rate(); + +BinaryModule load_binary_module( char const* module_path ) +{ + HMODULE lib = LoadLibraryA( module_path ); + return BinaryModule { scast(void*, lib) }; +} + +void unload_binary_module( BinaryModule* module ) +{ + FreeLibrary( scast(HMODULE, module->OpaqueHandle) ); + *module = {}; +} + +void* get_binary_module_symbol( BinaryModule module, char const* symbol_name ) +{ + return rcast(void*, GetProcAddress( scast(HMODULE, module.OpaqueHandle), symbol_name )); +} +#pragma endregion Platform API + +FILETIME file_get_last_write_time( char const* path ) +{ + WIN32_FIND_DATAA dll_file_info = {}; + HANDLE dll_file_handle = FindFirstFileA( path, & dll_file_info ); + if ( dll_file_handle == INVALID_HANDLE_VALUE ) + { + FindClose( dll_file_handle ); + } + + return dll_file_info.ftLastWriteTime; +} + +#pragma region Engine Module API global HMODULE Lib_Handmade_Engine = nullptr; engine::ModuleAPI load_engine_module_api() { using ModuleAPI = engine::ModuleAPI; - // TODO(Ed) : Need proper paything to the dll (not assume is in the base directory). - - CopyFileA( "handmade_engine.dll", "handmade_engine_temp.dll", FALSE ); + CopyFileA( Path_Engine_DLL, Path_Engine_DLL_InUse, FALSE ); // Engine - Lib_Handmade_Engine = LoadLibraryA( "handmade_engine_temp.dll" ); + Lib_Handmade_Engine = LoadLibraryA( Path_Engine_DLL_InUse ); if ( ! Lib_Handmade_Engine ) { return {}; } - constexpr char const* - handmade_engine_symbols = Path_To_Symbol_Tables "handmade_engine.symbols"; + constexpr Str fname_handmade_engine_symbols = str_ascii("handmade_engine.symbols"); - Debug_FileContent symbol_table = debug_file_read_content( handmade_engine_symbols ); + StrFixed< S16_MAX > path_handmade_engine_symbols { 0, {} }; + path_handmade_engine_symbols.concat( Path_Binaries, fname_handmade_engine_symbols ); + + Debug_FileContent symbol_table = debug_file_read_content( path_handmade_engine_symbols ); if ( symbol_table.Size == 0 ) { - fatal( "Failed to laod symbol table for handmade engine module!" ); + fatal( "Failed to load symbol table for handmade engine module!" ); return {}; } @@ -872,6 +866,7 @@ void unload_engine_module_api( engine::ModuleAPI* engine_api ) OutputDebugStringA( "Unloaded engine module API\n" ); } } +#pragma endregion Engine Module API NS_PLATFORM_END @@ -910,6 +905,10 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho platform_api.set_monitor_refresh_rate = nullptr; platform_api.get_engine_frame_target = nullptr; platform_api.set_engine_frame_target = nullptr; + + platform_api.load_binary_module = & load_binary_module; + platform_api.unload_binary_module = & unload_binary_module; + platform_api.get_module_procedure = & get_binary_module_symbol; } // Memory @@ -940,9 +939,6 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho } } - // Load engine module - engine::ModuleAPI engine_api = load_engine_module_api(); - WNDCLASSW window_class {}; HWND window_handle = nullptr; { @@ -983,6 +979,41 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho // WinDimensions dimensions = get_window_dimensions( window_handle ); resize_dib_section( &Surface_Back_Buffer, 1280, 720 ); + // Setup pathing + // TODO(Ed): This will not support long paths, NEEDS to be changed to support long paths. + { + char path_buffer[S16_MAX]; + GetModuleFileNameA( 0, path_buffer, sizeof(path_buffer) ); + + if ( GetCurrentDirectoryA( S16_MAX, Path_Binaries ) == 0 ) + { + fatal( "Failed to get the root directory!" ); + } + Path_Binaries.Len = str_length( Path_Binaries ); + Path_Binaries[ Path_Binaries.Len ] = '\\'; + ++ Path_Binaries.Len; + + if ( SetCurrentDirectoryA( ".." ) == 0 ) + { + fatal( "Failed to set current directory to root!"); + } + + if ( GetCurrentDirectoryA( S16_MAX, Path_Root.Data ) == 0 ) + { + fatal( "Failed to get the root directory!" ); + } + Path_Root.Len = str_length(Path_Root.Data); + Path_Root.Data[ Path_Root.Len ] = '\\'; + ++ Path_Root.Len; + + Path_Engine_DLL. concat( Path_Binaries, FName_Engine_DLL ); + Path_Engine_DLL_InUse.concat( Path_Binaries, FName_Engine_DLL_InUse ); + } + + // Load engine module + FILETIME engine_api_load_time = file_get_last_write_time( Path_Engine_DLL ); + engine::ModuleAPI engine_api = load_engine_module_api(); + b32 sound_is_valid = false; DWORD ds_cursor_byte_delta = 0; f32 ds_latency_ms = 0; @@ -1091,8 +1122,6 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho OutputDebugStringA( text_buffer ); #endif - u64 module_reload_counter = 0; - Running = true; #if 0 // This tests the play & write cursor update frequency. @@ -1109,13 +1138,13 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho #endif while( Running ) { - if ( module_reload_counter > 120 ) + FILETIME engine_api_current_time = file_get_last_write_time( Path_Engine_DLL ); + if ( CompareFileTime( & engine_api_load_time, & engine_api_current_time ) != 0 ) { + engine_api_load_time = engine_api_current_time; unload_engine_module_api( & engine_api ); engine_api = load_engine_module_api(); - module_reload_counter = 0; } - ++ module_reload_counter; process_pending_window_messages( new_keyboard ); @@ -1490,6 +1519,9 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho engine_api.shutdown( & engine_memory, & platform_api ); + unload_engine_module_api( & engine_api ); + DeleteFileA( Path_Engine_DLL_InUse ); + if ( jsl_num_devices > 0 ) { for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index ) diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 2187381..5af17d3 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -51,7 +51,7 @@ write-host "Building HandmadeHero with $vendor" if ( $dev ) { if ( $debug -eq $null ) { - # $debug = $true + $debug = $true } if ( $optimize -eq $null ) { @@ -194,9 +194,12 @@ if ( $vendor -match "clang" ) param( [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary ) Write-Host "build-simple: clang" - $object = $binary -replace '\.exe', '.obj' - $pdb = $binary -replace '\.exe', '.pdb' - $map = $binary -replace '\.exe', '.map' + $object = $unit -replace '\.cpp', '.obj' + $map = $unit -replace '\.cpp', '.map' + + # The PDB file has to also be time-stamped so that we can reload the DLL at runtime + $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss" + $pdb = $binary -replace '\.(exe|dll)$', "_$timestamp.pdb" $compiler_args += @( $flag_no_color_diagnostics, @@ -275,6 +278,7 @@ if ( $vendor -match "msvc" ) $flag_dll_debug = '/LDd' $flag_linker = '/link' $flag_link_dll = '/DLL' + $flag_link_no_incremental = '/INCREMENTAL:NO' $flag_link_mapfile = '/MAP:' $flag_link_optimize_references = '/OPT:REF' $flag_link_win_debug = '/DEBUG' @@ -309,9 +313,14 @@ if ( $vendor -match "msvc" ) param( [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary ) Write-Host "build-simple: msvc" - $object = $binary -replace '\.(exe|dll)$', '.obj' - $pdb = $binary -replace '\.(exe|dll)$', '.pdb' - $map = $binary -replace '\.(exe|dll)$', '.map' + $object = $unit -replace '\.(cpp)$', '.obj' + $map = $unit -replace '\.(cpp)$', '.map' + $object = $object -replace '\bproject\b', 'build' + $map = $map -replace '\bproject\b', 'build' + + # The PDB file has to also be time-stamped so that we can reload the DLL at runtime + $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss" + $pdb = $binary -replace '\.(exe|dll)$', "_$timestamp.pdb" $compiler_args += @( $flag_nologo, @@ -355,6 +364,7 @@ if ( $vendor -match "msvc" ) $linker_args += @( $flag_nologo, $flag_link_win_machine_64, + $flag_link_no_incremental, ( $flag_link_win_path_output + $binary ) ) if ( $debug ) { @@ -383,6 +393,7 @@ if ( $vendor -match "msvc" ) $path_project = Join-Path $path_root 'project' $path_build = Join-Path $path_root 'build' $path_data = Join-Path $path_root 'data' +$path_binaries = Join-Path $path_data 'binaries' $path_deps = Join-Path $path_project 'dependencies' $path_gen = Join-Path $path_project 'gen' $path_platform = Join-Path $path_project 'platform' @@ -398,6 +409,10 @@ if ( (Test-Path $path_deps) -eq $false ) { & $update_deps } +if ( (Test-Path $path_binaries) -eq $false ) { + New-Item $path_binaries -ItemType Directory +} + #region Handmade Generate if ( $false ) { $includes = @( @@ -464,6 +479,13 @@ else { if ( $engine ) { + # Delete old PDBs + $pdb_files = Get-ChildItem -Path $path_binaries -Filter "handmade_engine_*.pdb" + foreach ($file in $pdb_files) { + Remove-Item -Path $file.FullName -Force + Write-Host "Deleted $file" -ForegroundColor Green + } + $engine_compiler_args = $compiler_args $engine_compiler_args += ($flag_define + 'Build_DLL=1' ) @@ -481,15 +503,19 @@ if ( $engine ) $flag_link_optimize_references ) - $unit = Join-Path $path_project 'handmade_engine.cpp' - $dynamic_library = Join-Path $path_build 'handmade_engine.dll' + $unit = Join-Path $path_project 'handmade_engine.cpp' + $dynamic_library = Join-Path $path_binaries 'handmade_engine.dll' build-simple $includes $engine_compiler_args $linker_args $unit $dynamic_library if ( Test-Path $dynamic_library ) { - $data_path = Join-Path $path_data 'handmade_engine.dll' - move-item $dynamic_library $data_path -Force + # $data_path = Join-Path $path_data 'handmade_engine.dll' + # move-item $dynamic_library $data_path -Force + $path_lib = $dynamic_library -replace '\.dll', '.lib' + $path_exp = $dynamic_library -replace '\.dll', '.exp' + Remove-Item $path_lib -Force + Remove-Item $path_exp -Force # We need to generate the symbol table so that we can lookup the symbols we need when loading/reloading the library at runtime. # This is done by sifting through the emitter.map file from the linker for the base symbol names @@ -505,6 +531,8 @@ if ( $engine ) $path_engine_map = Join-Path $path_build 'handmade_engine.map' + $maxNameLength = ($engine_symbols | Measure-Object -Property Length -Maximum).Maximum + $engine_symbol_table = @() $engine_symbol_list = @() Get-Content -Path $path_engine_map | ForEach-Object { @@ -526,17 +554,27 @@ if ( $engine ) write-host "Engine Symbol Table:" -ForegroundColor Green $engine_symbol_table | ForEach-Object { - write-host "`t$_" -ForegroundColor Green + $split = $_ -split ', ', 2 + $paddedName = $split[0].PadRight($maxNameLength) + $decoratedName = $split[1] + write-host "`t$paddedName, $decoratedName" -ForegroundColor Green } # Write the symbol table to a file - $path_engine_symbols = Join-Path $path_data 'handmade_engine.symbols' + $path_engine_symbols = Join-Path $path_binaries 'handmade_engine.symbols' $engine_symbol_list | Out-File -Path $path_engine_symbols } } if ( $platform ) { + # Delete old PDBs + $pdb_files = Get-ChildItem -Path $path_binaries -Filter "handmade_win32_*.pdb" + foreach ($file in $pdb_files) { + Remove-Item -Path $file.FullName -Force + Write-Host "Deleted $file" -ForegroundColor Green + } + $platform_compiler_args = $compiler_args $platform_compiler_args += ($flag_define + 'Build_DLL=0' ) @@ -552,16 +590,23 @@ if ( $platform ) $flag_link_optimize_references ) - $unit = Join-Path $path_project 'handmade_win32.cpp' - $executable = Join-Path $path_build 'handmade_win32.exe' + $unit = Join-Path $path_project 'handmade_win32.cpp' + $executable = Join-Path $path_binaries 'handmade_win32.exe' build-simple $includes $platform_compiler_args $linker_args $unit $executable - if ( Test-Path $executable ) - { - $data_path = Join-Path $path_data 'handmade_win32.exe' - move-item $executable $data_path -Force - } + # if ( Test-Path $executable ) + # { + # $data_path = Join-Path $path_data 'handmade_win32.exe' + # move-item $executable $data_path -Force + # } +} + +$path_jsl_dll = Join-Path $path_binaries 'JoyShockLibrary.dll' +if ( (Test-Path $path_jsl_dll) -eq $false ) +{ + $path_jsl_dep_dll = Join-Path $path_deps 'JoyShockLibrary/x64/JoyShockLibrary.dll' + Copy-Item $path_jsl_dep_dll $path_jsl_dll } #endregion Handmade Runtime diff --git a/scripts/clean.ps1 b/scripts/clean.ps1 index 6b3630e..f41ace3 100644 --- a/scripts/clean.ps1 +++ b/scripts/clean.ps1 @@ -3,8 +3,13 @@ $path_root = git rev-parse --show-toplevel $path_project = join-path $path_root "project" $path_build = join-path $path_root "build" +$path_data = join-path $path_root "data" $path_dependencies = join-path $path_project "dependencies" +$path_binaries = join-path $path_data "binaries" if ( Test-Path $path_build ) { Remove-Item -verbose $path_build -Recurse } +if ( Test-Path $path_binaries ) { + Remove-Item -verbose $path_binaries -Recurse +} diff --git a/scripts/handmade.rdbg b/scripts/handmade.rdbg index 31f860a..89979ac 100644 Binary files a/scripts/handmade.rdbg and b/scripts/handmade.rdbg differ diff --git a/scripts/update_deps.ps1 b/scripts/update_deps.ps1 index 8bfd20d..6a5a26f 100644 --- a/scripts/update_deps.ps1 +++ b/scripts/update_deps.ps1 @@ -4,6 +4,7 @@ $path_root = & git rev-parse --show-toplevel $path_data = Join-Path $path_root "data" $path_project = Join-Path $path_root "project" $path_deps = Join-Path $path_project "dependencies" +$path_binaries = Join-Path $path_data "binaries" $path_deps_windows = Join-Path $path_deps "windows" $path_temp = Join-Path $path_deps "temp" $path_platform = Join-Path $path_project "platform" @@ -15,6 +16,10 @@ if (Test-Path $path_deps) { } New-Item -ItemType Directory -Path $path_temp +if ( -not (Test-Path $path_binaries) ) { + New-Item -ItemType Directory -Path $path_binaries +} + $url_gencpp = "https://github.com/Ed94/gencpp/releases/download/latest/gencpp_singleheader.zip" $path_gencpp_zip = Join-Path $path_temp "gencpp_singleheader.zip" @@ -59,7 +64,7 @@ $jsl_lib_files = (Get-ChildItem (Join-Path $path_temp "JSL\x64") -Recurse -Inclu Move-Item $jsl_lib_files -Destination $path_jsl_lib -Force $path_jsl_dll = Join-Path $path_jsl_lib "JoyShockLibrary.dll" -Move-Item $path_jsl_dll $path_data -Force +Copy-Item $path_jsl_dll $path_binaries -Force #endregion JoyShockLibrary Remove-Item $path_temp -Recurse -Force