diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 6a38b7f..71da193 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -13,6 +13,7 @@ "_UNICODE", "GEN_TIME", "Build_Debug", + "Build_Development", ], "windowsSdkVersion": "10.0.22621.0", "compilerPath": "cl.exe", diff --git a/README.md b/README.md index 596d58e..26c7352 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Any code I do for this [series](https://handmadehero.org) will be here. ## Scripts -* `build.ps1` - Builds the project use `.\scripts\build msvc` or `.\scripts\build clang`. Add `release` to build in release mode +* `build.ps1` - Builds the project use `.\scripts\build msvc debug` or `.\scripts\build clang debug`. Add `optimize` for optimized builds. * `clean.ps1` - Cleans the project * `update_deps.ps1` - Updates the project dependencies to their latest from their respective repos. (Not done automatically on build) @@ -21,3 +21,7 @@ The build is done in two stages: 1. ~~Build and run metaprogram to scan and generate dependent code.~~ (Not needed yet) 2. Build the handmade hero runtime. +## Gallery + +![img](https://files.catbox.moe/fwjm1m.png) +![img](https://files.catbox.moe/b7ifa8.png) diff --git a/docs/Day 014.md b/docs/Day 014.md new file mode 100644 index 0000000..b301120 --- /dev/null +++ b/docs/Day 014.md @@ -0,0 +1,29 @@ +# Day 14 + +The `game_state` example felt like a forced way to start doing memory management but thats fine. +I'm not making any design changes to it other than setting it as engine::Memory instead of game_memory (since I'm doing 3 api layers instead of the 2 hes doing). + +Learning about the virtual memory mapping was nice, it was something on a backburner for me to learn about but I never got around to it. +The address setting was quite awesome to see. + +## Some thoughts on platform API + +I like Casey's one call idea he emphasized in the Q&A, don't really want to detract from that. + +Instead I just want to change it so that by the time you enter the engine loop you are guaranteed to have all the engine data provided by the platform layer. +But, without having to shove everything in the procedure captures. Instead, just have an global engine context thats invalid until engine initialization is done by the platfomr layer. + + +So it might end up something like this: + +![img](https://files.catbox.moe/u1q1au.png) + +It ends up making two api paths, one for engine to do initialization when platform provides all the critical data engine needs, and another where the platform provides the engine update function. + +It will be known to the user and engine that platform will update some of the engine data ( like input, render, sound, etc ), which will be done in the platform update function. +This is already the case, just need to convey it more strongly if I'm decoupling it from the procedure captures. + +This is so that I don't have to do insane chaining to pass these captures when I know some of this data should be contextually known to all procedures within the engine. +I have a feeling Casey may already aleivate this or show that it's not a problem in the future so we'll see and I'll adjust accordingly. + +I premtively also did the boxes for an 'editor' and 'game' api. Where there could be possible `n` amount of api layers. I'm not sure if I'll do this, but I'm leaving it open for now. What will most likely happen is they'll still be priority to keep it to a very minimal amount, and not give the game or editor the ability to poke at the engine much at all (which leads to the circular API Casey is warning about). diff --git a/docs/Visuals.afdesign b/docs/Visuals.afdesign index bb87c7b..79f80fd 100644 Binary files a/docs/Visuals.afdesign and b/docs/Visuals.afdesign differ diff --git a/project/engine.cpp b/project/engine.cpp index 2eebe0a..ae66fa7 100644 --- a/project/engine.cpp +++ b/project/engine.cpp @@ -3,43 +3,46 @@ NS_ENGINE_BEGIN +struct EngineState +{ + s32 WavePeriod; + s32 WaveToneHz; + s32 ToneVolume; + s32 XOffset; + s32 YOffset; +}; -using GetSoundSampleValueFn = s16( SoundBuffer* sound_buffer ); - -global s32 SoundTest_ToneVolume = 3000; -global s32 SoundTest_WavePeriod = 0; -global s32 SoundTest_WaveToneHz = 262; - +using GetSoundSampleValueFn = s16( EngineState* state, SoundBuffer* sound_buffer ); internal s16 -square_wave_sample_value( SoundBuffer* sound_buffer ) +square_wave_sample_value( EngineState* state, SoundBuffer* sound_buffer ) { - s16 sample_value = (sound_buffer->RunningSampleIndex / (SoundTest_WavePeriod /2)) % 2 ? - SoundTest_ToneVolume : - SoundTest_ToneVolume; + s16 sample_value = (sound_buffer->RunningSampleIndex / (state->WavePeriod / 2) ) % 2 ? + state->ToneVolume : - state->ToneVolume; return sample_value; } internal s16 -sine_wave_sample_value( SoundBuffer* sound_buffer ) +sine_wave_sample_value( EngineState* state, SoundBuffer* sound_buffer ) { local_persist f32 time = 0.f; // time = TAU * (f32)sound_buffer->RunningSampleIndex / (f32)SoundTest_WavePeriod; f32 sine_value = sinf( time ); - s16 sample_value = scast(u16, sine_value * SoundTest_ToneVolume); + s16 sample_value = scast(u16, sine_value * state->ToneVolume); - time += TAU * 1.0f / scast(f32, SoundTest_WavePeriod ); + time += TAU * 1.0f / scast(f32, state->WavePeriod ); return sample_value; } internal void -output_sound( SoundBuffer* sound_buffer, GetSoundSampleValueFn* get_sample_value ) +output_sound( EngineState* state, SoundBuffer* sound_buffer, GetSoundSampleValueFn* get_sample_value ) { s16* sample_out = sound_buffer->Samples; for ( u32 sample_index = 0; sample_index < sound_buffer->NumSamples; ++ sample_index ) { - s16 sample_value = get_sample_value( sound_buffer ); + s16 sample_value = get_sample_value( state, sound_buffer ); sound_buffer->RunningSampleIndex++; // char ms_timing_debug[256] {}; @@ -106,9 +109,19 @@ b32 input_using_analog() return false; } +internal void +startup() +{ +} + +internal void +shutdown() +{ +} + // TODO : I rather expose the back_buffer and sound_buffer using getters for access in any function. internal void -update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer ) +update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer, Memory* memory ) { // Graphics & Input Test local_persist u32 x_offset = 0; @@ -128,11 +141,17 @@ update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* } #endif -#if 1 + EngineState* state = rcast( EngineState*, memory->Persistent ); do_once_start - { - SoundTest_WavePeriod = sound_buffer->SamplesPerSecond / SoundTest_WaveToneHz; - } + assert( sizeof(EngineState) <= memory->PersistentSize ); + + state->ToneVolume = 3000; + state->WaveToneHz = 262; + state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz; + + state->XOffset = 0; + state->YOffset = 0; + do_once_end ControllerState* controller = & input->Controllers[0]; @@ -151,22 +170,22 @@ update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* if ( pad->Triangle.State ) { - SoundTest_ToneVolume += 10; + state->ToneVolume += 10; } if ( pad->Circle.State ) { - SoundTest_ToneVolume -= 10; + state->ToneVolume -= 10; } if ( pad->Square.State ) { - SoundTest_WaveToneHz += 1; - SoundTest_WavePeriod = sound_buffer->SamplesPerSecond / SoundTest_WaveToneHz; + state->WaveToneHz += 1; + state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz; } if ( pad->X.State ) { - SoundTest_WaveToneHz -= 1; - SoundTest_WavePeriod = sound_buffer->SamplesPerSecond / SoundTest_WaveToneHz; + state->WaveToneHz -= 1; + state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz; } if ( pad->Options.State ) @@ -193,22 +212,22 @@ update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* if ( pad->Y.State ) { - SoundTest_ToneVolume += 10; + state->ToneVolume += 10; } if ( pad->B.State ) { - SoundTest_ToneVolume -= 10; + state->ToneVolume -= 10; } if ( pad->X.State ) { - SoundTest_WaveToneHz += 1; - SoundTest_WavePeriod = sound_buffer->SamplesPerSecond / SoundTest_WaveToneHz; + state->WaveToneHz += 1; + state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz; } if ( pad->A.State ) { - SoundTest_WaveToneHz -= 1; - SoundTest_WavePeriod = sound_buffer->SamplesPerSecond / SoundTest_WaveToneHz; + state->WaveToneHz -= 1; + state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz; } if ( pad->Start.State ) @@ -221,13 +240,12 @@ update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* // TODO(Ed) : Add rumble test } } -#endif // TODO(Ed) : Allow sample offsets here for more robust platform options if ( ! wave_switch ) - output_sound( sound_buffer, sine_wave_sample_value ); + output_sound( state, sound_buffer, sine_wave_sample_value ); else - output_sound( sound_buffer, square_wave_sample_value ); + output_sound( state, sound_buffer, square_wave_sample_value ); render_weird_graident( back_buffer, x_offset, y_offset ); } diff --git a/project/engine.h b/project/engine.h index 71fde35..52f1eb2 100644 --- a/project/engine.h +++ b/project/engine.h @@ -11,6 +11,29 @@ NS_ENGINE_BEGIN +struct Clocks +{ + // TODO(Ed) : Clock values... + f32 SecondsElapsed; +}; + +struct Memory +{ + // All memory for the engine is required to be zero initialized. + + // Wiped on shutdown + void* Persistent; + u64 PersistentSize; + + // Wiped on a per-frame basis + // void* Frame; + // u64 FrameSize; + + // Wiped whenever the engine wants to? + void* Transient; + u64 TransientSize; +}; + struct OffscreenBuffer { void* Memory; // Lets use directly mess with the "pixel's memory buffer" @@ -157,6 +180,6 @@ b32 input_using_analog(); // Needs a contextual reference to four things: // Timing, Input, Bitmap Buffer, Sound Buffer -void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer ); +void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer, Memory* memory ); NS_ENGINE_END diff --git a/project/handmace.cpp b/project/handmade.cpp similarity index 100% rename from project/handmace.cpp rename to project/handmade.cpp diff --git a/project/platform/handmade_win32.cpp b/project/platform/handmade_win32.cpp index 3ef2aa6..c4aa9a8 100644 --- a/project/platform/handmade_win32.cpp +++ b/project/platform/handmade_win32.cpp @@ -97,7 +97,6 @@ struct SoundOutput s32 LatencySampleCount; }; - HRESULT WINAPI DirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter ); using DirectSoundCreateFn = HRESULT WINAPI (LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter ); @@ -511,6 +510,48 @@ WinMain( { using namespace win32; + // Memory + engine::Memory engine_memory {}; + { + engine_memory.PersistentSize = megabytes( 64 ); + // engine_memory.FrameSize = megabytes( 64 ); + engine_memory.TransientSize = gigabytes( 2 ); + + u64 total_size = engine_memory.PersistentSize + // + engine_memory.FrameSize + + engine_memory.TransientSize; + + #if Build_Debug + void* Base_Address = (void*) terabytes( 1 ); + // void* Frame_Address = (void*) terabytes( 2 ); + // void* Transient_Address = (void*) terabytes( 2 ); + #else + void* Base_Address = 0; + // void* Frame_Address = 0; + // void* Transient_Address = 0; + #endif + + engine_memory.Persistent = VirtualAlloc( Base_Address, total_size + , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ); + engine_memory.Transient = rcast( u8*, engine_memory.Persistent ) + engine_memory.PersistentSize; + + #if 0 + engine_memory.Frame = VirtualAlloc( 0, engine_memory.FrameSize + , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ); + + engine_memory.Transient = VirtualAlloc( 0, engine_memory.TransientSize + , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ); + #endif + + if ( engine_memory.Persistent == nullptr + // || ! engine_memory.Frame + || engine_memory.Transient == nullptr ) + { + // TODO : Diagnostic Logging + return -1; + } + } + // MessageBox( 0, L"First message!", L"Handmade Hero", MB_Ok_Btn | MB_Icon_Information ); WNDCLASSW window_class {}; @@ -567,6 +608,8 @@ WinMain( SoundBufferSamples = rcast( s16*, VirtualAlloc( 0, 48000 * 2 * sizeof(s16) , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write )); + assert( SoundBufferSamples ); + sound_output.RunningSampleIndex = 0; sound_output.LatencySampleCount = DS_SecondaryBuffer_SamplesPerSecond / 15; // ds_clear_sound_buffer( & sound_output ); @@ -599,8 +642,8 @@ WinMain( using JSL_DeviceHandle = int; u32 jsl_num_devices - // = JslConnectDevices(); - = 0; + = JslConnectDevices(); + // = 0; JSL_DeviceHandle jsl_device_handles[4] {}; { xinput_load_library_bindings(); @@ -809,7 +852,7 @@ WinMain( sound_buffer.SamplesPerSecond = DS_SecondaryBuffer_SamplesPerSecond; sound_buffer.Samples = SoundBufferSamples; - engine::update_and_render( & input, rcast(engine::OffscreenBuffer*, & BackBuffer.Memory), & sound_buffer ); + engine::update_and_render( & input, rcast(engine::OffscreenBuffer*, & BackBuffer.Memory), & sound_buffer, & engine_memory ); // Rendering { diff --git a/project/platform/macros.h b/project/platform/macros.h index dd10ee0..1853b21 100644 --- a/project/platform/macros.h +++ b/project/platform/macros.h @@ -18,7 +18,7 @@ #define do_once() \ do \ { \ - static \ + local_persist \ bool Done = false; \ if ( Done ) \ return; \ @@ -29,7 +29,7 @@ #define do_once_start \ do \ { \ - static \ + local_persist \ bool Done = false; \ if ( Done ) \ break; \ @@ -41,3 +41,29 @@ #define array_count( array ) ( sizeof( array ) / sizeof( ( array )[0] ) ) + +// TODO(Ed) : Move to memory header eventually +#define kilobytes( x ) ( ( x ) * ( s64 )( 1024 ) ) +#define megabytes( x ) ( kilobytes( x ) * ( s64 )( 1024 ) ) +#define gigabytes( x ) ( megabytes( x ) * ( s64 )( 1024 ) ) +#define terabytes( x ) ( gigabytes( x ) * ( s64 )( 1024 ) ) + +// TODO(Ed) : Move to debug header eventually + +#if Build_Development +# define assert( expression ) \ + if ( !( expression ) ) \ + { \ + *( int* )0 = 0; \ + } + // platform::assertion_failure( __FILE__, __LINE__, #expression ); +#else +# define assert( expression ) +#endif + +// TODO(Ed) : Add this sauce later +#if 0 +#define congrats( message ) +#define ensure( condition, expression ) +#define fatal( message ) +#endif diff --git a/project/platform/memory.h b/project/platform/memory.h new file mode 100644 index 0000000..e69de29 diff --git a/project/platform/platform.h b/project/platform/platform.h index 8cc58bd..b0c14a4 100644 --- a/project/platform/platform.h +++ b/project/platform/platform.h @@ -9,4 +9,3 @@ #include "generics.h" #include "math_constants.h" #include "types.h" - diff --git a/project/platform/win32.h b/project/platform/win32.h index ca7ad02..cea9628 100644 --- a/project/platform/win32.h +++ b/project/platform/win32.h @@ -15,7 +15,7 @@ // #include "windows/file.h" // #include "windows/io.h" -// #ifdef Build_Debug +// #if Build_Debug // # include "windows/dbghelp.h" // #endif diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 2b8040d..42edb21 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -8,9 +8,10 @@ Push-Location $path_root #region Arguments $vendor = $null - $optimized = $false - $debug = $false + $optimized = $null + $debug = $null $analysis = $false + $dev = $false [array] $vendors = @( "clang", "msvc" ) @@ -22,6 +23,7 @@ if ( $args ) { $args | ForEach-Object { "optimized" { $optimized = $true } "debug" { $debug = $true } "analysis" { $analysis = $true } + "dev" { $dev = $true } } }} #endregion Argument @@ -39,7 +41,16 @@ if ( $vendor -eq $null ) { } write-host "Building HandmadeHero with $vendor" -write-host "Build Type: $(if ($release) {"Release"} else {"Debug"} )" + +if ( $dev ) { + if ( $debug -eq $null ) { + $debug = $true + } + + if ( $optimize -eq $null ) { + $optimize = $false + } +} function run-compiler { @@ -180,9 +191,12 @@ if ( $vendor -match "clang" ) $compiler_args += $flag_no_optimization } if ( $debug ) { - $compiler_args += ( $flag_define + 'Build_Debug' ) + $compiler_args += ( $flag_define + 'Build_Debug=1' ) $compiler_args += $flag_debug, $flag_debug_codeview, $flag_profiling_debug } + else { + $compiler_args += ( $flag_define + 'Build_Debug=0' ) + } $warning_ignores | ForEach-Object { $compiler_args += $flag_warning + $_ @@ -289,7 +303,7 @@ if ( $vendor -match "msvc" ) if ( $debug ) { $compiler_args += $flag_debug - $compiler_args += ( $flag_define + 'Build_Debug' ) + $compiler_args += ( $flag_define + 'Build_Debug=1' ) $compiler_args += ( $flag_path_debug + $path_build + '\' ) $compiler_args += $flag_link_win_rt_static_debug @@ -298,6 +312,7 @@ if ( $vendor -match "msvc" ) } } else { + $compiler_args += ( $flag_define + 'Build_Debug=0' ) $compiler_args += $flag_link_win_rt_static } $compiler_args += $includes | ForEach-Object { $flag_include + $_ } @@ -404,6 +419,13 @@ $compiler_args = @( # ($flag_set_stack_size + $stack_size) ) +if ( $dev ) { + $compiler_args += ( $flag_define + 'Build_Development=1' ) +} +else { + $compiler_args += ( $flag_define + 'Build_Development=0' ) +} + $linker_args = @( $lib_gdi32, # $lib_xinput, diff --git a/scripts/handmade.rdbg b/scripts/handmade.rdbg index 649867a..7e83307 100644 Binary files a/scripts/handmade.rdbg and b/scripts/handmade.rdbg differ