mirror of
				https://github.com/Ed94/HandmadeHero.git
				synced 2025-10-31 06:50:54 -07:00 
			
		
		
		
	Day 21 complete
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -22,3 +22,5 @@ build | |||||||
|  |  | ||||||
| **/*.dll | **/*.dll | ||||||
| data/test.out | data/test.out | ||||||
|  | data/handmade_engine.symbols | ||||||
|  | data/handmade_win32.exe | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							| @@ -8,7 +8,7 @@ | |||||||
| 			"type":"cppvsdbg", | 			"type":"cppvsdbg", | ||||||
| 			"request": "launch", | 			"request": "launch", | ||||||
| 			"name" : "Debug handmade win32 msvc", | 			"name" : "Debug handmade win32 msvc", | ||||||
| 			"program": "${workspaceFolder}/build/handmade_win32.exe", | 			"program": "${workspaceFolder}/data/handmade_win32.exe", | ||||||
| 			"args": [], | 			"args": [], | ||||||
| 			"cwd": "${workspaceFolder}/data", | 			"cwd": "${workspaceFolder}/data", | ||||||
| 			"visualizerFile": "${workspaceFolder}/scripts/handmade.natvis" | 			"visualizerFile": "${workspaceFolder}/scripts/handmade.natvis" | ||||||
|   | |||||||
| @@ -8,16 +8,16 @@ | |||||||
| 		<ShowEmptyFolders>true</ShowEmptyFolders> | 		<ShowEmptyFolders>true</ShowEmptyFolders> | ||||||
| 		<IsVirtual>false</IsVirtual> | 		<IsVirtual>false</IsVirtual> | ||||||
| 		<IsFolder>false</IsFolder> | 		<IsFolder>false</IsFolder> | ||||||
| 		<BuildCommand>pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(WorkspaceDirectory)/scripts/build.ps1 msvc dev optimized</BuildCommand> | 		<BuildCommand>pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(WorkspaceDirectory)/scripts/build.ps1 msvc dev debug engine</BuildCommand> | ||||||
| 		<RebuildCommand></RebuildCommand> | 		<RebuildCommand>pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(WorkspaceDirectory)/scripts/build.ps1 msvc dev debug platform</RebuildCommand> | ||||||
| 		<BuildFileCommand></BuildFileCommand> | 		<BuildFileCommand></BuildFileCommand> | ||||||
| 		<CleanCommand>pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(WorkspaceDirectory)/scripts/clean.ps1</CleanCommand> | 		<CleanCommand>pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(WorkspaceDirectory)/scripts/clean.ps1</CleanCommand> | ||||||
| 		<BuildWorkingDirectory></BuildWorkingDirectory> | 		<BuildWorkingDirectory></BuildWorkingDirectory> | ||||||
| 		<CancelBuild></CancelBuild> | 		<CancelBuild></CancelBuild> | ||||||
| 		<RunCommand>$(WorkspaceDirectory)/build/handmade_win32.exe</RunCommand> | 		<RunCommand>$(WorkspaceDirectory)/data/handmade_win32.exe</RunCommand> | ||||||
| 		<RunCommandWorkingDirectory>$(WorkspaceDirectory)/data</RunCommandWorkingDirectory> | 		<RunCommandWorkingDirectory>$(WorkspaceDirectory)/data</RunCommandWorkingDirectory> | ||||||
| 		<DebugCommand>$(WorkspaceDirectory)/build/handmade_win32.exe</DebugCommand> | 		<DebugCommand>$(WorkspaceDirectory)/data/handmade_win32.exe</DebugCommand> | ||||||
| 		<ExePathCommand>$(WorkspaceDirectory)/build/handmade_win32.exe</ExePathCommand> | 		<ExePathCommand>$(WorkspaceDirectory)/data/handmade_win32.exe</ExePathCommand> | ||||||
| 		<DebugSln></DebugSln> | 		<DebugSln></DebugSln> | ||||||
| 		<UseVisualStudioEnvBat>true</UseVisualStudioEnvBat> | 		<UseVisualStudioEnvBat>true</UseVisualStudioEnvBat> | ||||||
| 		<Configurations> | 		<Configurations> | ||||||
|   | |||||||
| @@ -17,28 +17,43 @@ | |||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Development|x64'"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Development|x64'"> | ||||||
|     <IncludePath>$(ProjectDir)project;$(IncludePath)</IncludePath> |     <IncludePath>$(ProjectDir)project;$(IncludePath)</IncludePath> | ||||||
|     <LibraryPath>$(ProjectDir)data;$(windir)System32;$(LibraryPath)</LibraryPath> |     <LibraryPath>$(ProjectDir)data;$(windir)System32;$(LibraryPath)</LibraryPath> | ||||||
|     <NMakeBuildCommandLine>pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(ProjectDir)scripts\build.ps1 msvc dev</NMakeBuildCommandLine> |     <NMakeBuildCommandLine>pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(ProjectDir)scripts\build.ps1 msvc dev engine</NMakeBuildCommandLine> | ||||||
|     <NMakeCleanCommandLine>pwsh ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(ProjectDir)scripts\clean.ps1</NMakeCleanCommandLine> |     <NMakeCleanCommandLine>pwsh ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(ProjectDir)scripts\clean.ps1</NMakeCleanCommandLine> | ||||||
|     <NMakePreprocessorDefinitions>GEN_TIME;Build_Development;Build_Debug;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions> |     <NMakePreprocessorDefinitions>GEN_TIME;Build_Development;Build_Debug;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions> | ||||||
|     <ExternalIncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath)</ExternalIncludePath> |     <ExternalIncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath)</ExternalIncludePath> | ||||||
|  |     <NMakeReBuildCommandLine> | ||||||
|  |     </NMakeReBuildCommandLine> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClInclude Include="project\engine.h" /> |     <ClInclude Include="project\engine.h" /> | ||||||
|  |     <ClInclude Include="project\handmade.hpp" /> | ||||||
|     <ClInclude Include="project\platform\generics.h" /> |     <ClInclude Include="project\platform\generics.h" /> | ||||||
|  |     <ClInclude Include="project\platform\generics.hpp" /> | ||||||
|     <ClInclude Include="project\platform\grime.h" /> |     <ClInclude Include="project\platform\grime.h" /> | ||||||
|  |     <ClInclude Include="project\platform\grime.hpp" /> | ||||||
|     <ClInclude Include="project\platform\jsl.h" /> |     <ClInclude Include="project\platform\jsl.h" /> | ||||||
|  |     <ClInclude Include="project\platform\jsl.hpp" /> | ||||||
|     <ClInclude Include="project\platform\macros.h" /> |     <ClInclude Include="project\platform\macros.h" /> | ||||||
|  |     <ClInclude Include="project\platform\macros.hpp" /> | ||||||
|     <ClInclude Include="project\platform\math_constants.h" /> |     <ClInclude Include="project\platform\math_constants.h" /> | ||||||
|  |     <ClInclude Include="project\platform\math_constants.hpp" /> | ||||||
|     <ClInclude Include="project\platform\platform.h" /> |     <ClInclude Include="project\platform\platform.h" /> | ||||||
|  |     <ClInclude Include="project\platform\platform.hpp" /> | ||||||
|     <ClInclude Include="project\platform\platform_engine_api.h" /> |     <ClInclude Include="project\platform\platform_engine_api.h" /> | ||||||
|  |     <ClInclude Include="project\platform\platform_engine_api.hpp" /> | ||||||
|  |     <ClInclude Include="project\platform\platform_game_api.hpp" /> | ||||||
|     <ClInclude Include="project\platform\types.h" /> |     <ClInclude Include="project\platform\types.h" /> | ||||||
|  |     <ClInclude Include="project\platform\types.hpp" /> | ||||||
|     <ClInclude Include="project\platform\win32.h" /> |     <ClInclude Include="project\platform\win32.h" /> | ||||||
|  |     <ClInclude Include="project\platform\win32.hpp" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="project\engine.cpp" /> |     <ClCompile Include="project\engine.cpp" /> | ||||||
|     <ClCompile Include="project\handmade.cpp" /> |     <ClCompile Include="project\handmade.cpp" /> | ||||||
|  |     <ClCompile Include="project\handmade_engine.cpp" /> | ||||||
|     <ClCompile Include="project\handmade_win32.cpp" /> |     <ClCompile Include="project\handmade_win32.cpp" /> | ||||||
|     <ClCompile Include="project\platform\platform_win32.cpp" /> |     <ClCompile Include="project\platform\platform_win32.cpp" /> | ||||||
|  |     <ClCompile Include="project\platform\win32_platform.cpp" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <None Include="docs\Day 001.md" /> |     <None Include="docs\Day 001.md" /> | ||||||
|   | |||||||
| @@ -6,6 +6,6 @@ | |||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Development|x64'"> |   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Development|x64'"> | ||||||
|     <LocalDebuggerWorkingDirectory>$(ProjectDir)data</LocalDebuggerWorkingDirectory> |     <LocalDebuggerWorkingDirectory>$(ProjectDir)data</LocalDebuggerWorkingDirectory> | ||||||
|     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> |     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> | ||||||
|     <LocalDebuggerCommand>$(ProjectDir)build\handmade_win32.exe</LocalDebuggerCommand> |     <LocalDebuggerCommand>$(ProjectDir)data\handmade_win32.exe</LocalDebuggerCommand> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
| </Project> | </Project> | ||||||
							
								
								
									
										15
									
								
								docs/Day 021.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								docs/Day 021.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | # Day 21 | ||||||
