Day 25 Part 1

I'm splitting this implementation into parts since so much already happened...

I fully updated the code the the latest convention I want to use for the project.
Engine & Game replay should work.
This commit is contained in:
Edward R. Gonzalez 2023-09-30 10:05:37 -04:00
parent 465339743a
commit dc43db117c
13 changed files with 881 additions and 589 deletions

View File

@ -14,22 +14,22 @@
"label": "Static Data" "label": "Static Data"
}, },
{ {
"line": 640, "line": 655,
"column": 0, "column": 0,
"label": "Timing" "label": "Timing"
}, },
{ {
"line": 1471, "line": 1575,
"column": 4, "column": 4,
"label": "Main Loop : Audio Processing" "label": "Main Loop : Audio Processing"
}, },
{ {
"line": 1590, "line": 1694,
"column": 2, "column": 2,
"label": "Main Loop : Timing Update" "label": "Main Loop : Timing Update"
}, },
{ {
"line": 1674, "line": 1778,
"column": 0, "column": 0,
"label": "Main Loop : End" "label": "Main Loop : End"
} }

12
docs/Day 025.md Normal file
View File

@ -0,0 +1,12 @@
# Day 25
Him doing replay save states at the platform layer is causing issues for me...
I'm going to most likely end up doing two categories of save states, one for engine level and one for platform level.
The engine level can just store it in the memory struct, and the game memory can just stay where it is.
I want to use the same "save state" slots for both engine and game since there is no need different memory buckets for that. They will at worst case be ofcourse the size of engine's memory block.
So if there is 4, we are looking at 5x the actual memory size. This is fine for now since the engine block is 2 gigs.
Since engine manages the memory of game and editor (when editor exists), restoring its state will also restore the game and editor state.

View File

@ -8,6 +8,8 @@
#include "dependencies/gen.hpp" #include "dependencies/gen.hpp"
#undef ccast #undef ccast
#undef pcast #undef pcast
#undef rcast
#undef scast
#undef do_once #undef do_once
#undef do_once_start #undef do_once_start
#undef do_once_end #undef do_once_end

View File

