Day 14 complete

This commit is contained in:
Edward R. Gonzalez 2023-09-18 20:16:40 -04:00
parent abe3066071
commit 3de4178fff
14 changed files with 214 additions and 49 deletions

View File

@ -13,6 +13,7 @@
"_UNICODE",
"GEN_TIME",
"Build_Debug",
"Build_Development",
],
"windowsSdkVersion": "10.0.22621.0",
"compilerPath": "cl.exe",

View File

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

29
docs/Day 014.md Normal file
View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

View File

@ -9,4 +9,3 @@
#include "generics.h"
#include "math_constants.h"
#include "types.h"

View File

@ -15,7 +15,7 @@
// #include "windows/file.h"
// #include "windows/io.h"
// #ifdef Build_Debug
// #if Build_Debug
// # include "windows/dbghelp.h"
// #endif

View File

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

Binary file not shown.