|  |  | ||||||
|  | So I learned today the good reason why he doesn't use static variables; So that when he makes this library dynamically loaded we don't lose the state of the game on reload.   | ||||||
|  |  | ||||||
|  | This day was extremely gratifying to get working. | ||||||
|  |  | ||||||
|  | I went the extra mile than what Casey did and allow for name mangled symbols (for both clang and msvc).   | ||||||
|  | It took a few more steps than his solution but I get to keep the eronomics of namespaces. | ||||||
|  |  | ||||||
|  | After the linker finishes emitting, I use the build script to parse the .map file and extract the decorated symbols I need to load in the platform layer. Those are exported to a file called `handmade_engine.symbols` and then in the platform layer I load them up using an enum as the lookup table for the line the symbol will be in the file. From there its just loading up the symbol with GetProcAddress! | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,15 +1,21 @@ | |||||||
| #include "engine.hpp" |  | ||||||
| //#include "win32.h"
 | //#include "win32.h"
 | ||||||
|  | #include "engine.hpp" | ||||||
|  | #include "platform/platform_engine_api.hpp" | ||||||
|  | #include "handmade.hpp" | ||||||
| 
 | 
 | ||||||
| NS_ENGINE_BEGIN | NS_ENGINE_BEGIN | ||||||
| 
 | 
 | ||||||