@ -5,73 +5,57 @@
NS_ENGINE_BEGIN NS_ENGINE_BEGIN
#define pressed( btn ) (btn.EndedDown && btn.HalfTransitions == 1) #define pressed( btn ) (btn.ended_down && btn.half_transitions > 0)
// Used to determine if analog input is at move threshold // Used to determine if analog input is at move threshold
constexpr f32 analog__move_threshold = 0.5f; constexpr f32 analog__move_threshold = 0.5f;
struct EngineActions struct EngineActions
{ {
b32 move_up = false; b32 move_up;
b32 move_down = false; b32 move_down;
b32 move_left = false; b32 move_left;
b32 move_right = false; b32 move_right;
b32 loop_mode = false; b32 loop_mode_engine;
b32 loop_mode_game;
b32 raise_volume = false; b32 raise_volume;
b32 lower_volume = false; b32 lower_volume;
b32 raise_tone_hz = false; b32 raise_tone_hz;
b32 lower_tone_hz = false; b32 lower_tone_hz;
b32 toggle_wave_tone = false; b32 toggle_wave_tone;
#if Build_Development #if Build_Development
b32 pause_renderer = false; b32 pause_renderer;
#endif #endif
}; };
struct PlayerActions
{
s32 player_x_move_digital = 0;
s32 player_y_move_digital = 0;
f32 player_x_move_analog = 0;
f32 player_y_move_analog = 0;
b32 jump = false;
};
struct EngineState struct EngineState
{ {
s32 WaveToneHz; s32 wave_tone_hz;
s32 ToneVolume; s32 tone_volume;
s32 XOffset; s32 x_offset;
s32 YOffset; s32 y_offset;
b32 RendererPaused; b32 renderer_paused;
f32 SampleWaveSineTime; f32 sample_wave_sine_time;
b32 SampleWaveSwitch; b32 sample_wave_switch;
s32 InputRecordingIndex;
s32 InputPlayingIndex;
platform::File ActiveInputRecordingFile;
platform::File ActivePlaybackFile;
hh::Memory game_memory; hh::Memory game_memory;
}; };
using GetSoundSampleValueFn = s16( EngineState* state, AudioBuffer* sound_buffer ); using GetSoundSampleValueFn = s16( EngineState* state, AudioBuffer* sound_buffer );
internal s16 internal s16
square_wave_sample_value( EngineState* state, AudioBuffer* sound_buffer ) square_wave_sample_value( EngineState* state, AudioBuffer* sound_buffer )
{ {
s32 wave_period = sound_buffer->SamplesPerSecond / state->WaveToneHz; s32 wave_period = sound_buffer->samples_per_second / state->wave_tone_hz;
s32 sample_value = (sound_buffer->RunningSampleIndex / (wave_period / 2) ) % 2 ? s32 sample_value = (sound_buffer->running_sample_index / (wave_period / 2) ) % 2 ?
state->ToneVolume : - state->ToneVolume; state->tone_volume : - state->tone_volume;
return scast(s16, sample_value); return scast(s16, sample_value);
} }
@ -79,13 +63,13 @@ 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 )
{ {
f32& time = state->SampleWaveSineTime; f32& time = state->sample_wave_sine_time;
s32 wave_period = sound_buffer->SamplesPerSecond / state->WaveToneHz; s32 wave_period = sound_buffer->samples_per_second / state->wave_tone_hz;
// time = TAU * (f32)sound_buffer->RunningSampleIndex / (f32)SoundTest_WavePeriod; // time = TAU * (f32)sound_buffer->RunningSampleIndex / (f32)SoundTest_WavePeriod;
f32 sine_value = sinf( time ); f32 sine_value = sinf( time );
s16 sample_value = scast(s16, sine_value * scast(f32, state->ToneVolume)); s16 sample_value = scast(s16, sine_value * scast(f32, state->tone_volume));
time += TAU * 1.0f / scast(f32, wave_period ); time += TAU * 1.0f / scast(f32, wave_period );
if ( time > TAU ) if ( time > TAU )
@ -98,11 +82,11 @@ sine_wave_sample_value( EngineState* state, AudioBuffer* sound_buffer )
internal void internal void
output_sound( EngineState* state, AudioBuffer* sound_buffer, GetSoundSampleValueFn* get_sample_value ) output_sound( EngineState* state, AudioBuffer* sound_buffer, GetSoundSampleValueFn* get_sample_value )
{ {
s16* sample_out = sound_buffer->Samples; s16* sample_out = sound_buffer->samples;
for ( s32 sample_index = 0; sample_index < sound_buffer->NumSamples; ++ sample_index ) for ( s32 sample_index = 0; sample_index < sound_buffer->num_samples; ++ sample_index )
{ {
s16 sample_value = get_sample_value( state, sound_buffer ); s16 sample_value = get_sample_value( state, sound_buffer );
sound_buffer->RunningSampleIndex++; sound_buffer->running_sample_index++;
// char ms_timing_debug[256] {}; // char ms_timing_debug[256] {};
// wsprintfA( ms_timing_debug, "sample_value: %d\n", sample_value ); // wsprintfA( ms_timing_debug, "sample_value: %d\n", sample_value );
@ -128,14 +112,14 @@ render_weird_graident(OffscreenBuffer* buffer, u32 x_offset, u32 y_offset )
u8 Alpha; u8 Alpha;
}; };
u8* row = rcast( u8*, buffer->Memory); u8* row = rcast( u8*, buffer->memory);
local_persist float wildcard = 0; local_persist float wildcard = 0;
for ( u32 y = 0; y < buffer->Height; ++ y ) for ( u32 y = 0; y < buffer->height; ++ y )
{ {
// u8* pixel = rcast(u8*, row); // u8* pixel = rcast(u8*, row);
// Pixel* pixel = rcast( Pixel*, row ); // Pixel* pixel = rcast( Pixel*, row );
u32* pixel = rcast(u32*, row); u32* pixel = rcast(u32*, row);
for ( u32 x = 0; x < buffer->Width; ++ x ) for ( u32 x = 0; x < buffer->width; ++ x )
{ {
/* Pixel in memory: /* Pixel in memory:
----------------------------------------------- -----------------------------------------------
@ -150,25 +134,25 @@ render_weird_graident(OffscreenBuffer* buffer, u32 x_offset, u32 y_offset )
u8 green = scast(u8, y + y_offset - u8(wildcard) % 128); u8 green = scast(u8, y + y_offset - u8(wildcard) % 128);
u8 red = scast(u8, wildcard) % 256 - x * 0.4f; u8 red = scast(u8, wildcard) % 256 - x * 0.4f;
#else #else
u8 red = scast(u8, y + x_offset); u8 red = scast(u8, y + y_offset);
u8 green = scast(u8, x + y_offset); u8 green = scast(u8, x + x_offset);
u8 blue = scast(u8, x + y - x_offset - y_offset); u8 blue = scast(u8, x + y_offset) - scast(u8, y + y_offset);
// blue *= 2; // blue *= 2;
#endif #endif
*pixel++ = u32(red/2 << 16) | u32(green/6 << 8) | blue/2 << 0; *pixel++ = u32(red/2 << 16) | u32(green/6 << 0) | blue/2 << 0;
} }
wildcard += 0.5375f; wildcard += 0.5375f;
row += buffer->Pitch; row += buffer->pitch;
} }
} }
internal void internal void
render_player( OffscreenBuffer* buffer, s32 pos_x, s32 pos_y ) render_player( OffscreenBuffer* buffer, s32 pos_x, s32 pos_y )
{ {
u8* end_of_buffer = rcast(u8*, buffer->Memory) u8* end_of_buffer = rcast(u8*, buffer->memory)
- buffer->BytesPerPixel * buffer->Width - buffer->bytes_per_pixel * buffer->width
+ buffer->Pitch * buffer->Height; + buffer->pitch * buffer->height;
s32 top = pos_y; s32 top = pos_y;
s32 bottom = pos_y + 10; s32 bottom = pos_y + 10;
@ -178,198 +162,286 @@ render_player( OffscreenBuffer* buffer, s32 pos_x, s32 pos_y )
for ( s32 coord_x = pos_x; coord_x < (pos_x+ 10); ++ coord_x ) for ( s32 coord_x = pos_x; coord_x < (pos_x+ 10); ++ coord_x )
{ {
u8* u8*
pixel_byte = rcast(u8*, buffer->Memory); pixel_byte = rcast(u8*, buffer->memory);
pixel_byte += coord_x * buffer->BytesPerPixel; pixel_byte += coord_x * buffer->bytes_per_pixel;
pixel_byte += top * buffer->Pitch; pixel_byte += top * buffer->pitch;
for ( s32 coord_y = top; coord_y < bottom; ++ coord_y ) for ( s32 coord_y = top; coord_y < bottom; ++ coord_y )
{ {
if ( pixel_byte < buffer->Memory || pixel_byte >= end_of_buffer ) if ( pixel_byte < buffer->memory || pixel_byte >= end_of_buffer )
continue; continue;
s32* pixel = rcast(s32*, pixel_byte); s32* pixel = rcast(s32*, pixel_byte);
*pixel = color; *pixel = color;
pixel_byte += buffer->Pitch;
pixel_byte += buffer->pitch;
} }
} }
} }
using SnapshotFn = void ( s32 slot, Memory* memory, platform::ModuleAPI* platform_api );
internal internal
void begin_recording_input( EngineState* state, InputState* input, platform::ModuleAPI* platform_api ) void load_engine_snapshot( s32 slot, Memory* memory, platform::ModuleAPI* platform_api )
{
platform_api->memory_copy( memory->persistent, memory->total_size(), memory->snapshots[ slot ].memory );
}
internal
void load_game_snapshot( s32 slot, Memory* memory, platform::ModuleAPI* platform_api )
{
EngineState* state = rcast( EngineState*, memory->persistent );
void* persistent_slot = memory->snapshots[ slot ].memory;
void* transient_slot = rcast( Byte*, memory->snapshots[ slot ].memory ) + state->game_memory.persistent_size;
platform_api->memory_copy( state->game_memory.persistent, state->game_memory.persistent_size, persistent_slot );
platform_api->memory_copy( state->game_memory.transient, state->game_memory.transient_size, transient_slot );
}
internal
void take_engine_snapshot( s32 slot, Memory* memory, platform::ModuleAPI* platform_api )
{
platform_api->memory_copy( memory->snapshots[ slot ].memory, memory->total_size(), memory->persistent );
}
internal
void take_game_snapshot( s32 slot, Memory* memory, platform::ModuleAPI* platform_api )
{
EngineState* state = rcast( EngineState*, memory->persistent );
void* persistent_slot = memory->snapshots[ slot ].memory;
void* transient_slot = rcast( Byte*, memory->snapshots[ slot ].memory ) + state->game_memory.persistent_size;
platform_api->memory_copy( persistent_slot, state->game_memory.persistent_size, state->game_memory.persistent );
platform_api->memory_copy( transient_slot, state->game_memory.transient_size, state->game_memory.transient );
}
#define Snapshot_New_Way 1
internal
void begin_recording_input( Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{ {
Str file_name = str_ascii("test_input.hmi"); Str file_name = str_ascii("test_input.hmi");
StrPath file_path = {}; StrPath file_path = {};
file_path.concat( platform_api->path_scratch, file_name ); file_path.concat( platform_api->path_scratch, file_name );
state->ActiveInputRecordingFile.Path = file_path; memory->active_recording_file.path = file_path;
state->InputRecordingIndex = 1; memory->input_recording_index = 1;
// TODO(Ed) : If game persist memory is larger than 4 gb, this will need to be done in chunks... #if Snapshot_New_Way
platform_api->file_delete( memory->active_recording_file.path );
#else
platform_api->file_write_content( & state->ActiveInputRecordingFile, scast(u32, state->game_memory.PersistentSize), state->game_memory.Persistent ); platform_api->file_write_content( & state->ActiveInputRecordingFile, scast(u32, state->game_memory.PersistentSize), state->game_memory.Persistent );
#endif
} }
internal internal
void end_recording_input( EngineState* state, InputState* input, platform::ModuleAPI* platform_api ) void end_recording_input( Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{ {
platform_api->file_close( & state->ActiveInputRecordingFile ); memory->input_recording_index = 0;
state->InputRecordingIndex = 0; platform_api->file_close( & memory->active_recording_file );
} }
internal internal
void begin_playback_input( EngineState* state, InputState* input, platform::ModuleAPI* platform_api ) void begin_playback_input( Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{ {
Str file_name = str_ascii("test_input.hmi"); Str file_name = str_ascii("test_input.hmi");
StrPath file_path = {}; StrPath file_path = {};
file_path.concat( platform_api->path_scratch, file_name ); file_path.concat( platform_api->path_scratch, file_name );
if ( platform_api->file_check_exists( file_path ) ) if ( platform_api->file_check_exists( file_path ) )
{ {
state->ActivePlaybackFile.Path = file_path; memory->active_playback_file.path = file_path;
state->InputPlayingIndex = 1; memory->input_playback_index = 1;
} }
#if Snapshot_New_Way
#else
if ( state->ActiveInputRecordingFile.OpaqueHandle == nullptr ) if ( state->ActiveInputRecordingFile.OpaqueHandle == nullptr )
{ {
platform_api->file_read_stream( & state->ActivePlaybackFile, scast(u32, state->game_memory.PersistentSize), state->game_memory.Persistent ); platform_api->file_read_stream( & state->ActivePlaybackFile, scast(u32, state->game_memory.PersistentSize), state->game_memory.Persistent );
} }
#endif
} }
internal internal
void end_playback_input( EngineState* state, InputState* input, platform::ModuleAPI* platform_api ) void end_playback_input( Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{ {
memory->input_playback_index = 0;
#if Snapshot_New_Way
#else
platform_api->file_rewind( & state->ActivePlaybackFile ); platform_api->file_rewind( & state->ActivePlaybackFile );
platform_api->file_read_stream( & state->ActivePlaybackFile, scast(u32, state->game_memory.PersistentSize), state->game_memory.Persistent ); platform_api->file_read_stream( & state->ActivePlaybackFile, scast(u32, state->game_memory.PersistentSize), state->game_memory.Persistent );
platform_api->file_close( & state->ActivePlaybackFile ); #endif
state->InputPlayingIndex = 0; platform_api->file_close( & memory->active_playback_file );
} }
InputStateSnapshot input_state_snapshot( InputState* input ) InputStateSnapshot input_state_snapshot( InputState* input )
{ {
InputStateSnapshot snapshot = {}; InputStateSnapshot snapshot = {};
for ( s32 idx = 0; idx < array_count( snapshot.Controllers ); ++ idx ) for ( s32 idx = 0; idx < array_count( snapshot.controllers ); ++ idx )
{ {
ControllerState* controller = & input->Controllers[idx]; ControllerState* controller = & input->controllers[idx];
if ( controller == nullptr ) if ( controller == nullptr )
continue; continue;
if ( controller->DSPad ) if ( controller->ds_pad )
snapshot.Controllers[idx].DSPad = *controller->DSPad; snapshot.controllers[idx].ds_pad = *controller->ds_pad;
if ( controller->XPad ) if ( controller->xpad )
snapshot.Controllers[idx].XPad = *controller->XPad; snapshot.controllers[idx].xpad = *controller->xpad;
if ( controller->Keyboard ) if ( controller->keyboard )
{ {
snapshot.Controllers[idx].Keyboard = *controller->Keyboard; snapshot.controllers[idx].keyboard = *controller->keyboard;
} }
if ( controller->Mouse ) if ( controller->mouse )
snapshot.Controllers[idx].Mouse = *controller->Mouse; snapshot.controllers[idx].mouse = *controller->mouse;
} }
return snapshot; return snapshot;
} }
internal internal
void record_input( EngineState* state, InputState* input, platform::ModuleAPI* platform_api ) void record_input( Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{ {
InputStateSnapshot snapshot = input_state_snapshot( input ); InputStateSnapshot snapshot = input_state_snapshot( input );
if ( platform_api->file_write_stream( & state->ActiveInputRecordingFile, sizeof(snapshot), &snapshot ) == 0 ) if ( platform_api->file_write_stream( & memory->active_recording_file, sizeof(snapshot), &snapshot ) == 0 )
{ {
// TODO(Ed) : Logging // TODO(Ed) : Logging
} }
} }
internal internal
void play_input( EngineState* state, InputState* input, platform::ModuleAPI* platform_api ) void play_input( SnapshotFn* load_snapshot, Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{ {
InputStateSnapshot new_input; InputStateSnapshot new_input;
if ( platform_api->file_read_stream( & state->ActivePlaybackFile, sizeof(InputStateSnapshot), & new_input ) == 0 ) if ( platform_api->file_read_stream( & memory->active_playback_file, sizeof(InputStateSnapshot), & new_input ) == 0 )
{ {
end_playback_input( state, input, platform_api ); end_playback_input( memory, input, platform_api );
begin_playback_input( state, input, platform_api ); load_snapshot( memory->active_snapshot_slot, memory, platform_api );
begin_playback_input( memory, input, platform_api );
return; return;
} }
for ( s32 idx = 0; idx < array_count( new_input.Controllers ); ++ idx ) for ( s32 idx = 0; idx < array_count( new_input.controllers ); ++ idx )
{ {
ControllerState* controller = & input->Controllers[idx]; ControllerState* controller = & input->controllers[idx];
if ( controller == nullptr ) if ( controller == nullptr )
continue; continue;
if ( controller->DSPad ) if ( controller->ds_pad )
*controller->DSPad = new_input.Controllers[idx].DSPad; *controller->ds_pad = new_input.controllers[idx].ds_pad;
if ( controller->XPad ) if ( controller->xpad )
*controller->XPad = new_input.Controllers[idx].XPad; *controller->xpad = new_input.controllers[idx].xpad;
if ( controller->Keyboard ) if ( controller->keyboard )
{ {
*controller->Keyboard = new_input.Controllers[idx].Keyboard; *controller->keyboard = new_input.controllers[idx].keyboard;
} }
if ( controller->Mouse ) if ( controller->mouse )
*controller->Mouse = new_input.Controllers[idx].Mouse; *controller->mouse = new_input.controllers[idx].mouse;
}
}
void process_loop_mode( SnapshotFn* take_snapshot, SnapshotFn* load_snapshot
, Memory* memory, EngineState* state, InputState* input, platform::ModuleAPI* platform_api )
{
if ( memory->input_recording_index == 0 && memory->input_playback_index == 0 )
{
take_snapshot( 0, memory, platform_api );
memory->active_snapshot_slot = 0;
begin_recording_input( memory, input, platform_api );
}
else if ( memory->input_playback_index )
{
end_playback_input( memory, input, platform_api );
load_snapshot( memory->active_snapshot_slot, memory, platform_api );
}
else if ( memory->input_recording_index )
{
end_recording_input( memory, input, platform_api );
load_snapshot( memory->active_snapshot_slot, memory, platform_api );
begin_playback_input( memory, input, platform_api );
} }
} }
internal internal
void input_poll_engine_actions( InputState* input, EngineActions* actions ) void input_poll_engine_actions( InputState* input, EngineActions* actions )
{ {
ControllerState* controller = & input->Controllers[0]; ControllerState* controller = & input->controllers[0];
KeyboardState* keyboard = controller->Keyboard; KeyboardState* keyboard = controller->keyboard;
actions->move_right |= keyboard->D.EndedDown; // actions->move_right |= keyboard->D.EndedDown;
actions->move_left |= keyboard->A.EndedDown; // actions->move_left |= keyboard->A.EndedDown;
actions->move_up |= keyboard->W.EndedDown; // actions->move_up |= keyboard->W.EndedDown;
actions->move_down |= keyboard->S.EndedDown; // actions->move_down |= keyboard->S.EndedDown;
actions->raise_volume |= keyboard->Up.EndedDown; actions->raise_volume |= keyboard->up.ended_down;
actions->lower_volume |= keyboard->Down.EndedDown; actions->lower_volume |= keyboard->down.ended_down;
actions->raise_tone_hz |= keyboard->Right.EndedDown; actions->raise_tone_hz |= keyboard->right.ended_down;
actions->lower_tone_hz |= keyboard->Left.EndedDown; actions->lower_tone_hz |= keyboard->left.ended_down;
#if Build_Development #if Build_Development
actions->pause_renderer |= pressed( keyboard->Pause ); actions->pause_renderer |= pressed( keyboard->pause );
#endif #endif
actions->toggle_wave_tone |= pressed( keyboard->Q ); actions->toggle_wave_tone |= pressed( keyboard->Q );
actions->loop_mode |= pressed( keyboard->L ); actions->loop_mode_game |= pressed( keyboard->L ) && ! keyboard->right_shift.ended_down;
actions->loop_mode_engine |= pressed( keyboard->L ) && keyboard->right_shift.ended_down;
MousesState* mouse = controller->mouse;
actions->move_right = (mouse->horizontal_wheel.end > 0.f) * 20;
actions->move_left = (mouse->horizontal_wheel.end < 0.f) * 20;
actions->move_up = (mouse->vertical_wheel.end > 0.f) * 10;
actions->move_down = (mouse->vertical_wheel.end < 0.f) * 10;
} }
internal internal
void input_poll_player_actions( InputState* input, PlayerActions* actions ) void input_poll_player_actions( InputState* input, hh::PlayerActions* actions )
{ {
ControllerState* controller = & input->Controllers[0]; ControllerState* controller = & input->controllers[0];
if ( controller->DSPad ) if ( controller->ds_pad )
{ {
DualsensePadState* pad = controller->DSPad; DualsensePadState* pad = controller->ds_pad;
actions->jump |= pressed( pad->X ); actions->jump |= pressed( pad->cross );
actions->player_x_move_analog += pad->Stick.Left.X.End; actions->player_x_move_analog += pad->stick.left.X.end;
actions->player_y_move_analog += pad->Stick.Left.Y.End; actions->player_y_move_analog += pad->stick.left.Y.end;
} }
if ( controller->XPad ) if ( controller->xpad )
{ {
XInputPadState* pad = controller->XPad; XInputPadState* pad = controller->xpad;
actions->jump |= pressed( pad->A ); actions->jump |= pressed( pad->A );
actions->player_x_move_analog += pad->Stick.Left.X.End; actions->player_x_move_analog += pad->stick.left.X.end;
actions->player_y_move_analog += pad->Stick.Left.Y.End; actions->player_y_move_analog += pad->stick.left.Y.end;
} }
if ( controller->Keyboard ) if ( controller->keyboard )
{ {
KeyboardState* keyboard = controller->Keyboard; KeyboardState* keyboard = controller->keyboard;
actions->jump |= pressed( keyboard->Space ); actions->jump |= pressed( keyboard->space );
actions->player_x_move_digital += keyboard->D.EndedDown - keyboard->A.EndedDown; actions->player_x_move_digital += keyboard->D.ended_down - keyboard->A.ended_down;
actions->player_y_move_digital += keyboard->W.EndedDown - keyboard->S.EndedDown; actions->player_y_move_digital += keyboard->W.ended_down - keyboard->S.ended_down;
}
if ( controller->mouse )
{
MousesState* mouse = controller->mouse;
} }
} }
@ -382,37 +454,44 @@ void on_module_reload( Memory* memory, platform::ModuleAPI* platfom_api )
Engine_API Engine_API
void startup( Memory* memory, platform::ModuleAPI* platform_api ) void startup( Memory* memory, platform::ModuleAPI* platform_api )
{ {
EngineState* state = rcast( EngineState*, memory->Persistent ); memory->active_snapshot_slot = -1;
assert( sizeof(EngineState) <= memory->PersistentSize ); memory->input_recording_index = 0;
memory->input_playback_index = 0;
memory->active_recording_file = {};
memory->active_playback_file = {};
memory->engine_loop_active = false;
memory->game_loop_active = false;
state->ToneVolume = 1000; for ( s32 slot = 0; slot < memory->Num_Snapshot_Slots; ++ slot )
{
// TODO(Ed) : Specify default file paths for saving slots ?
}
state->XOffset = 0; EngineState* state = rcast( EngineState*, memory->persistent );
state->YOffset = 0; assert( sizeof(EngineState) <= memory->persistent_size );
state->SampleWaveSwitch = false; state->tone_volume = 1000;
state->WaveToneHz = 60;
state->SampleWaveSineTime = 0.f;
state->RendererPaused = false; state->x_offset = 0;
state->y_offset = 0;
state->InputRecordingIndex = 0; state->sample_wave_switch = false;
state->InputPlayingIndex = 0; state->wave_tone_hz = 60;
state->sample_wave_sine_time = 0.f;
state->ActiveInputRecordingFile = {}; state->renderer_paused = false;
state->ActivePlaybackFile = {}; state->game_memory.persistent_size = memory->persistent_size / 2;
state->game_memory.persistent = rcast(Byte*, memory->persistent) + state->game_memory.persistent_size;
state->game_memory.transient_size = memory->transient_size / 2;
state->game_memory.transient = rcast(Byte*, memory->transient) + state->game_memory.transient_size;
state->game_memory.PersistentSize = memory->PersistentSize / 2; hh::PlayerState* player = rcast( hh::PlayerState*, state->game_memory.persistent );
state->game_memory.Persistent = rcast(Byte*, memory->Persistent) + state->game_memory.PersistentSize; assert( sizeof(hh::PlayerState) <= state->game_memory.persistent_size );
state->game_memory.TransientSize = memory->TransientSize / 2;
state->game_memory.Transient = rcast(Byte*, memory->Transient) + state->game_memory.TransientSize;
hh::PlayerState* player = rcast( hh::PlayerState*, state->game_memory.Persistent ); player->pos_x = 100;
assert( sizeof(hh::PlayerState) <= state->game_memory.PersistentSize ); player->pos_y = 100;
player->mid_jump = false;
player->Pos_X = 100; player->jump_time = 0.f;
player->Pos_Y = 100;
player->MidJump = false;
} }
Engine_API Engine_API
@ -422,137 +501,169 @@ void shutdown( Memory* memory, platform::ModuleAPI* platform_api )
Engine_API Engine_API
// TODO : I rather expose the back_buffer and sound_buffer using getters for access in any function. // 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 ) void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* platform_api, ThreadContext* thread )
{ {
EngineState* state = rcast( EngineState*, memory->Persistent ); EngineState* state = rcast( EngineState*, memory->persistent );
assert( sizeof(EngineState) <= memory->PersistentSize ); assert( sizeof(EngineState) <= memory->persistent_size );
ControllerState* controller = & input->Controllers[0]; ControllerState* controller = & input->controllers[0];
EngineActions engine_actions {}; EngineActions engine_actions {};
PlayerActions player_actions {}; hh::PlayerActions player_actions {};
input_poll_engine_actions( input, & engine_actions ); input_poll_engine_actions( input, & engine_actions );
// Ease of use: Allow user to press L key without shift if engine loop recording is active.
engine_actions.loop_mode_engine |= engine_actions.loop_mode_game && memory->engine_loop_active;
if ( engine_actions.loop_mode_engine && ! memory->game_loop_active )
{ {
state->XOffset += 3 * engine_actions.move_right; process_loop_mode( & take_engine_snapshot, & load_engine_snapshot, memory, state, input, platform_api );
state->XOffset -= 3 * engine_actions.move_left; memory->engine_loop_active = memory->input_playback_index || memory->input_recording_index;
state->YOffset += 3 * engine_actions.move_down; }
state->YOffset -= 3 * engine_actions.move_up;
// Input recording and playback for engine state
if ( memory->engine_loop_active )
{
if ( memory->input_recording_index )
{
record_input( memory, input, platform_api );
}
if ( memory->input_playback_index )
{
play_input( & load_engine_snapshot, memory, input, platform_api );
}
}
// Process Engine Actions
{
state->x_offset += 3 * engine_actions.move_right;
state->x_offset -= 3 * engine_actions.move_left;
state->y_offset += 3 * engine_actions.move_down;
state->y_offset -= 3 * engine_actions.move_up;
if ( engine_actions.raise_volume ) if ( engine_actions.raise_volume )
{ {
state->ToneVolume += 10; state->tone_volume += 10;
} }
if ( engine_actions.lower_volume ) if ( engine_actions.lower_volume )
{ {
state->ToneVolume -= 10; state->tone_volume -= 10;
if ( state->ToneVolume <= 0 ) if ( state->tone_volume <= 0 )
state->ToneVolume = 0; state->tone_volume = 0;
} }
if ( engine_actions.raise_tone_hz ) if ( engine_actions.raise_tone_hz )
{ {
state->WaveToneHz += 1; state->wave_tone_hz += 1;
} }
if ( engine_actions.lower_tone_hz ) if ( engine_actions.lower_tone_hz )
{ {
state->WaveToneHz -= 1; state->wave_tone_hz -= 1;
if ( state->WaveToneHz <= 0 ) if ( state->wave_tone_hz <= 0 )
state->WaveToneHz = 1; state->wave_tone_hz = 1;
} }
if ( engine_actions.toggle_wave_tone ) if ( engine_actions.toggle_wave_tone )
{ {
state->SampleWaveSwitch ^= true; state->sample_wave_switch ^= true;
} }
if ( engine_actions.loop_mode ) if ( engine_actions.loop_mode_game && ! memory->engine_loop_active )
{ {
if ( state->InputRecordingIndex == 0 && state->InputPlayingIndex == 0 ) process_loop_mode( & take_game_snapshot, & load_game_snapshot, memory, state, input, platform_api );
{ memory->game_loop_active = memory->input_playback_index || memory->input_recording_index;
begin_recording_input( state, input, platform_api );
}
else if ( state->InputPlayingIndex )
{
end_playback_input( state, input, platform_api );
}
else if ( state->InputRecordingIndex )
{
end_recording_input( state, input, platform_api );
begin_playback_input( state, input, platform_api );
}
} }
#if Build_Development #if Build_Development
if ( engine_actions.pause_renderer ) if ( engine_actions.pause_renderer )
{ {
if ( state->RendererPaused ) if ( state->renderer_paused )
{ {
platform_api->debug_set_pause_rendering(false); platform_api->debug_set_pause_rendering(false);
state->RendererPaused = false; state->renderer_paused = false;
} }
else else
{ {
platform_api->debug_set_pause_rendering(true); platform_api->debug_set_pause_rendering(true);
state->RendererPaused = true; state->renderer_paused = true;
} }
} }
#endif #endif
} }
if ( state->InputRecordingIndex ) if ( ! memory->engine_loop_active )
{ {
record_input( state, input, platform_api ); // Input recording and playback for game state
} if ( memory->input_recording_index )
if ( state->InputPlayingIndex ) {
{ record_input( memory, input, platform_api );
play_input( state, input, platform_api ); }
if ( memory->input_playback_index )
{
play_input( & load_game_snapshot, memory, input, platform_api );
}
} }
hh::PlayerState* player = rcast( hh::PlayerState*, state->game_memory.Persistent ); hh::PlayerState* player = rcast( hh::PlayerState*, state->game_memory.persistent );
assert( sizeof(hh::PlayerState) <= state->game_memory.PersistentSize ); assert( sizeof(hh::PlayerState) <= state->game_memory.persistent_size );
input_poll_player_actions( input, & player_actions ); input_poll_player_actions( input, & player_actions );
{ {
player->Pos_X += player_actions.player_x_move_digital * 5; player->pos_x += player_actions.player_x_move_digital * 5;
player->Pos_Y -= player_actions.player_y_move_digital * 5; player->pos_y -= player_actions.player_y_move_digital * 5;
player->Pos_X += scast(u32, player_actions.player_x_move_analog * 5); player->pos_x += scast(u32, player_actions.player_x_move_analog * 5);
player->Pos_Y -= scast(u32, player_actions.player_y_move_analog * 5) - scast(u32, sinf( player->JumpTime * TAU ) * 10); player->pos_y -= scast(u32, player_actions.player_y_move_analog * 5) - scast(u32, sinf( player->jump_time * TAU ) * 10);
if ( player->JumpTime > 0.f ) if ( player->jump_time > 0.f )
{ {
player->JumpTime -= 0.025f; player->jump_time -= 0.025f;
} }
else else
{ {
player->JumpTime = 0.f; player->jump_time = 0.f;
player->MidJump = false; player->mid_jump = false;
} }
if ( ! player->MidJump && player_actions.jump ) if ( ! player->mid_jump && player_actions.jump )
{ {
player->JumpTime = 1.f; player->jump_time = 1.f;
player->MidJump = true; player->mid_jump = true;
} }
} }
render_weird_graident( back_buffer, 0, 0 ); render_weird_graident( back_buffer, state->x_offset, state->y_offset );
render_player( back_buffer, player->Pos_X, player->Pos_Y ); render_player( back_buffer, player->pos_x, player->pos_y );
if ( state->InputRecordingIndex ) if ( memory->input_recording_index )
render_player( back_buffer, player->Pos_X + 20, player->Pos_Y - 20 ); render_player( back_buffer, player->pos_x + 20, player->pos_y - 20 );
render_player( back_buffer, (s32)input->controllers[0].mouse->X.end, (s32)input->controllers[0].mouse->Y.end );
// Mouse buttons test
{
if ( input->controllers[0].mouse->left.ended_down == true )
render_player( back_buffer, 5, 5 );
if ( input->controllers[0].mouse->middle.ended_down == true )
render_player( back_buffer, 5, 20 );
if ( input->controllers[0].mouse->right.ended_down == true )
render_player( back_buffer, 5, 35 );
}
} }
Engine_API Engine_API
void update_audio( AudioBuffer* audio_buffer, Memory* memory, platform::ModuleAPI* platform_api ) void update_audio( AudioBuffer* audio_buffer, Memory* memory, platform::ModuleAPI* platform_api, ThreadContext* thread )
{ {
EngineState* state = rcast( EngineState*, memory->Persistent ); EngineState* state = rcast( EngineState*, memory->persistent );
do_once_start do_once_start
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->SampleWaveSwitch ) if ( ! state->sample_wave_switch )
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 );

View File

@ -14,7 +14,18 @@ NS_ENGINE_BEGIN
struct Clocks struct Clocks
{ {
// TODO(Ed) : Clock values... // TODO(Ed) : Clock values...
f32 SecondsElapsed; f32 seconds_elapsed;
};
struct ThreadContext
{
u32 placeholder;
};
struct MemorySnapshot
{
Str file_path;
void* memory;
}; };
struct Memory struct Memory
@ -22,51 +33,75 @@ struct Memory
// All memory for the engine is required to be zero initialized. // All memory for the engine is required to be zero initialized.
// Wiped on shutdown // Wiped on shutdown
void* Persistent; void* persistent;
u64 PersistentSize; u64 persistent_size;
// Wiped on a per-frame basis // Wiped on a per-frame basis
// void* Frame; // void* Frame;
// u64 FrameSize; // u64 FrameSize;
// Wiped whenever the engine wants to? // Wiped whenever the engine wants to?
void* Transient; void* transient;
u64 TransientSize; u64 transient_size;
// TODO(Ed) : Move this crap to state & replay archive definitions?
static constexpr
s32 Num_Snapshot_Slots = 4;
// Abuse RAM to store snapshots of the Engine or Game state.
MemorySnapshot snapshots[ Num_Snapshot_Slots ];
s32 active_snapshot_slot;
// Recording and playback info is the same for either engine or game.
s32 input_recording_index;
s32 input_playback_index;
platform::File active_recording_file;
platform::File active_playback_file;
// Engine-wide recording & playback loop.
s32 engine_loop_active;
s32 game_loop_active;
u64 total_size()
{
return persistent_size + transient_size;
}
}; };
struct OffscreenBuffer struct OffscreenBuffer
{ {
void* Memory; // Lets use directly mess with the "pixel's memory buffer" void* memory; // Lets use directly mess with the "pixel's memory buffer"
u32 Width; u32 width;
u32 Height; u32 height;
u32 Pitch; u32 pitch;
u32 BytesPerPixel; u32 bytes_per_pixel;
}; };
// TODO : Will be gutting this once we have other stuff lifted. // TODO : Will be gutting this once we have other stuff lifted.
struct AudioBuffer struct AudioBuffer
{ {
s16* Samples; s16* samples;
u32 RunningSampleIndex; u32 running_sample_index;
s32 SamplesPerSecond; s32 samples_per_second;
s32 NumSamples; s32 num_samples;
}; };
struct DigitalBtn struct DigitalBtn
{ {
s32 HalfTransitions; s32 half_transitions;
b32 EndedDown; b32 ended_down;
}; };
struct AnalogAxis struct AnalogAxis
{ {
f32 Start; f32 start;
f32 End; f32 end;
f32 Min; f32 min;
f32 Max; f32 max;
// Platform doesn't provide this, we process in the engine layer. // Platform doesn't provide this, we process in the engine layer.
f32 Average; f32 average;
}; };
struct AnalogStick struct AnalogStick
@ -77,62 +112,70 @@ struct AnalogStick
union KeyboardState union KeyboardState
{ {
DigitalBtn Keys[12]; DigitalBtn keys[12];
struct { struct {
DigitalBtn Row_1; DigitalBtn row_1;
DigitalBtn Q; DigitalBtn Q;
DigitalBtn E; DigitalBtn E;
DigitalBtn W; DigitalBtn W;
DigitalBtn A; DigitalBtn A;
DigitalBtn S; DigitalBtn S;
DigitalBtn D; DigitalBtn D;
DigitalBtn K;
DigitalBtn L; DigitalBtn L;
DigitalBtn Escape; DigitalBtn escape;
DigitalBtn Backspace; DigitalBtn backspace;
DigitalBtn Up; DigitalBtn up;
DigitalBtn Down; DigitalBtn down;
DigitalBtn Left; DigitalBtn left;
DigitalBtn Right; DigitalBtn right;
DigitalBtn Space; DigitalBtn space;
DigitalBtn Pause; DigitalBtn pause;
DigitalBtn right_shift;
DigitalBtn left_shift;
}; };
}; };
struct MousesState struct MousesState
{ {
DigitalBtn Left; DigitalBtn left;
DigitalBtn Middle; DigitalBtn middle;
DigitalBtn Right; DigitalBtn right;
AnalogAxis X;
AnalogAxis Y;
AnalogAxis vertical_wheel;
AnalogAxis horizontal_wheel;
}; };
struct XInputPadState struct XInputPadState
{ {
struct struct
{ {
AnalogStick Left; AnalogStick left;
AnalogStick Right; AnalogStick right;
} Stick; } stick;
AnalogAxis LeftTrigger; AnalogAxis left_trigger;
AnalogAxis RightTrigger; AnalogAxis right_trigger;
union { union {
DigitalBtn Btns[14]; DigitalBtn btns[14];
struct { struct {
struct { struct {
DigitalBtn Up; DigitalBtn up;
DigitalBtn Down; DigitalBtn down;
DigitalBtn Left; DigitalBtn left;
DigitalBtn Right; DigitalBtn right;
} DPad; } dpad;
DigitalBtn A; DigitalBtn A;
DigitalBtn B; DigitalBtn B;
DigitalBtn X; DigitalBtn X;
DigitalBtn Y; DigitalBtn Y;
DigitalBtn Back; DigitalBtn back;
DigitalBtn Start; DigitalBtn start;
DigitalBtn LeftShoulder; DigitalBtn left_shoulder;
DigitalBtn RightShoulder; DigitalBtn right_shoulder;
}; };
}; };
}; };
@ -141,28 +184,28 @@ struct DualsensePadState
{ {
struct struct
{ {
AnalogStick Left; AnalogStick left;
AnalogStick Right; AnalogStick right;
} Stick; } stick;
AnalogAxis L2; AnalogAxis L2;
AnalogAxis R2; AnalogAxis R2;
union { union {
DigitalBtn Btns[14]; DigitalBtn btns[14];
struct { struct {
struct { struct {
DigitalBtn Up; DigitalBtn up;
DigitalBtn Down; DigitalBtn down;
DigitalBtn Left; DigitalBtn left;
DigitalBtn Right; DigitalBtn right;
} DPad; } dpad;
DigitalBtn X; DigitalBtn cross;
DigitalBtn Circle; DigitalBtn circle;
DigitalBtn Square; DigitalBtn square;
DigitalBtn Triangle; DigitalBtn triangle;
DigitalBtn Share; DigitalBtn share;
DigitalBtn Options; DigitalBtn options;
DigitalBtn L1; DigitalBtn L1;
DigitalBtn R1; DigitalBtn R1;
}; };
@ -171,39 +214,39 @@ struct DualsensePadState
struct ControllerState struct ControllerState
{ {
KeyboardState* Keyboard; KeyboardState* keyboard;
MousesState* Mouse; MousesState* mouse;
XInputPadState* XPad; XInputPadState* xpad;
DualsensePadState* DSPad; DualsensePadState* ds_pad;
}; };
struct ControllerStateSnapshot struct ControllerStateSnapshot
{ {
KeyboardState Keyboard; KeyboardState keyboard;
MousesState Mouse; MousesState mouse;
XInputPadState XPad; XInputPadState xpad;
DualsensePadState DSPad; DualsensePadState ds_pad;
}; };
struct InputState struct InputState
{ {
ControllerState Controllers[4]; ControllerState controllers[4];
}; };
struct InputStateSnapshot struct InputStateSnapshot
{ {
ControllerStateSnapshot Controllers[4]; ControllerStateSnapshot controllers[4];
}; };
using InputBindCallback = void( void* ); using InputBindCallback = void( void* );
using InputBindCallback_DigitalBtn = void( engine::DigitalBtn* Button ); using InputBindCallback_DigitalBtn = void( engine::DigitalBtn* button );
using InputBindCallback_AnalogAxis = void( engine::AnalogAxis* Axis ); using InputBindCallback_AnalogAxis = void( engine::AnalogAxis* axis );
using InputBindCallback_AnalogStick = void( engine::AnalogStick* Stick ); using InputBindCallback_AnalogStick = void( engine::AnalogStick* stick );
struct InputMode struct InputMode
{ {
InputBindCallback* Binds; InputBindCallback* binds;
s32 NumBinds; s32 num_binds;
}; };
void input_mode_pop( InputMode* mode ); void input_mode_pop( InputMode* mode );
@ -212,8 +255,8 @@ void input_mode_pop( InputMode* mode );
#if 0 #if 0
struct RecordedInput struct RecordedInput
{ {
s32 Num; s32 num;
InputState* Stream; InputState* stream;
}; };
#endif #endif

View File

@ -16,12 +16,12 @@ 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
using UpdateAndRenderFn = void ( InputState* input, OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* platform_api ); using UpdateAndRenderFn = void ( InputState* input, OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* platform_api, ThreadContext* thread );
// 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.
using UpdateAudioFn = void ( AudioBuffer* audio_buffer, Memory* memory, platform::ModuleAPI* platform_api ); using UpdateAudioFn = void ( AudioBuffer* audio_buffer, Memory* memory, platform::ModuleAPI* platform_api, ThreadContext* thread );
struct ModuleAPI struct ModuleAPI
{ {

View File

@ -10,8 +10,8 @@ Str const symbol_startup = str_ascii("?startup@engine@@YAXPEAUMemory@1@PEAUModu
constexpr constexpr
Str const symbol_shutdown = str_ascii("?shutdown@engine@@YAXPEAUMemory@1@PEAUModuleAPI@platform@@@Z"); Str const symbol_shutdown = str_ascii("?shutdown@engine@@YAXPEAUMemory@1@PEAUModuleAPI@platform@@@Z");
constexpr constexpr
Str const symbol_update_and_render = str_ascii("?update_and_render@engine@@YAXPEAUInputState@1@PEAUOffscreenBuffer@1@PEAUMemory@1@PEAUModuleAPI@platform@@@Z"); Str const symbol_update_and_render = str_ascii("?update_and_render@engine@@YAXPEAUInputState@1@PEAUOffscreenBuffer@1@PEAUMemory@1@PEAUModuleAPI@platform@@PEAUThreadContext@1@@Z");
constexpr constexpr
Str const symbol_update_audio = str_ascii("?update_audio@engine@@YAXPEAUAudioBuffer@1@PEAUMemory@1@PEAUModuleAPI@platform@@@Z"); Str const symbol_update_audio = str_ascii("?update_audio@engine@@YAXPEAUAudioBuffer@1@PEAUMemory@1@PEAUModuleAPI@platform@@PEAUThreadContext@1@@Z");
NS_ENGINE_END NS_ENGINE_END

View File

@ -11,22 +11,27 @@ struct Memory
{ {
// Subscection of engine memory for the game to use. // Subscection of engine memory for the game to use.
void* Persistent; void* persistent;
u64 PersistentSize; u64 persistent_size;
// void* Frame; // void* Frame;
// u64 FrameSize; // u64 FrameSize;
void* Transient; void* transient;
u64 TransientSize; u64 transient_size;
u64 total_size()
{
return persistent_size + transient_size;
}
}; };
// We want a 'binding' to have multiple binds to active it (most likely) // We want a 'binding' to have multiple binds to active it (most likely)
struct Actionable struct Actionable
{ {
char const* Name; char const* name;
engine::InputBindCallback* Binds; engine::InputBindCallback* binds;
s32 NumBinds; s32 num_binds;
}; };
struct ActionableMode struct ActionableMode
@ -58,18 +63,28 @@ struct ActionableMode
struct Player struct Player
{ {
// So far just has an assigned controller. // So far just has an assigned controller.
engine::ControllerState* Controller; engine::ControllerState* controller;
// Possilby some other stuff in the future. // Possilby some other stuff in the future.
}; };
struct PlayerState struct PlayerState
{ {
s32 Pos_X; s32 pos_x;
s32 Pos_Y; s32 pos_y;
b32 MidJump; b32 mid_jump;
f32 JumpTime; f32 jump_time;
};
struct PlayerActions
{
s32 player_x_move_digital;
s32 player_y_move_digital;
f32 player_x_move_analog;
f32 player_y_move_analog;
b32 jump = false;
}; };
NS_HANDMADE_END NS_HANDMADE_END

View File

@ -11,6 +11,7 @@
#pragma warning( disable: 4820 ) // Support auto-adding padding to structs #pragma warning( disable: 4820 ) // Support auto-adding padding to structs
#pragma warning( disable: 4711 ) // Support automatic inline expansion #pragma warning( disable: 4711 ) // Support automatic inline expansion
#pragma warning( disable: 4710 ) // Support automatic inline expansion #pragma warning( disable: 4710 ) // Support automatic inline expansion
#pragma warning( disable: 4805 ) // Support comparisons of s32 to bool.
#endif #endif
#ifdef __clang__ #ifdef __clang__

View File

@ -10,19 +10,19 @@
// Casting // Casting
#define ccast( Type, Value ) ( const_cast< Type >( (Value) ) ) #define ccast( type, value ) ( const_cast< type >( (value) ) )
#define pcast( Type, Value ) ( * reinterpret_cast< Type* >( & ( Value ) ) ) #define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) )
#define rcast( Type, Value ) reinterpret_cast< Type >( Value ) #define rcast( type, value ) reinterpret_cast< type >( value )
#define scast( Type, Value ) static_cast< Type >( Value ) #define scast( type, value ) static_cast< type >( value )
#define do_once() \ #define do_once() \
do \ do \
{ \ { \
local_persist \ local_persist \
bool Done = false; \ bool done = false; \
if ( Done ) \ if ( done ) \
return; \ return; \
Done = true; \ done = true; \
} \ } \
while(0) while(0)
@ -30,10 +30,10 @@
do \ do \
{ \ { \
local_persist \ local_persist \
bool Done = false; \ bool done = false; \
if ( Done ) \ if ( done ) \
break; \ break; \
Done = true; done = true;
#define do_once_end \ #define do_once_end \
} \ } \

View File

@ -34,10 +34,10 @@ using DebugSetPauseRenderingFn = void (b32 value);
struct File struct File
{ {
void* OpaqueHandle; void* opaque_handle;
Str Path; Str path;
void* Data; void* data;
u32 Size; u32 size;
}; };
#pragma region Settings Exposure #pragma region Settings Exposure
@ -57,7 +57,7 @@ using SetEngineFrameTargetFn = void ( u32 rate_in_hz );
struct BinaryModule struct BinaryModule
{ {
void* OpaqueHandle; void* opaque_handle;
}; };
using LoadBinaryModuleFn = BinaryModule ( char const* module_path ); using LoadBinaryModuleFn = BinaryModule ( char const* module_path );
@ -78,6 +78,8 @@ using FileWriteContentFn = u32 ( File* file, u32 content_size, void* content_mem
using FileWriteStreamFn = u32 ( File* file, u32 content_size, void* content_memory ); using FileWriteStreamFn = u32 ( File* file, u32 content_size, void* content_memory );
using FileRewindFn = void ( File* file ); using FileRewindFn = void ( File* file );
using MemoryCopyFn = void( void* dest, u64 src_size, void* src );
struct ModuleAPI struct ModuleAPI
{ {
Str path_root; Str path_root;
@ -106,6 +108,8 @@ struct ModuleAPI
FileRewindFn* file_rewind; // Rewinds the file stream to the beginning FileRewindFn* file_rewind; // Rewinds the file stream to the beginning
FileWriteContentFn* file_write_content; // Writes content to file (overwrites) FileWriteContentFn* file_write_content; // Writes content to file (overwrites)
FileWriteStreamFn* file_write_stream; // Appends content to file FileWriteStreamFn* file_write_stream; // Appends content to file
MemoryCopyFn* memory_copy;
}; };
#pragma endregion Settings Exposure #pragma endregion Settings Exposure

View File

@ -12,32 +12,32 @@ u32 str_length( char const* str );
// Length tracked raw strings. // Length tracked raw strings.
struct Str struct Str
{ {
u32 Len; u32 len;
char* Data; char* ptr;
void append( u32 src_len, char const* src ) { void append( u32 src_len, char const* src ) {
str_append( Len, Data, src_len, src ); str_append( len, ptr, src_len, src );
} }
void append( Str const src ) { void append( Str const src ) {
str_append( Len, Data, src.Len, src.Data ); str_append( len, ptr, src.len, src.ptr );
} }
void concat( u32 dest_size, Str* dest, Str const str_a, Str const str_b ) void concat( u32 dest_size, Str* dest, Str const str_a, Str const str_b )
{ {
str_concat( dest_size, dest->Data str_concat( dest_size, dest->ptr
, str_a.Len, str_a.Data , str_a.len, str_a.ptr
, str_b.Len, str_b.Data ); , str_b.len, str_b.ptr );
dest->Len = str_a.Len + str_b.Len; dest->len = str_a.len + str_b.len;
} }
operator char*() const { operator char*() const {
return Data; return ptr;
} }
char& operator []( u32 idx ) { char& operator []( u32 idx ) {
return Data[idx]; return ptr[idx];
} }
char const& operator []( u32 idx ) const { char const& operator []( u32 idx ) const {
return Data[idx]; return ptr[idx];
} }
}; };
@ -47,35 +47,35 @@ struct StrFixed
{ {
constexpr static u32 Capacity = capacity; constexpr static u32 Capacity = capacity;
u32 Len; u32 len;
char Data[capacity]; char ptr[capacity];
void append( u32 src_len, char const* src ) { void append( u32 src_len, char const* src ) {
str_append( Len, Data, src_len, src ); str_append( len, data, src_len, src );
} }
void append( Str const src ) { void append( Str const src ) {
str_append( Len, Data, src.Len, src.Data ); str_append( len, data, src.Len, src.data );
} }
void concat( Str const str_a, Str const str_b ) void concat( Str const str_a, Str const str_b )
{ {
str_concat( Capacity, Data str_concat( Capacity, ptr
, str_a.Len, str_a.Data , str_a.len, str_a.ptr
, str_b.Len, str_b.Data ); , str_b.len, str_b.ptr );
Len = str_a.Len + str_b.Len; len = str_a.len + str_b.len;
} }
operator char*() { return Data;} operator char*() { return ptr;}
operator char const*() { return Data; } operator char const*() { return ptr; }
operator Str() { return { Len, Data }; } operator Str() { return { len, ptr }; }
operator Str const() const { return { Len, Data }; } operator Str const() const { return { len, ptr }; }
char& operator []( u32 idx ) { char& operator []( u32 idx ) {
assert( idx < Capacity ); assert( idx < Capacity );
return Data[idx]; return ptr[idx];
} }
char const& operator []( u32 idx ) const { char const& operator []( u32 idx ) const {
assert( idx < Capacity ); assert( idx < Capacity );
return Data[idx]; return ptr[idx];
} }
}; };

File diff suppressed because it is too large Load Diff