Day 21 complete

This commit is contained in:
Edward R. Gonzalez 2023-09-26 17:26:35 -04:00
parent 1c3cf08687
commit 9220550dd4
22 changed files with 640 additions and 254 deletions

2
.gitignore vendored
View File

@ -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
View File

@ -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"

View File

@ -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>

View File

@ -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" />

View File

@ -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
View 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!
![img](https://files.catbox.moe/sdebtc.png)
![img](https://files.catbox.moe/ufkacl.png)
![img](https://files.catbox.moe/zr52au.png)
![img](https://files.catbox.moe/g3f1vv.png)

View File

@ -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 );
do_once_start
assert( sizeof(EngineState) <= memory->PersistentSize ); assert( sizeof(EngineState) <= memory->PersistentSize );
state->ToneVolume = 1000; state->ToneVolume = 1000;
state->WaveToneHz = 120;
state->XOffset = 0; state->XOffset = 0;
state->YOffset = 0; state->YOffset = 0;
state->WaveSwitch = false;
state->SampleWaveSwitch = false;
state->WaveToneHz = 120;
state->SampleWaveSineTime = 0.f;
state->RendererPaused = false;
#if Build_Debug && 0 #if Build_Debug && 0
{ {
using namespace platform; using namespace platform;
char const* file_path = __FILE__; char const* file_path = __FILE__;
Debug_FileContent file_content = debug_file_read_content( file_path ); Debug_FileContent file_content = platform_api->debug_file_read_content( file_path );
if ( file_content.Size ) if ( file_content.Size )
{ {
debug_file_write_content( "test.out", file_content.Size, file_content.Data ); platform_api->debug_file_write_content( "test.out", file_content.Size, file_content.Data );
debug_file_free_content( & file_content ); platform_api->debug_file_free_content( & file_content );
} }
} }
#endif #endif
do_once_end }
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

View File

@ -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

View 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;
}

View File

@ -4,5 +4,5 @@
#pragma once #pragma once
#include "engine.hpp" #include "engine/engine.hpp"

67
project/handmade.hpp Normal file
View 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

View 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

View File

@ -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

View File

@ -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 )

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,3 @@
/*
This represents the API only accessible to the platform layer to fullfill for the game layer.
*/

View File

@ -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

View File

@ -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 )
{ {

View File

@ -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 ) {
@ -129,10 +135,20 @@ if ( $vendor -match "clang" )
$flag_exceptions_disabled = '-fno-exceptions' $flag_exceptions_disabled = '-fno-exceptions'
$flag_preprocess = '-E' $flag_preprocess = '-E'
$flag_include = '-I' $flag_include = '-I'
$flag_section_data = '-fdata-sections'
$flag_section_functions = '-ffunction-sections'
$flag_library = '-l' $flag_library = '-l'
$flag_library_path = '-L' $flag_library_path = '-L'
$flag_linker = '-Wl,' $flag_linker = '-Wl,'
$flag_link_mapfile = '-Map' if ( $IsWindows ) {
$flag_link_dll = '/DLL'
$flag_link_mapfile = '/MAP:'
$flag_link_optimize_references = '/OPT:REF'
}
if ( $IsLinux ) {
$flag_link_mapfile = '--Map='
$flag_link_optimize_references = '--gc-sections'
}
$flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE' $flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE'
$flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS' $flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS'
$flag_link_win_machine_32 = '/MACHINE:X86' $flag_link_win_machine_32 = '/MACHINE:X86'
@ -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,6 +398,8 @@ if ( (Test-Path $path_deps) -eq $false ) {
& $update_deps & $update_deps
} }
#region Handmade Generate
if ( $false ) {
$includes = @( $includes = @(
$path_project, $path_project,
$path_gen, $path_gen,
@ -389,8 +413,6 @@ $linker_args = @(
$flag_link_win_subsystem_console $flag_link_win_subsystem_console
) )
#region Handmade Generate
if ( $false ) {
$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,6 +462,84 @@ else {
$compiler_args += ( $flag_define + 'Build_Development=0' ) $compiler_args += ( $flag_define + 'Build_Development=0' )
} }
if ( $engine )
{
$engine_compiler_args = $compiler_args
$engine_compiler_args += ($flag_define + 'Build_DLL=1' )
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")))')
}
$linker_args = @(
$flag_link_dll,
$flag_link_optimize_references
)
$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 = @( $linker_args = @(
$lib_gdi32, $lib_gdi32,
# $lib_xinput, # $lib_xinput,
@ -461,7 +552,18 @@ $linker_args = @(
$flag_link_optimize_references $flag_link_optimize_references
) )
build-simple $includes $compiler_args $linker_args $unit $executable $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.

View File

@ -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