| struct EngineState | struct EngineState | ||||||
| { | { | ||||||
| 	s32 WaveSwitch; |  | ||||||
| 	s32 WaveToneHz; | 	s32 WaveToneHz; | ||||||
| 	s32 ToneVolume; | 	s32 ToneVolume; | ||||||
| 	s32 XOffset; | 	s32 XOffset; | ||||||
| 	s32 YOffset; | 	s32 YOffset; | ||||||
|  | 
 | ||||||
|  | 	b32 RendererPaused; | ||||||
|  | 
 | ||||||
|  | 	f32 SampleWaveSineTime; | ||||||
|  | 	b32 SampleWaveSwitch; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| using GetSoundSampleValueFn = s16( EngineState* state, AudioBuffer* sound_buffer ); | using GetSoundSampleValueFn = s16( EngineState* state, AudioBuffer* sound_buffer ); | ||||||
| @@ -28,7 +34,7 @@ square_wave_sample_value( EngineState* state, AudioBuffer* sound_buffer ) | |||||||
| internal s16 | internal s16 | ||||||
| sine_wave_sample_value( EngineState* state, AudioBuffer* sound_buffer ) | sine_wave_sample_value( EngineState* state, AudioBuffer* sound_buffer ) | ||||||
| { | { | ||||||
| 	local_persist f32 time = 0.f; | 	f32& time = state->SampleWaveSineTime; | ||||||
| 
 | 
 | ||||||
| 	s32 wave_period = sound_buffer->SamplesPerSecond / state->WaveToneHz; | 	s32 wave_period = sound_buffer->SamplesPerSecond / state->WaveToneHz; | ||||||
| 
 | 
 | ||||||
| @@ -104,7 +110,6 @@ render_weird_graident(OffscreenBuffer* buffer, u32 x_offset, u32 y_offset ) | |||||||
| 			u8 red   = 0; | 			u8 red   = 0; | ||||||
| 		#endif | 		#endif | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 			*pixel++ = u32(red << 16) | u32(green << 8) | blue; | 			*pixel++ = u32(red << 16) | u32(green << 8) | blue; | ||||||
| 		} | 		} | ||||||
| 		wildcard += 0.5375f; | 		wildcard += 0.5375f; | ||||||
| @@ -112,66 +117,55 @@ render_weird_graident(OffscreenBuffer* buffer, u32 x_offset, u32 y_offset ) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| b32 input_using_analog() | Engine_API | ||||||
|  | void on_module_reload( Memory* memory, platform::ModuleAPI* platfom_api ) | ||||||
| { | { | ||||||
| 	return false; | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void startup() | Engine_API | ||||||
|  | void startup( Memory* memory, platform::ModuleAPI* platform_api ) | ||||||
| { | { | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void shutdown() |  | ||||||
| { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // TODO : I rather expose the back_buffer and sound_buffer using getters for access in any function.
 |  | ||||||
| void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory* memory ) |  | ||||||
| { |  | ||||||
| 	// Graphics & Input Test
 |  | ||||||
| 	local_persist u32 x_offset = 0; |  | ||||||
| 	local_persist u32 y_offset = 0; |  | ||||||
| 
 |  | ||||||
| 	// Wave Sound Test
 |  | ||||||
| 	local_persist bool wave_switch = false; |  | ||||||
| 
 |  | ||||||
| #if 0 |  | ||||||
| 	if ( input_using_analog() ) |  | ||||||
| 	{ |  | ||||||
| 		// TODO(Ed) : Use analog movement tuning
 |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		// TODO(Ed) : Use digital movement tuning
 |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 	EngineState* state = rcast( EngineState*, memory->Persistent ); | 	EngineState* state = rcast( EngineState*, memory->Persistent ); | ||||||
|  | 	assert( sizeof(EngineState) <= memory->PersistentSize ); | ||||||
| 
 | 
 | ||||||
| 	do_once_start | 	state->ToneVolume = 1000; | ||||||
| 		assert( sizeof(EngineState) <= memory->PersistentSize ); |  | ||||||
| 
 | 
 | ||||||
| 		state->ToneVolume = 1000; | 	state->XOffset = 0; | ||||||
| 		state->WaveToneHz = 120; | 	state->YOffset = 0; | ||||||
| 
 | 
 | ||||||
| 		state->XOffset    = 0; | 	state->SampleWaveSwitch = false; | ||||||
| 		state->YOffset    = 0; | 	state->WaveToneHz = 120; | ||||||
| 		state->WaveSwitch = false; | 	state->SampleWaveSineTime = 0.f; | ||||||
| 
 | 
 | ||||||
| 		#if Build_Debug && 0 | 	state->RendererPaused = false; | ||||||
|  | 
 | ||||||
|  | 	#if Build_Debug && 0 | ||||||
|  | 	{ | ||||||
|  | 		using namespace platform; | ||||||
|  | 
 | ||||||
|  | 		char const* file_path = __FILE__; | ||||||
|  | 		Debug_FileContent file_content = platform_api->debug_file_read_content( file_path ); | ||||||
|  | 		if ( file_content.Size ) | ||||||
| 		{ | 		{ | ||||||
| 			using namespace platform; | 			platform_api->debug_file_write_content( "test.out", file_content.Size, file_content.Data ); | ||||||
| 
 | 			platform_api->debug_file_free_content( & file_content ); | ||||||
| 			char const* file_path = __FILE__; |  | ||||||
| 			Debug_FileContent file_content = debug_file_read_content( file_path ); |  | ||||||
| 			if ( file_content.Size ) |  | ||||||
| 			{ |  | ||||||
| 				debug_file_write_content( "test.out", file_content.Size, file_content.Data ); |  | ||||||
| 				debug_file_free_content( & file_content ); |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 		#endif | 	} | ||||||
| 	do_once_end | 	#endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Engine_API | ||||||
|  | void shutdown( Memory* memory, platform::ModuleAPI* platform_api ) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Engine_API | ||||||
|  | // TODO : I rather expose the back_buffer and sound_buffer using getters for access in any function.
 | ||||||
|  | void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* platform_api ) | ||||||
|  | { | ||||||
|  | 	EngineState* state = rcast( EngineState*, memory->Persistent ); | ||||||
|  | 	assert( sizeof(EngineState) <= memory->PersistentSize ); | ||||||
| 
 | 
 | ||||||
| 	ControllerState* controller = & input->Controllers[0]; | 	ControllerState* controller = & input->Controllers[0]; | ||||||
| 
 | 
 | ||||||
| @@ -195,7 +189,6 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory* | |||||||
| 	b32 toggle_wave_tone = false; | 	b32 toggle_wave_tone = false; | ||||||
| 
 | 
 | ||||||
| 	b32 pause_renderer  = false; | 	b32 pause_renderer  = false; | ||||||
| 	local_persist b32 renderer_paused = false; |  | ||||||
| 
 | 
 | ||||||
| 	f32 analog_threshold = 0.5f; | 	f32 analog_threshold = 0.5f; | ||||||
| 
 | 
 | ||||||
| @@ -255,10 +248,10 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory* | |||||||
| 		toggle_wave_tone |= pressed( keyboard->Space ); | 		toggle_wave_tone |= pressed( keyboard->Space ); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	x_offset += 3 * move_right; | 	state->XOffset += 3 * move_right; | ||||||
| 	x_offset -= 3 * move_left; | 	state->XOffset -= 3 * move_left; | ||||||
| 	y_offset += 3 * move_down; | 	state->YOffset += 3 * move_down; | ||||||
| 	y_offset -= 3 * move_up; | 	state->YOffset -= 3 * move_up; | ||||||
| 
 | 
 | ||||||
| 	if ( raise_volume ) | 	if ( raise_volume ) | ||||||
| 	{ | 	{ | ||||||
| @@ -284,26 +277,27 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory* | |||||||
| 
 | 
 | ||||||
| 	if ( toggle_wave_tone ) | 	if ( toggle_wave_tone ) | ||||||
| 	{ | 	{ | ||||||
| 		state->WaveSwitch ^= true; | 		state->SampleWaveSwitch ^= true; | ||||||
| 	} | 	} | ||||||
| 	render_weird_graident( back_buffer, x_offset, y_offset ); | 	render_weird_graident( back_buffer, state->XOffset, state->YOffset ); | ||||||
| 
 | 
 | ||||||
| 	if ( pause_renderer ) | 	if ( pause_renderer ) | ||||||
| 	{ | 	{ | ||||||
| 		if ( renderer_paused ) | 		if ( state->RendererPaused ) | ||||||
| 		{ | 		{ | ||||||
| 			platform::set_pause_rendering(false); | 			platform_api->debug_set_pause_rendering(false); | ||||||
| 			renderer_paused = false; | 			state->RendererPaused = false; | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			platform::set_pause_rendering(true); | 			platform_api->debug_set_pause_rendering(true); | ||||||
| 			renderer_paused = true; | 			state->RendererPaused = true; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void update_audio( AudioBuffer* audio_buffer, Memory* memory ) | Engine_API | ||||||
|  | void update_audio( AudioBuffer* audio_buffer, Memory* memory, platform::ModuleAPI* platform_api ) | ||||||
| { | { | ||||||
| 	EngineState* state = rcast( EngineState*, memory->Persistent ); | 	EngineState* state = rcast( EngineState*, memory->Persistent ); | ||||||
| 	do_once_start | 	do_once_start | ||||||
| @@ -311,11 +305,10 @@ void update_audio( AudioBuffer* audio_buffer, Memory* memory ) | |||||||
| 	do_once_end | 	do_once_end | ||||||
| 
 | 
 | ||||||
| 	// TODO(Ed) : Allow sample offsets here for more robust platform options
 | 	// TODO(Ed) : Allow sample offsets here for more robust platform options
 | ||||||
| 	if ( ! state->WaveSwitch ) | 	if ( ! state->SampleWaveSwitch ) | ||||||
| 		output_sound( state, audio_buffer, sine_wave_sample_value ); | 		output_sound( state, audio_buffer, sine_wave_sample_value ); | ||||||
| 	else | 	else | ||||||
| 		output_sound( state, audio_buffer, square_wave_sample_value ); | 		output_sound( state, audio_buffer, square_wave_sample_value ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| NS_ENGINE_END | NS_ENGINE_END | ||||||
| 
 |  | ||||||
| @@ -197,56 +197,3 @@ void input_mode_pop( InputMode* mode ); | |||||||
| void input_mode_pop( InputMode* mode ); | void input_mode_pop( InputMode* mode ); | ||||||
| 
 | 
 | ||||||
| NS_ENGINE_END | NS_ENGINE_END | ||||||
| 
 |  | ||||||
| // TODO(Ed) : Move this to handmade game layer later.
 |  | ||||||
| 
 |  | ||||||
| #define NS_HANDMADE_BEGIN namespace handmade { |  | ||||||
| #define NS_HANDMADE_END   } |  | ||||||
| 
 |  | ||||||
| NS_HANDMADE_BEGIN |  | ||||||
| 
 |  | ||||||
| // We want a 'binding' to have multiple binds to active it (most likely)
 |  | ||||||
| struct Actionable |  | ||||||
| { |  | ||||||
| 	char const*                Name; |  | ||||||
| 	engine::InputBindCallback* Binds; |  | ||||||
| 	s32                        NumBinds; |  | ||||||
| 	char _PAD_[4]; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct ActionableMode |  | ||||||
| { |  | ||||||
| 	 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| 	Platform Layer: |  | ||||||
| 
 |  | ||||||
| 	Controller : Keyboard & Mouse, XPad, DSPad |  | ||||||
| 
 |  | ||||||
| 	---VV--- |  | ||||||
| 
 |  | ||||||
| 	Engine Layer: |  | ||||||
| 
 |  | ||||||
| 	InputBinding callbacks (per-game-logic frame basis) |  | ||||||
| 	Push/Pop input modes (binding sets) |  | ||||||
| 
 |  | ||||||
| 	---VV--- |  | ||||||
| 
 |  | ||||||
| 	Game Layer: |  | ||||||
| 
 |  | ||||||
| 	Actionables : Binding Sets where a raw input, or input interpretation leads to an player action. |  | ||||||
| 	ActionSet   : Actionables.Push/Pop -> Input.Push/Pop ? |  | ||||||
| 	Player : Controller, Actionables, ActionSets |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| struct Player |  | ||||||
| { |  | ||||||
| 	// So far just has an assigned controller.
 |  | ||||||
| 	engine::ControllerState* Controller; |  | ||||||
| 	 |  | ||||||
| 	// Possilby some other stuff in the future.
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| NS_HANDMADE_END |  | ||||||
| 
 |  | ||||||
							
								
								
									
										11
									
								
								project/engine/win32_engine.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								project/engine/win32_engine.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | #include "platform/win32.hpp" | ||||||
|  | #include "engine.hpp" | ||||||
|  |  | ||||||
|  | b32 WINAPI DllMain( | ||||||
|  | 	HINSTANCE instance, | ||||||
|  | 	DWORD reason_for_call, | ||||||
|  | 	LPVOID reserved | ||||||
|  | ) | ||||||
|  | { | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
| @@ -4,5 +4,5 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "engine.hpp" | #include "engine/engine.hpp" | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										67
									
								
								project/handmade.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								project/handmade.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "engine/engine.hpp" | ||||||
|  |  | ||||||
|  | #define NS_HANDMADE_BEGIN namespace handmade { | ||||||
|  | #define NS_HANDMADE_END   } | ||||||
|  |  | ||||||
|  | NS_HANDMADE_BEGIN | ||||||
|  |  | ||||||
|  | struct Memory | ||||||
|  | { | ||||||
|  | 	// Subscection of engine memory for the game to use. | ||||||
|  |  | ||||||
|  | 	void* Persistent; | ||||||
|  | 	u64   PersistentSize; | ||||||
|  |  | ||||||
|  | 	// void* Frame; | ||||||
|  | 	// u64   FrameSize; | ||||||
|  |  | ||||||
|  | 	void* Transient; | ||||||
|  | 	u64   TransientSize; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // We want a 'binding' to have multiple binds to active it (most likely) | ||||||
|  | struct Actionable | ||||||
|  | { | ||||||
|  | 	char const*                Name; | ||||||
|  | 	engine::InputBindCallback* Binds; | ||||||
|  | 	s32                        NumBinds; | ||||||
|  | 	char _PAD_[4]; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct ActionableMode | ||||||
|  | { | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Platform Layer: | ||||||
|  |  | ||||||
|  | 	Controller : Keyboard & Mouse, XPad, DSPad | ||||||
|  |  | ||||||
|  | 	---VV--- | ||||||
|  |  | ||||||
|  | 	Engine Layer: | ||||||
|  |  | ||||||
|  | 	InputBinding callbacks (per-game-logic frame basis) | ||||||
|  | 	Push/Pop input modes (binding sets) | ||||||
|  |  | ||||||
|  | 	---VV--- | ||||||
|  |  | ||||||
|  | 	Game Layer: | ||||||
|  |  | ||||||
|  | 	Actionables : Binding Sets where a raw input, or input interpretation leads to an player action. | ||||||
|  | 	ActionSet   : Actionables.Push/Pop -> Input.Push/Pop ? | ||||||
|  | 	Player : Controller, Actionables, ActionSets | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | struct Player | ||||||
|  | { | ||||||
|  | 	// So far just has an assigned controller. | ||||||
|  | 	engine::ControllerState* Controller; | ||||||
|  |  | ||||||
|  | 	// Possilby some other stuff in the future. | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | NS_HANDMADE_END | ||||||
							
								
								
									
										19
									
								
								project/handmade_engine.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								project/handmade_engine.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | #ifdef __clang__ | ||||||
|  | #pragma clang diagnostic push | ||||||
|  | #pragma clang diagnostic ignored "-Wunused-const-variable" | ||||||
|  | #pragma clang diagnostic ignored "-Wswitch" | ||||||
|  | #pragma clang diagnostic ignored "-Wunused-variable" | ||||||
|  | #pragma clang diagnostic ignored "-Wunknown-pragmas" | ||||||
|  | #pragma clang diagnostic ignored "-Wvarargs" | ||||||
|  | #pragma clang diagnostic ignored "-Wunused-function" | ||||||
|  | #pragma clang diagnostic ignored "-Wunused-but-set-variable" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "platform/grime.hpp" | ||||||
|  |  | ||||||
|  | #if Build_Unity | ||||||
|  | #	include "engine/engine.cpp" | ||||||
|  | #	if SYSTEM_WINDOWS | ||||||
|  | #		include "engine/win32_engine.cpp" | ||||||
|  | #	endif | ||||||
|  | #endif | ||||||
| @@ -10,7 +10,5 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if Build_Unity | #if Build_Unity | ||||||
| #include "handmade.cpp" |  | ||||||
| #include "engine.cpp" |  | ||||||
| #include "platform/win32_platform.cpp" | #include "platform/win32_platform.cpp" | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -61,6 +61,12 @@ | |||||||
| #	define assert( expression ) | #	define assert( expression ) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef COMPILER_CLANG | ||||||
|  | #	define compiler_decorated_func_name __PRETTY_NAME__ | ||||||
|  | #elif defined(COMPILER_MSVC) | ||||||
|  | #	define compiler_decorated_func_name __FUNCDNAME__ | ||||||
|  | #endif | ||||||
|  |  | ||||||
| // TODO(Ed) : Add this sauce later | // TODO(Ed) : Add this sauce later | ||||||
| #if 0 | #if 0 | ||||||
| #define congrats( message ) | #define congrats( message ) | ||||||
|   | |||||||
| @@ -32,7 +32,11 @@ | |||||||
|  |  | ||||||
| NS_PLATFORM_BEGIN | NS_PLATFORM_BEGIN | ||||||
|  |  | ||||||
| #if Build_Debug | // On-Demand platform interface. | ||||||
|  | // Everything exposed here should be based on a feature a game may want to provide a user | ||||||
|  | // (Example: Letting the user change the refresh-rate of the monitor or the engine's target frame-rate) | ||||||
|  |  | ||||||
|  | #if Build_Development | ||||||
| /* | /* | ||||||
| 	IMPORTANT : These are not for shipping code - they are blocking and the write isn't protected. | 	IMPORTANT : These are not for shipping code - they are blocking and the write isn't protected. | ||||||
| */ | */ | ||||||
| @@ -44,34 +48,42 @@ struct Debug_FileContent | |||||||
| 	char  _PAD_[4]; | 	char  _PAD_[4]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| void              debug_file_free_content ( Debug_FileContent* file_content ); | using DebugFileFreeContentFn  = void ( Debug_FileContent* file_content ); | ||||||
| Debug_FileContent debug_file_read_content ( char const* file_path ); | using DebugFileReadContentFn  = Debug_FileContent ( char const* file_path ); | ||||||
| b32               debug_file_write_content( char const* file_path, u32 content_size, void* content_memory ); | using DebugFileWriteContentFn = b32 ( char const* file_path, u32 content_size, void* content_memory ); | ||||||
|  |  | ||||||
| // Allows the engine or game to pause the renderering of any next frames. |  | ||||||
| // ( Prevents blipping of the black buffer ) |  | ||||||
| void set_pause_rendering( b32 value ); |  | ||||||
|  |  | ||||||
|  | using DebugSetPauseRenderingFn = void (b32 value); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| // On-Demand platform interface. |  | ||||||
| // Everything exposed here should be based on a feature a game may want to provide a user |  | ||||||
| // (Example: Letting the user change the refresh-rate of the monitor or the engine's target frame-rate) |  | ||||||
|  |  | ||||||
| // TODO(Ed) : Implement this later when settings UI is setup. | // TODO(Ed) : Implement this later when settings UI is setup. | ||||||
| #pragma region Settings Exposure | #pragma region Settings Exposure | ||||||
| // Exposing specific properties for user configuration in settings | // Exposing specific properties for user configuration in settings | ||||||
|  |  | ||||||
| // Returns the current monitor refresh rate. | // Returns the current monitor refresh rate. | ||||||
| u32 get_monitor_refresh_rate(); | using GetMonitorRefreshRateFn = u32(); | ||||||
|  |  | ||||||
| // Sets the monitor refresh rate | // Sets the monitor refresh rate | ||||||
| // Must be of the compatiable listing for the monitor the window surface is presenting to. | // Must be of the compatiable listing for the monitor the window surface is presenting to | ||||||
| void set_monitor_refresh_rate( u32 rate_in_hz ); | using SetMonitorRefreshRateFn = void ( u32 rate_in_hz ); | ||||||
|  |  | ||||||
| u32 get_engine_frame_target(); | using GetEngineFrameTargetFn = u32 (); | ||||||
|  | using SetEngineFrameTargetFn = void ( u32 rate_in_hz ); | ||||||
|  |  | ||||||
| void set_engine_frame_target( u32 rate_in_hz ); | struct ModuleAPI | ||||||
|  | { | ||||||
|  | #if Build_Development | ||||||
|  | 	DebugFileFreeContentFn*  debug_file_free_content; | ||||||
|  | 	DebugFileReadContentFn*  debug_file_read_content; | ||||||
|  | 	DebugFileWriteContentFn* debug_file_write_content; | ||||||
|  |  | ||||||
|  | 	DebugSetPauseRenderingFn* debug_set_pause_rendering; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	GetMonitorRefreshRateFn* get_monitor_refresh_rate; | ||||||
|  | 	SetMonitorRefreshRateFn* set_monitor_refresh_rate; | ||||||
|  |  | ||||||
|  | 	GetEngineFrameTargetFn* get_engine_frame_target; | ||||||
|  | 	SetEngineFrameTargetFn* set_engine_frame_target; | ||||||
|  | }; | ||||||
|  |  | ||||||
| #pragma endregion Settings Exposure | #pragma endregion Settings Exposure | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,20 +2,47 @@ | |||||||
| 	This represents the API only accessible to the platform layer to fullfill for the engine layer. | 	This represents the API only accessible to the platform layer to fullfill for the engine layer. | ||||||
| */ | */ | ||||||
| #pragma once | #pragma once | ||||||
| #include "engine.hpp" | #include "engine/engine.hpp" | ||||||
|  |  | ||||||
|  | #ifndef Engine_API | ||||||
|  | #	define Engine_API | ||||||
|  | #endif | ||||||
|  |  | ||||||
| NS_ENGINE_BEGIN | NS_ENGINE_BEGIN | ||||||
|  |  | ||||||
| void startup(); | using OnModuleRelaodFn = void( Memory* memory, platform::ModuleAPI* platform_api ); | ||||||
| void shutdown(); | using StartupFn        = void( Memory* memory, platform::ModuleAPI* platform_api ); | ||||||
|  | using ShutdownFn       = void( Memory* memory, platform::ModuleAPI* platform_api ); | ||||||
|  |  | ||||||
| // Needs a contextual reference to four things: | // Needs a contextual reference to four things: | ||||||
| // Timing, Input, Bitmap Buffer | // Timing, Input, Bitmap Buffer | ||||||
| void update_and_render( InputState* input, OffscreenBuffer* back_buffer,  Memory* memory ); | using UpdateAndRenderFn = void ( InputState* input, OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* platform_api ); | ||||||
|  |  | ||||||
| // Audio timing is complicated, processing samples must be done at a different period from the rest of the engine's usual update. | // Audio timing is complicated, processing samples must be done at a different period from the rest of the engine's usual update. | ||||||
| // IMPORTANT: This has very tight timing, and cannot be more than a millisecond in execution. | // IMPORTANT: This has very tight timing, and cannot be more than a millisecond in execution. | ||||||
| // TODO(Ed) : Reduce timing pressure on performance by measuring it or pinging its time. | // TODO(Ed) : Reduce timing pressure on performance by measuring it or pinging its time. | ||||||
| void update_audio( AudioBuffer* audio_buffer, Memory* memory ); | using UpdateAudioFn = void ( AudioBuffer* audio_buffer, Memory* memory, platform::ModuleAPI* platform_api ); | ||||||
|  |  | ||||||
|  | struct ModuleAPI | ||||||
|  | { | ||||||
|  | 	enum : u32 | ||||||
|  | 	{ | ||||||
|  | 		Sym_OnModuleReload, | ||||||
|  | 		Sym_Startup, | ||||||
|  | 		Sym_Shutdown, | ||||||
|  | 		Sym_UpdateAndRender, | ||||||
|  | 		Sym_UpdateAudio, | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	OnModuleRelaodFn* on_module_reload; | ||||||
|  | 	StartupFn*        startup; | ||||||
|  | 	ShutdownFn*       shutdown; | ||||||
|  |  | ||||||
|  | 	UpdateAndRenderFn* update_and_render; | ||||||
|  | 	UpdateAudioFn*     update_audio; | ||||||
|  |  | ||||||
|  | 	b32 IsValid; | ||||||
|  | 	char _PAD_[4]; | ||||||
|  | }; | ||||||
|  |  | ||||||
| NS_ENGINE_END | NS_ENGINE_END | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								project/platform/platform_game_api.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								project/platform/platform_game_api.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | /* | ||||||
|  | 	This represents the API only accessible to the platform layer to fullfill for the game layer. | ||||||
|  | */ | ||||||
| @@ -113,6 +113,14 @@ enum XI_State : DWORD | |||||||
| 	XI_PluggedIn = ERROR_SUCCESS, | 	XI_PluggedIn = ERROR_SUCCESS, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template< typename ProcSignature > | ||||||
|  | ProcSignature* get_procedure_from_library( HMODULE library_module, char const* symbol ) | ||||||
|  | { | ||||||
|  | 	void* address = rcast( void*, GetProcAddress( library_module, symbol ) ); | ||||||
|  | 	return rcast( ProcSignature*, address ); | ||||||
|  | } | ||||||
|  |  | ||||||
| #pragma region XInput | #pragma region XInput | ||||||
| WIN_LIB_API DWORD WINAPI XInputGetState | WIN_LIB_API DWORD WINAPI XInputGetState | ||||||
| ( | ( | ||||||
| @@ -151,11 +159,14 @@ xinput_load_library_bindings() | |||||||
| { | { | ||||||
| 	HMODULE xinput_lib = LoadLibraryA( XINPUT_DLL_A ); | 	HMODULE xinput_lib = LoadLibraryA( XINPUT_DLL_A ); | ||||||
|  |  | ||||||
| #pragma warning( push ) | 	XInputGetStateFn* get_state = get_procedure_from_library< XInputGetStateFn >( xinput_lib, "XInputGetState" ); | ||||||
| #pragma warning( disable: 4191 ) | 	XInputSetStateFn* set_state = get_procedure_from_library< XInputSetStateFn >( xinput_lib, "XInputSetState" ); | ||||||
| 	xinput_get_state = rcast( XInputGetStateFn*, GetProcAddress( xinput_lib, "XInputGetState" )); |  | ||||||
| 	xinput_set_state = rcast( XInputSetStateFn*, GetProcAddress( xinput_lib, "XInputSetState" )); | 	if ( get_state ) | ||||||
| #pragma warning( pop ) | 		xinput_get_state = get_state; | ||||||
|  |  | ||||||
|  | 	if ( set_state ) | ||||||
|  | 		xinput_set_state = set_state; | ||||||
| } | } | ||||||
| #pragma endregion XInput | #pragma endregion XInput | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ | |||||||
| #include "win32.hpp" | #include "win32.hpp" | ||||||
|  |  | ||||||
| // Engine layer headers | // Engine layer headers | ||||||
| #include "engine.hpp" | #include "engine/engine.hpp" | ||||||
| #include "platform_engine_api.hpp" | #include "platform_engine_api.hpp" | ||||||
|  |  | ||||||
| // Standard-Library stand-ins | // Standard-Library stand-ins | ||||||
| @@ -216,7 +216,7 @@ b32 debug_file_write_content( char const* file_path, u32 content_size, void* con | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| void set_pause_rendering( b32 value ) | void debug_set_pause_rendering( b32 value ) | ||||||
| { | { | ||||||
| 	Pause_Rendering = value; | 	Pause_Rendering = value; | ||||||
| } | } | ||||||
| @@ -425,15 +425,12 @@ init_sound(HWND window_handle, DirectSoundBuffer* sound_buffer ) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Get direct sound object | 	// Get direct sound object | ||||||
| #pragma warning( push ) | 	direct_sound_create = get_procedure_from_library< DirectSoundCreateFn >( sound_library, "DirectSoundCreate" ); | ||||||
| #pragma warning( disable: 4191 ) |  | ||||||
| 	direct_sound_create = rcast( DirectSoundCreateFn*, GetProcAddress( sound_library, "DirectSoundCreate" )); |  | ||||||
| 	if ( ! ensure( direct_sound_create, "Failed to get direct_sound_create_procedure" ) ) | 	if ( ! ensure( direct_sound_create, "Failed to get direct_sound_create_procedure" ) ) | ||||||
| 	{ | 	{ | ||||||
| 		// TOOD : Diagnostic | 		// TOOD : Diagnostic | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| #pragma warning( pop ) |  | ||||||
|  |  | ||||||
| 	LPDIRECTSOUND direct_sound; | 	LPDIRECTSOUND direct_sound; | ||||||
| 	if ( ! SUCCEEDED(direct_sound_create( 0, & direct_sound, 0 )) ) | 	if ( ! SUCCEEDED(direct_sound_create( 0, & direct_sound, 0 )) ) | ||||||
| @@ -751,6 +748,131 @@ process_pending_window_messages( engine::KeyboardState* keyboard ) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #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 ) | ||||||
|  | { | ||||||
|  | 	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'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Right now they are just the data directory | ||||||
|  | #define Path_To_Symbol_Tables | ||||||
|  |  | ||||||
|  | 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 ); | ||||||
|  |  | ||||||
|  | 	// Engine | ||||||
|  | 	Lib_Handmade_Engine = LoadLibraryA( "handmade_engine_temp.dll" ); | ||||||
|  | 	if ( ! Lib_Handmade_Engine ) | ||||||
|  | 	{ | ||||||
|  | 		return {}; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	constexpr char const* | ||||||
|  | 	handmade_engine_symbols = Path_To_Symbol_Tables "handmade_engine.symbols"; | ||||||
|  |  | ||||||
|  | 	Debug_FileContent symbol_table = debug_file_read_content( handmade_engine_symbols ); | ||||||
|  | 	if ( symbol_table.Size == 0 ) | ||||||
|  | 	{ | ||||||
|  | 		fatal( "Failed to laod symbol table for handmade engine module!" ); | ||||||
|  | 		return {}; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// TODO(Ed) : Clean this up later when Casey makes strings. (If he doesn't we'll do it) | ||||||
|  | 	char symbol_on_module_reload[256]; | ||||||
|  | 	char symboL_startup[256]; | ||||||
|  | 	char symboL_shutdown[256]; | ||||||
|  | 	char symboL_update_and_render[256]; | ||||||
|  | 	char symbol_update_audio[256]; | ||||||
|  | 	get_symbol_from_module_table( symbol_table, ModuleAPI::Sym_OnModuleReload,  symbol_on_module_reload ); | ||||||
|  | 	get_symbol_from_module_table( symbol_table, ModuleAPI::Sym_Startup,         symboL_startup ); | ||||||
|  | 	get_symbol_from_module_table( symbol_table, ModuleAPI::Sym_Shutdown,        symboL_shutdown ); | ||||||
|  | 	get_symbol_from_module_table( symbol_table, ModuleAPI::Sym_UpdateAndRender, symboL_update_and_render ); | ||||||
|  | 	get_symbol_from_module_table( symbol_table, ModuleAPI::Sym_UpdateAudio,     symbol_update_audio ); | ||||||
|  |  | ||||||
|  | 	debug_file_free_content( & symbol_table ); | ||||||
|  |  | ||||||
|  | 	engine::ModuleAPI engine_api {}; | ||||||
|  | 	engine_api.on_module_reload  = get_procedure_from_library< engine::OnModuleRelaodFn > ( Lib_Handmade_Engine, symbol_on_module_reload ); | ||||||
|  | 	engine_api.startup           = get_procedure_from_library< engine::StartupFn >        ( Lib_Handmade_Engine, symboL_startup ); | ||||||
|  | 	engine_api.shutdown          = get_procedure_from_library< engine::ShutdownFn >       ( Lib_Handmade_Engine, symboL_shutdown ); | ||||||
|  | 	engine_api.update_and_render = get_procedure_from_library< engine::UpdateAndRenderFn >( Lib_Handmade_Engine, symboL_update_and_render ); | ||||||
|  | 	engine_api.update_audio      = get_procedure_from_library< engine::UpdateAudioFn >    ( Lib_Handmade_Engine, symbol_update_audio ); | ||||||
|  |  | ||||||
|  | 	engine_api.IsValid = | ||||||
|  | 			engine_api.on_module_reload | ||||||
|  | 		&&	engine_api.startup | ||||||
|  | 		&&	engine_api.shutdown | ||||||
|  | 		&&	engine_api.update_and_render | ||||||
|  | 		&&	engine_api.update_audio; | ||||||
|  | 	if ( engine_api.IsValid ) | ||||||
|  | 	{ | ||||||
|  | 		OutputDebugStringA( "Loaded engine module API\n" ); | ||||||
|  | 	} | ||||||
|  | 	return engine_api; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void unload_engine_module_api( engine::ModuleAPI* engine_api ) | ||||||
|  | { | ||||||
|  | 	if ( engine_api->IsValid ) | ||||||
|  | 	{ | ||||||
|  | 		FreeLibrary( Lib_Handmade_Engine ); | ||||||
|  | 		*engine_api = {}; | ||||||
|  | 		OutputDebugStringA( "Unloaded engine module API\n" ); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| NS_PLATFORM_END | NS_PLATFORM_END | ||||||
|  |  | ||||||
| int CALLBACK | int CALLBACK | ||||||
| @@ -774,6 +896,22 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho | |||||||
|  |  | ||||||
| 	QueryPerformanceFrequency( rcast(LARGE_INTEGER*, & Performance_Counter_Frequency) ); | 	QueryPerformanceFrequency( rcast(LARGE_INTEGER*, & Performance_Counter_Frequency) ); | ||||||
|  |  | ||||||
|  | 	// Prepare platform API | ||||||
|  | 	ModuleAPI platform_api {}; | ||||||
|  | 	{ | ||||||
|  | 	#if Build_Development | ||||||
|  | 		platform_api.debug_file_free_content  = & debug_file_free_content; | ||||||
|  | 		platform_api.debug_file_read_content  = & debug_file_read_content; | ||||||
|  | 		platform_api.debug_file_write_content = & debug_file_write_content; | ||||||
|  |  | ||||||
|  | 		platform_api.debug_set_pause_rendering = & debug_set_pause_rendering; | ||||||
|  | 	#endif | ||||||
|  | 		platform_api.get_monitor_refresh_rate = nullptr; | ||||||
|  | 		platform_api.set_monitor_refresh_rate = nullptr; | ||||||
|  | 		platform_api.get_engine_frame_target  = nullptr; | ||||||
|  | 		platform_api.set_engine_frame_target  = nullptr; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// Memory | 	// Memory | ||||||
| 	engine::Memory engine_memory {}; | 	engine::Memory engine_memory {}; | ||||||
| 	{ | 	{ | ||||||
| @@ -802,6 +940,9 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// Load engine module | ||||||
|  | 	engine::ModuleAPI engine_api = load_engine_module_api(); | ||||||
|  |  | ||||||
| 	WNDCLASSW window_class {}; | 	WNDCLASSW window_class {}; | ||||||
| 	HWND window_handle = nullptr; | 	HWND window_handle = nullptr; | ||||||
| 	{ | 	{ | ||||||
| @@ -935,6 +1076,8 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	engine_api.startup( & engine_memory, & platform_api ); | ||||||
|  |  | ||||||
| 	u64 last_frame_clock = timing_get_wall_clock(); | 	u64 last_frame_clock = timing_get_wall_clock(); | ||||||
| 	u64 last_frame_cycle = __rdtsc(); | 	u64 last_frame_cycle = __rdtsc(); | ||||||
| 	u64 flip_wall_clock = last_frame_clock; | 	u64 flip_wall_clock = last_frame_clock; | ||||||
| @@ -942,8 +1085,14 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho | |||||||
| #if Build_Development | #if Build_Development | ||||||
| 	u64 startup_cycles = last_frame_cycle - launch_cycle; | 	u64 startup_cycles = last_frame_cycle - launch_cycle; | ||||||
| 	f32 startup_ms     = timing_get_ms_elapsed( launch_clock, last_frame_clock ); | 	f32 startup_ms     = timing_get_ms_elapsed( launch_clock, last_frame_clock ); | ||||||
|  |  | ||||||
|  | 	char text_buffer[256]; | ||||||
|  | 	sprintf_s( text_buffer, sizeof(text_buffer), "Startup MS: %f\n", startup_ms ); | ||||||
|  | 	OutputDebugStringA( text_buffer ); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | 	u64 module_reload_counter = 0; | ||||||
|  |  | ||||||
| 	Running = true; | 	Running = true; | ||||||
| #if 0 | #if 0 | ||||||
| // This tests the play & write cursor update frequency. | // This tests the play & write cursor update frequency. | ||||||
| @@ -960,6 +1109,14 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho | |||||||
| #endif | #endif | ||||||
| 	while( Running ) | 	while( Running ) | ||||||
| 	{ | 	{ | ||||||
|  | 		if ( module_reload_counter > 120 ) | ||||||
|  | 		{ | ||||||
|  | 			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 ); | 		process_pending_window_messages( new_keyboard ); | ||||||
|  |  | ||||||
| 		// TODO(Ed): Offload polling to these functions later. | 		// TODO(Ed): Offload polling to these functions later. | ||||||
| @@ -1107,7 +1264,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Engine's logical iteration and rendering process | 		// Engine's logical iteration and rendering process | ||||||
| 		engine::update_and_render( & input, rcast(engine::OffscreenBuffer*, & Surface_Back_Buffer.Memory), & engine_memory ); | 		engine_api.update_and_render( & input, rcast(engine::OffscreenBuffer*, & Surface_Back_Buffer.Memory), & engine_memory, & platform_api ); | ||||||
|  |  | ||||||
| 		u64   audio_frame_start = timing_get_wall_clock(); | 		u64   audio_frame_start = timing_get_wall_clock(); | ||||||
| 		f32   flip_to_audio_ms  = timing_get_ms_elapsed( flip_wall_clock, audio_frame_start ); | 		f32   flip_to_audio_ms  = timing_get_ms_elapsed( flip_wall_clock, audio_frame_start ); | ||||||
| @@ -1194,7 +1351,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho | |||||||
| 			sound_buffer.RunningSampleIndex = ds_sound_buffer.RunningSampleIndex; | 			sound_buffer.RunningSampleIndex = ds_sound_buffer.RunningSampleIndex; | ||||||
| 			sound_buffer.SamplesPerSecond   = ds_sound_buffer.SamplesPerSecond; | 			sound_buffer.SamplesPerSecond   = ds_sound_buffer.SamplesPerSecond; | ||||||
| 			sound_buffer.Samples            = ds_sound_buffer.Samples; | 			sound_buffer.Samples            = ds_sound_buffer.Samples; | ||||||
| 			engine::update_audio( & sound_buffer, & engine_memory ); | 			engine_api.update_audio( & sound_buffer, & engine_memory, & platform_api ); | ||||||
|  |  | ||||||
| 			DebugTimeMarker* marker = & debug_markers[ debug_marker_index ]; | 			DebugTimeMarker* marker = & debug_markers[ debug_marker_index ]; | ||||||
| 			marker->OutputPlayCusror   = ds_play_cursor; | 			marker->OutputPlayCusror   = ds_play_cursor; | ||||||
| @@ -1331,7 +1488,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho | |||||||
| 		#endif | 		#endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	engine::shutdown(); | 	engine_api.shutdown( & engine_memory, & platform_api ); | ||||||
|  |  | ||||||
| 	if ( jsl_num_devices > 0 ) | 	if ( jsl_num_devices > 0 ) | ||||||
| 	{ | 	{ | ||||||
|   | |||||||
| @@ -14,6 +14,9 @@ Push-Location $path_root | |||||||
| 	   $debug 	     = $null | 	   $debug 	     = $null | ||||||
| 	   $analysis	 = $false | 	   $analysis	 = $false | ||||||
| 	   $dev          = $false | 	   $dev          = $false | ||||||
|  | 	   $platform     = $null | ||||||
|  | 	   $engine       = $null | ||||||
|  | 	   $game         = $null | ||||||
|  |  | ||||||
| [array] $vendors = @( "clang", "msvc" ) | [array] $vendors = @( "clang", "msvc" ) | ||||||
|  |  | ||||||
| @@ -26,11 +29,14 @@ if ( $args ) { $args | ForEach-Object { | |||||||
| 		"debug"               { $debug     = $true } | 		"debug"               { $debug     = $true } | ||||||
| 		"analysis"            { $analysis  = $true } | 		"analysis"            { $analysis  = $true } | ||||||
| 		"dev"                 { $dev       = $true } | 		"dev"                 { $dev       = $true } | ||||||
|  | 		"platform"            { $platform  = $true } | ||||||
|  | 		"engine"              { $engine    = $true } | ||||||
|  | 		"game"                { $game      = $true } | ||||||
| 	} | 	} | ||||||
| }} | }} | ||||||
| #endregion Argument | #endregion Argument | ||||||
|  |  | ||||||
| #region Configuration | #region Toolchain Configuration | ||||||
| if ($IsWindows) { | if ($IsWindows) { | ||||||
| 	# This HandmadeHero implementation is only designed for 64-bit systems | 	# This HandmadeHero implementation is only designed for 64-bit systems | ||||||
|     & $devshell -arch amd64 |     & $devshell -arch amd64 | ||||||
| @@ -45,7 +51,7 @@ write-host "Building HandmadeHero with $vendor" | |||||||
|  |  | ||||||
| if ( $dev ) { | if ( $dev ) { | ||||||
| 	if ( $debug -eq $null ) { | 	if ( $debug -eq $null ) { | ||||||
| 		$debug = $true | 		# $debug = $true | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if ( $optimize -eq $null ) { | 	if ( $optimize -eq $null ) { | ||||||
| @@ -118,42 +124,52 @@ function run-linker | |||||||
| if ( $vendor -match "clang" ) | if ( $vendor -match "clang" ) | ||||||
| { | { | ||||||
| 	# https://clang.llvm.org/docs/ClangCommandLineReference.html | 	# https://clang.llvm.org/docs/ClangCommandLineReference.html | ||||||
| 	$flag_all_c 					 = '/TC' | 	$flag_all_c 					   = '/TC' | ||||||
| 	$flag_all_cpp                    = '/TP' | 	$flag_all_cpp                      = '/TP' | ||||||
| 	$flag_compile                    = '-c' | 	$flag_compile                      = '-c' | ||||||
| 	$flag_color_diagnostics          = '-fcolor-diagnostics' | 	$flag_color_diagnostics            = '-fcolor-diagnostics' | ||||||
| 	$flag_no_color_diagnostics       = '-fno-color-diagnostics' | 	$flag_no_color_diagnostics         = '-fno-color-diagnostics' | ||||||
| 	$flag_debug                      = '-g' | 	$flag_debug                        = '-g' | ||||||
| 	$flag_debug_codeview             = '-gcodeview' | 	$flag_debug_codeview               = '-gcodeview' | ||||||
| 	$flag_define                     = '-D' | 	$flag_define                       = '-D' | ||||||
| 	$flag_exceptions_disabled		 = '-fno-exceptions' | 	$flag_exceptions_disabled		   = '-fno-exceptions' | ||||||
| 	$flag_preprocess 			     = '-E' | 	$flag_preprocess 			       = '-E' | ||||||
| 	$flag_include                    = '-I' | 	$flag_include                      = '-I' | ||||||
| 	$flag_library					 = '-l' | 	$flag_section_data                 = '-fdata-sections' | ||||||
| 	$flag_library_path				 = '-L' | 	$flag_section_functions            = '-ffunction-sections' | ||||||
| 	$flag_linker                     = '-Wl,' | 	$flag_library					   = '-l' | ||||||
| 	$flag_link_mapfile 				 = '-Map' | 	$flag_library_path				   = '-L' | ||||||
| 	$flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE' | 	$flag_linker                       = '-Wl,' | ||||||
| 	$flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS' | 	if ( $IsWindows ) { | ||||||
| 	$flag_link_win_machine_32        = '/MACHINE:X86' | 		$flag_link_dll                 = '/DLL' | ||||||
| 	$flag_link_win_machine_64        = '/MACHINE:X64' | 		$flag_link_mapfile 		       = '/MAP:' | ||||||
| 	$flag_link_win_debug             = '/DEBUG' | 		$flag_link_optimize_references = '/OPT:REF' | ||||||
| 	$flag_link_win_pdb 			     = '/PDB:' | 	} | ||||||
| 	$flag_link_win_path_output       = '/OUT:' | 	if ( $IsLinux ) { | ||||||
| 	$flag_no_optimization 		     = '-O0' | 		$flag_link_mapfile              = '--Map=' | ||||||
| 	$flag_optimize_fast 		     = '-O2' | 		$flag_link_optimize_references  = '--gc-sections' | ||||||
| 	$flag_optimize_size 		     = '-O1' | 	} | ||||||
| 	$flag_optimize_intrinsics		 = '-Oi' | 	$flag_link_win_subsystem_console    = '/SUBSYSTEM:CONSOLE' | ||||||
| 	$flag_path_output                = '-o' | 	$flag_link_win_subsystem_windows    = '/SUBSYSTEM:WINDOWS' | ||||||
| 	$flag_preprocess_non_intergrated = '-no-integrated-cpp' | 	$flag_link_win_machine_32           = '/MACHINE:X86' | ||||||
| 	$flag_profiling_debug            = '-fdebug-info-for-profiling' | 	$flag_link_win_machine_64           = '/MACHINE:X64' | ||||||
| 	$flag_set_stack_size			 = '-stack=' | 	$flag_link_win_debug                = '/DEBUG' | ||||||
| 	$flag_syntax_only				 = '-fsyntax-only' | 	$flag_link_win_pdb 			        = '/PDB:' | ||||||
| 	$flag_target_arch				 = '-target' | 	$flag_link_win_path_output          = '/OUT:' | ||||||
| 	$flag_wall 					     = '-Wall' | 	$flag_no_optimization 		        = '-O0' | ||||||
| 	$flag_warning 					 = '-W' | 	$flag_optimize_fast 		        = '-O2' | ||||||
| 	$flag_warnings_as_errors         = '-Werror' | 	$flag_optimize_size 		        = '-O1' | ||||||
| 	$flag_win_nologo 			     = '/nologo' | 	$flag_optimize_intrinsics		    = '-Oi' | ||||||
|  | 	$flag_path_output                   = '-o' | ||||||
|  | 	$flag_preprocess_non_intergrated    = '-no-integrated-cpp' | ||||||
|  | 	$flag_profiling_debug               = '-fdebug-info-for-profiling' | ||||||
|  | 	$flag_set_stack_size			    = '-stack=' | ||||||
|  | 	$flag_syntax_only				    = '-fsyntax-only' | ||||||
|  | 	$flag_target_arch				    = '-target' | ||||||
|  | 	$flag_wall 					        = '-Wall' | ||||||
|  | 	$flag_warning 					    = '-W' | ||||||
|  | 	$flag_warnings_as_errors            = '-Werror' | ||||||
|  | 	$flag_win_nologo 			        = '/nologo' | ||||||
|  |  | ||||||
| 	$ignore_warning_ms_include            = 'no-microsoft-include' | 	$ignore_warning_ms_include            = 'no-microsoft-include' | ||||||
| 	$ignore_warning_return_type_c_linkage = 'no-return-type-c-linkage' | 	$ignore_warning_return_type_c_linkage = 'no-return-type-c-linkage' | ||||||
| @@ -175,12 +191,12 @@ if ( $vendor -match "clang" ) | |||||||
|  |  | ||||||
| 	function build-simple | 	function build-simple | ||||||
| 	{ | 	{ | ||||||
| 		param( [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$executable ) | 		param( [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary ) | ||||||
| 		Write-Host "build-simple: clang" | 		Write-Host "build-simple: clang" | ||||||
|  |  | ||||||
| 		$object = $executable -replace '\.exe', '.obj' | 		$object = $binary -replace '\.exe', '.obj' | ||||||
| 		$pdb    = $executable -replace '\.exe', '.pdb' | 		$pdb    = $binary -replace '\.exe', '.pdb' | ||||||
| 		$map    = $executable -replace '\.exe', '.map' | 		$map    = $binary -replace '\.exe', '.map' | ||||||
|  |  | ||||||
| 		$compiler_args += @( | 		$compiler_args += @( | ||||||
| 			$flag_no_color_diagnostics, | 			$flag_no_color_diagnostics, | ||||||
| @@ -188,6 +204,8 @@ if ( $vendor -match "clang" ) | |||||||
| 			$flag_target_arch, $target_arch, | 			$flag_target_arch, $target_arch, | ||||||
| 			$flag_wall, | 			$flag_wall, | ||||||
| 			$flag_preprocess_non_intergrated, | 			$flag_preprocess_non_intergrated, | ||||||
|  | 			$flag_section_data, | ||||||
|  | 			$flag_section_functions, | ||||||
| 			( $flag_path_output + $object ) | 			( $flag_path_output + $object ) | ||||||
| 		) | 		) | ||||||
| 		if ( $optimized ) { | 		if ( $optimized ) { | ||||||
| @@ -214,12 +232,12 @@ if ( $vendor -match "clang" ) | |||||||
|  |  | ||||||
| 		$linker_args += @( | 		$linker_args += @( | ||||||
| 			$flag_link_win_machine_64, | 			$flag_link_win_machine_64, | ||||||
| 			$( $flag_link_win_path_output + $executable ) | 			$( $flag_link_win_path_output + $binary ) | ||||||
| 		) | 		) | ||||||
| 		if ( $debug ) { | 		if ( $debug ) { | ||||||
| 			$linker_args += $flag_link_win_debug | 			$linker_args += $flag_link_win_debug | ||||||
| 			$linker_args += $flag_link_win_pdb + $pdb | 			$linker_args += $flag_link_win_pdb + $pdb | ||||||
| 			# $linker_args += $flag_link_mapfile + $map | 			$linker_args += $flag_link_mapfile + $map | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$libraries | ForEach-Object { | 		$libraries | ForEach-Object { | ||||||
| @@ -227,7 +245,7 @@ if ( $vendor -match "clang" ) | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$linker_args += $object | 		$linker_args += $object | ||||||
| 		run-linker $linker $executable $linker_args | 		run-linker $linker $binary $linker_args | ||||||
|  |  | ||||||
| 		# $compiler_args += $unit | 		# $compiler_args += $unit | ||||||
| 		# $linker_args | ForEach-Object { | 		# $linker_args | ForEach-Object { | ||||||
| @@ -256,6 +274,7 @@ if ( $vendor -match "msvc" ) | |||||||
| 	$flag_dll 				         = '/LD' | 	$flag_dll 				         = '/LD' | ||||||
| 	$flag_dll_debug 			     = '/LDd' | 	$flag_dll_debug 			     = '/LDd' | ||||||
| 	$flag_linker 		             = '/link' | 	$flag_linker 		             = '/link' | ||||||
|  | 	$flag_link_dll                   = '/DLL' | ||||||
| 	$flag_link_mapfile 				 = '/MAP:' | 	$flag_link_mapfile 				 = '/MAP:' | ||||||
| 	$flag_link_optimize_references   = '/OPT:REF' | 	$flag_link_optimize_references   = '/OPT:REF' | ||||||
| 	$flag_link_win_debug 	         = '/DEBUG' | 	$flag_link_win_debug 	         = '/DEBUG' | ||||||
| @@ -287,12 +306,12 @@ if ( $vendor -match "msvc" ) | |||||||
| 	# This works because this project uses a single unit to build | 	# This works because this project uses a single unit to build | ||||||
| 	function build-simple | 	function build-simple | ||||||
| 	{ | 	{ | ||||||
| 		param( [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$executable ) | 		param( [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary ) | ||||||
| 		Write-Host "build-simple: msvc" | 		Write-Host "build-simple: msvc" | ||||||
|  |  | ||||||
| 		$object = $executable -replace '\.exe', '.obj' | 		$object = $binary -replace '\.(exe|dll)$', '.obj' | ||||||
| 		$pdb    = $executable -replace '\.exe', '.pdb' | 		$pdb    = $binary -replace '\.(exe|dll)$', '.pdb' | ||||||
| 		$map    = $executable -replace '\.exe', '.map' | 		$map    = $binary -replace '\.(exe|dll)$', '.map' | ||||||
|  |  | ||||||
| 		$compiler_args += @( | 		$compiler_args += @( | ||||||
| 			$flag_nologo, | 			$flag_nologo, | ||||||
| @@ -336,18 +355,18 @@ if ( $vendor -match "msvc" ) | |||||||
| 		$linker_args += @( | 		$linker_args += @( | ||||||
| 			$flag_nologo, | 			$flag_nologo, | ||||||
| 			$flag_link_win_machine_64, | 			$flag_link_win_machine_64, | ||||||
| 			( $flag_link_win_path_output + $executable ) | 			( $flag_link_win_path_output + $binary ) | ||||||
| 		) | 		) | ||||||
| 		if ( $debug ) { | 		if ( $debug ) { | ||||||
| 			$linker_args += $flag_link_win_debug | 			$linker_args += $flag_link_win_debug | ||||||
| 			$linker_args += $flag_link_win_pdb + $pdb | 			$linker_args += $flag_link_win_pdb + $pdb | ||||||
| 			# $linker_args += $flag_link_mapfile + $map | 			$linker_args += $flag_link_mapfile + $map | ||||||
| 		} | 		} | ||||||
| 		else { | 		else { | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$linker_args += $object | 		$linker_args += $object | ||||||
| 		run-linker $linker $executable $linker_args | 		run-linker $linker $binary $linker_args | ||||||
|  |  | ||||||
| 		# $compiler_args += $unit | 		# $compiler_args += $unit | ||||||
| 		# $compiler_args += $flag_linker | 		# $compiler_args += $flag_linker | ||||||
| @@ -360,11 +379,14 @@ if ( $vendor -match "msvc" ) | |||||||
| } | } | ||||||
| #endregion Configuration | #endregion Configuration | ||||||
|  |  | ||||||
|  | #region Building | ||||||
| $path_project  = Join-Path $path_root    'project' | $path_project  = Join-Path $path_root    'project' | ||||||
| $path_build    = Join-Path $path_root    'build' | $path_build    = Join-Path $path_root    'build' | ||||||
|  | $path_data     = Join-Path $path_root	 'data' | ||||||
| $path_deps     = Join-Path $path_project 'dependencies' | $path_deps     = Join-Path $path_project 'dependencies' | ||||||
| $path_gen      = Join-Path $path_project 'gen' | $path_gen      = Join-Path $path_project 'gen' | ||||||
| $path_platform = Join-Path $path_project 'platform' | $path_platform = Join-Path $path_project 'platform' | ||||||
|  | $path_engine   = Join-Path $path_project 'engine' | ||||||
|  |  | ||||||
| $update_deps = Join-Path $PSScriptRoot 'update_deps.ps1' | $update_deps = Join-Path $PSScriptRoot 'update_deps.ps1' | ||||||
|  |  | ||||||
| @@ -376,21 +398,21 @@ if ( (Test-Path $path_deps) -eq $false ) { | |||||||
| 	& $update_deps | 	& $update_deps | ||||||
| } | } | ||||||
|  |  | ||||||
| $includes = @( |  | ||||||
| 	$path_project, |  | ||||||
| 	$path_gen, |  | ||||||
| 	# $path_deps, |  | ||||||
| 	$path_platform |  | ||||||
| ) |  | ||||||
| $compiler_args = @() |  | ||||||
| $compiler_args += ( $flag_define + 'GEN_TIME' ) |  | ||||||
|  |  | ||||||
| $linker_args = @( |  | ||||||
| 	$flag_link_win_subsystem_console |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| #region Handmade Generate | #region Handmade Generate | ||||||
| if ( $false ) { | if ( $false ) { | ||||||
|  | 	$includes = @( | ||||||
|  | 		$path_project, | ||||||
|  | 		$path_gen, | ||||||
|  | 		# $path_deps, | ||||||
|  | 		$path_platform | ||||||
|  | 	) | ||||||
|  | 	$compiler_args = @() | ||||||
|  | 	$compiler_args += ( $flag_define + 'GEN_TIME' ) | ||||||
|  |  | ||||||
|  | 	$linker_args = @( | ||||||
|  | 		$flag_link_win_subsystem_console | ||||||
|  | 	) | ||||||
|  |  | ||||||
| 	$unit       = Join-Path $path_gen   'handmade_gen.cpp' | 	$unit       = Join-Path $path_gen   'handmade_gen.cpp' | ||||||
| 	$executable = Join-Path $path_build 'handmade_gen.exe' | 	$executable = Join-Path $path_build 'handmade_gen.exe' | ||||||
|  |  | ||||||
| @@ -408,10 +430,7 @@ if ( $false ) { | |||||||
|  |  | ||||||
| #region Handmade Runtime | #region Handmade Runtime | ||||||
| $includes = @( | $includes = @( | ||||||
| 	$path_project, | 	$path_project | ||||||
| 	$path_gen, |  | ||||||
| 	$path_deps, |  | ||||||
| 	$path_platform |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| # Microsoft | # Microsoft | ||||||
| @@ -423,9 +442,6 @@ $lib_winmm  = 'Winmm.lib' | |||||||
| # Github | # Github | ||||||
| $lib_jsl = Join-Path $path_deps 'JoyShockLibrary/x64/JoyShockLibrary.lib' | $lib_jsl = Join-Path $path_deps 'JoyShockLibrary/x64/JoyShockLibrary.lib' | ||||||
|  |  | ||||||
| $unit       = Join-Path $path_project 'handmade_win32.cpp' |  | ||||||
| $executable = Join-Path $path_build   'handmade_win32.exe' |  | ||||||
|  |  | ||||||
| $stack_size = 1024 * 1024 * 4 | $stack_size = 1024 * 1024 * 4 | ||||||
|  |  | ||||||
| $compiler_args = @( | $compiler_args = @( | ||||||
| @@ -436,9 +452,6 @@ $compiler_args = @( | |||||||
| 	$flag_warnings_as_errors | 	$flag_warnings_as_errors | ||||||
| 	$flag_optimize_intrinsics | 	$flag_optimize_intrinsics | ||||||
|  |  | ||||||
| 	($flag_define + 'Build_DLL=0' ) |  | ||||||
|  |  | ||||||
| 	# For now this script only supports unity builds... (for the full binary) |  | ||||||
| 	($flag_define + 'Build_Unity=1' ) | 	($flag_define + 'Build_Unity=1' ) | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -449,19 +462,108 @@ else { | |||||||
| 	$compiler_args += ( $flag_define + 'Build_Development=0' ) | 	$compiler_args += ( $flag_define + 'Build_Development=0' ) | ||||||
| } | } | ||||||
|  |  | ||||||
| $linker_args = @( | if ( $engine ) | ||||||
| 	$lib_gdi32, | { | ||||||
| 	# $lib_xinput, | 	$engine_compiler_args = $compiler_args | ||||||
| 	$lib_user32, | 	$engine_compiler_args += ($flag_define + 'Build_DLL=1' ) | ||||||
| 	$lib_winmm, |  | ||||||
|  |  | ||||||
| 	$lib_jsl, | 	if ( $vendor -eq 'msvc' ) | ||||||
|  | 	{ | ||||||
|  | 		$engine_compiler_args += ($flag_define + 'Engine_API=__declspec(dllexport)') | ||||||
|  | 	} | ||||||
|  | 	if ( $vendor -eq 'clang' ) | ||||||
|  | 	{ | ||||||
|  | 		$engine_compiler_args += ($flag_define + 'Engine_API=__attribute__((visibility("default")))') | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	$flag_link_win_subsystem_windows | 	$linker_args = @( | ||||||
| 	$flag_link_optimize_references | 		$flag_link_dll, | ||||||
| ) | 		$flag_link_optimize_references | ||||||
|  | 	) | ||||||
|  |  | ||||||
| build-simple $includes $compiler_args $linker_args $unit $executable | 	$unit            = Join-Path $path_project 'handmade_engine.cpp' | ||||||
|  | 	$dynamic_library = Join-Path $path_build   '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 | ||||||
|  |  | ||||||
|  | 		# 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 | ||||||
|  | 		# and mapping them to their found decorated name | ||||||
|  |  | ||||||
|  | 		$engine_symbols = @( | ||||||
|  | 			'on_module_reload', | ||||||
|  | 			'startup', | ||||||
|  | 			'shutdown', | ||||||
|  | 			'update_and_render', | ||||||
|  | 			'update_audio' | ||||||
|  | 		) | ||||||
|  |  | ||||||
|  | 		$path_engine_map = Join-Path $path_build 'handmade_engine.map' | ||||||
|  |  | ||||||
|  | 		$engine_symbol_table = @() | ||||||
|  | 		$engine_symbol_list  = @() | ||||||
|  | 		Get-Content -Path $path_engine_map | ForEach-Object { | ||||||
|  | 			# Split each line by whitespace | ||||||
|  | 			$tokens = $_ -split '\s+', 3 | ||||||
|  |  | ||||||
|  | 			# Extract only the decorated name using regex for both MSVC and Clang conventions | ||||||
|  | 			$decoratedName = ($tokens[2] -match '(\?[\w@]+|_Z[\w@]+)' ) ? $matches[1] : $null | ||||||
|  |  | ||||||
|  | 			# Check each regular name against the current line | ||||||
|  | 			foreach ($name in $engine_symbols) { | ||||||
|  | 				if ($decoratedName -like "*$name*") { | ||||||
|  | 					$engine_symbol_table += $name + ', ' + $decoratedName | ||||||
|  | 					$engine_symbol_list  += $decoratedName | ||||||
|  | 					$engine_symbols = $engine_symbols -ne $name  # Remove the found symbol from the array | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		write-host "Engine Symbol Table:" -ForegroundColor Green | ||||||
|  | 		$engine_symbol_table | ForEach-Object { | ||||||
|  | 			write-host "`t$_" -ForegroundColor Green | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		# Write the symbol table to a file | ||||||
|  | 		$path_engine_symbols = Join-Path $path_data 'handmade_engine.symbols' | ||||||
|  | 		$engine_symbol_list | Out-File -Path $path_engine_symbols | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | if ( $platform ) | ||||||
|  | { | ||||||
|  | 	$platform_compiler_args  = $compiler_args | ||||||
|  | 	$platform_compiler_args += ($flag_define + 'Build_DLL=0' ) | ||||||
|  |  | ||||||
|  | 	$linker_args = @( | ||||||
|  | 		$lib_gdi32, | ||||||
|  | 		# $lib_xinput, | ||||||
|  | 		$lib_user32, | ||||||
|  | 		$lib_winmm, | ||||||
|  |  | ||||||
|  | 		$lib_jsl, | ||||||
|  |  | ||||||
|  | 		$flag_link_win_subsystem_windows | ||||||
|  | 		$flag_link_optimize_references | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	$unit       = Join-Path $path_project 'handmade_win32.cpp' | ||||||
|  | 	$executable = Join-Path $path_build   '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 | ||||||
|  | 	} | ||||||
|  | } | ||||||
| #endregion Handmade Runtime | #endregion Handmade Runtime | ||||||
|  |  | ||||||
| Pop-Location | Pop-Location | ||||||
|  | #endregion Building | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							| @@ -23,5 +23,6 @@ if ( -not (Test-Path $vs_devshell) ) { | |||||||
|  |  | ||||||
| # Launch the Visual Studio Developer Shell | # Launch the Visual Studio Developer Shell | ||||||
| Push-Location | Push-Location | ||||||
|  | write-host @args | ||||||
| & $vs_devshell @args | & $vs_devshell @args | ||||||
| Pop-Location | Pop-Location | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user