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