mirror of
https://github.com/Ed94/HandmadeHero.git
synced 2024-12-22 06:14:45 -08:00
Day 14 complete
This commit is contained in:
parent
abe3066071
commit
3de4178fff
1
.vscode/c_cpp_properties.json
vendored
1
.vscode/c_cpp_properties.json
vendored
@ -13,6 +13,7 @@
|
||||
"_UNICODE",
|
||||
"GEN_TIME",
|
||||
"Build_Debug",
|
||||
"Build_Development",
|
||||
],
|
||||
"windowsSdkVersion": "10.0.22621.0",
|
||||
"compilerPath": "cl.exe",
|
||||
|
@ -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
29
docs/Day 014.md
Normal 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.
@ -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 );
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
0
project/platform/memory.h
Normal file
0
project/platform/memory.h
Normal file
@ -9,4 +9,3 @@
|
||||
#include "generics.h"
|
||||
#include "math_constants.h"
|
||||
#include "types.h"
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
// #include "windows/file.h"
|
||||
// #include "windows/io.h"
|
||||
|
||||
// #ifdef Build_Debug
|
||||
// #if Build_Debug
|
||||
// # include "windows/dbghelp.h"
|
||||
// #endif
|
||||
|
||||
|
@ -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.
Loading…
Reference in New Issue
Block a user