mirror of
https://github.com/Ed94/HandmadeHero.git
synced 2024-12-21 22:14:43 -08:00
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:
parent
465339743a
commit
dc43db117c
8
.vscode/bookmarks.json
vendored
8
.vscode/bookmarks.json
vendored
@ -14,22 +14,22 @@
|
||||
"label": "Static Data"
|
||||
},
|
||||
{
|
||||
"line": 640,
|
||||
"line": 655,
|
||||
"column": 0,
|
||||
"label": "Timing"
|
||||
},
|
||||
{
|
||||
"line": 1471,
|
||||
"line": 1575,
|
||||
"column": 4,
|
||||
"label": "Main Loop : Audio Processing"
|
||||
},
|
||||
{
|
||||
"line": 1590,
|
||||
"line": 1694,
|
||||
"column": 2,
|
||||
"label": "Main Loop : Timing Update"
|
||||
},
|
||||
{
|
||||
"line": 1674,
|
||||
"line": 1778,
|
||||
"column": 0,
|
||||
"label": "Main Loop : End"
|
||||
}
|
||||
|
12
docs/Day 025.md
Normal file
12
docs/Day 025.md
Normal 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.
|
@ -8,6 +8,8 @@
|
||||
#include "dependencies/gen.hpp"
|
||||
#undef ccast
|
||||
#undef pcast
|
||||
#undef rcast
|
||||
#undef scast
|
||||
#undef do_once
|
||||
#undef do_once_start
|
||||
#undef do_once_end
|
||||
|
@ -5,73 +5,57 @@
|
||||
|
||||
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
|
||||
constexpr f32 analog__move_threshold = 0.5f;
|
||||
|
||||
struct EngineActions
|
||||
{
|
||||
b32 move_up = false;
|
||||
b32 move_down = false;
|
||||
b32 move_left = false;
|
||||
b32 move_right = false;
|
||||
b32 move_up;
|
||||
b32 move_down;
|
||||
b32 move_left;
|
||||
b32 move_right;
|
||||
|
||||
b32 loop_mode = false;
|
||||
b32 loop_mode_engine;
|
||||
b32 loop_mode_game;
|
||||
|
||||
b32 raise_volume = false;
|
||||
b32 lower_volume = false;
|
||||
b32 raise_tone_hz = false;
|
||||
b32 lower_tone_hz = false;
|
||||
b32 raise_volume;
|
||||
b32 lower_volume;
|
||||
b32 raise_tone_hz;
|
||||
b32 lower_tone_hz;
|
||||
|
||||
b32 toggle_wave_tone = false;
|
||||
b32 toggle_wave_tone;
|
||||
|
||||
#if Build_Development
|
||||
b32 pause_renderer = false;
|
||||
b32 pause_renderer;
|
||||
#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
|
||||
{
|
||||
s32 WaveToneHz;
|
||||
s32 ToneVolume;
|
||||
s32 XOffset;
|
||||
s32 YOffset;
|
||||
s32 wave_tone_hz;
|
||||
s32 tone_volume;
|
||||
s32 x_offset;
|
||||
s32 y_offset;
|
||||
|
||||
b32 RendererPaused;
|
||||
b32 renderer_paused;
|
||||
|
||||
f32 SampleWaveSineTime;
|
||||
b32 SampleWaveSwitch;
|
||||
|
||||
s32 InputRecordingIndex;
|
||||
s32 InputPlayingIndex;
|
||||
|
||||
platform::File ActiveInputRecordingFile;
|
||||
platform::File ActivePlaybackFile;
|
||||
f32 sample_wave_sine_time;
|
||||
b32 sample_wave_switch;
|
||||
|
||||
hh::Memory game_memory;
|
||||
};
|
||||
|
||||
|
||||
using GetSoundSampleValueFn = s16( EngineState* state, AudioBuffer* sound_buffer );
|
||||
|
||||
internal s16
|
||||
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 ?
|
||||
state->ToneVolume : - state->ToneVolume;
|
||||
s32 sample_value = (sound_buffer->running_sample_index / (wave_period / 2) ) % 2 ?
|
||||
state->tone_volume : - state->tone_volume;
|
||||
|
||||
return scast(s16, sample_value);
|
||||
}
|
||||
@ -79,13 +63,13 @@ square_wave_sample_value( EngineState* state, AudioBuffer* sound_buffer )
|
||||
internal s16
|
||||
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;
|
||||
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 );
|
||||
if ( time > TAU )
|
||||
@ -98,11 +82,11 @@ sine_wave_sample_value( EngineState* state, AudioBuffer* sound_buffer )
|
||||
internal void
|
||||
output_sound( EngineState* state, AudioBuffer* sound_buffer, GetSoundSampleValueFn* get_sample_value )
|
||||
{
|
||||
s16* sample_out = sound_buffer->Samples;
|
||||
for ( s32 sample_index = 0; sample_index < sound_buffer->NumSamples; ++ sample_index )
|
||||
s16* sample_out = sound_buffer->samples;
|
||||
for ( s32 sample_index = 0; sample_index < sound_buffer->num_samples; ++ sample_index )
|
||||
{
|
||||
s16 sample_value = get_sample_value( state, sound_buffer );
|
||||
sound_buffer->RunningSampleIndex++;
|
||||
sound_buffer->running_sample_index++;
|
||||
|
||||
// char ms_timing_debug[256] {};
|
||||
// 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* row = rcast( u8*, buffer->Memory);
|
||||
u8* row = rcast( u8*, buffer->memory);
|
||||
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);
|
||||
// Pixel* pixel = rcast( Pixel*, 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:
|
||||
-----------------------------------------------
|
||||
@ -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 red = scast(u8, wildcard) % 256 - x * 0.4f;
|
||||
#else
|
||||
u8 red = scast(u8, y + x_offset);
|
||||
u8 green = scast(u8, x + y_offset);
|
||||
u8 blue = scast(u8, x + y - x_offset - y_offset);
|
||||
u8 red = scast(u8, y + y_offset);
|
||||
u8 green = scast(u8, x + x_offset);
|
||||
u8 blue = scast(u8, x + y_offset) - scast(u8, y + y_offset);
|
||||
// blue *= 2;
|
||||
#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;
|
||||
row += buffer->Pitch;
|
||||
row += buffer->pitch;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
render_player( OffscreenBuffer* buffer, s32 pos_x, s32 pos_y )
|
||||
{
|
||||
u8* end_of_buffer = rcast(u8*, buffer->Memory)
|
||||
- buffer->BytesPerPixel * buffer->Width
|
||||
+ buffer->Pitch * buffer->Height;
|
||||
u8* end_of_buffer = rcast(u8*, buffer->memory)
|
||||
- buffer->bytes_per_pixel * buffer->width
|
||||
+ buffer->pitch * buffer->height;
|
||||
|
||||
s32 top = pos_y;
|
||||
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 )
|
||||
{
|
||||
u8*
|
||||
pixel_byte = rcast(u8*, buffer->Memory);
|
||||
pixel_byte += coord_x * buffer->BytesPerPixel;
|
||||
pixel_byte += top * buffer->Pitch;
|
||||
pixel_byte = rcast(u8*, buffer->memory);
|
||||
pixel_byte += coord_x * buffer->bytes_per_pixel;
|
||||
pixel_byte += top * buffer->pitch;
|
||||
|
||||
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;
|
||||
|
||||
s32* pixel = rcast(s32*, pixel_byte);
|
||||
*pixel = color;
|
||||
|
||||
pixel_byte += buffer->Pitch;
|
||||
|
||||
|
||||
pixel_byte += buffer->pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using SnapshotFn = void ( s32 slot, Memory* memory, platform::ModuleAPI* platform_api );
|
||||
|
||||
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");
|
||||
StrPath file_path = {};
|
||||
file_path.concat( platform_api->path_scratch, file_name );
|
||||
|
||||
state->ActiveInputRecordingFile.Path = file_path;
|
||||
state->InputRecordingIndex = 1;
|
||||
memory->active_recording_file.path = file_path;
|
||||
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 );
|
||||
#endif
|
||||
}
|
||||
|
||||
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 );
|
||||
state->InputRecordingIndex = 0;
|
||||
memory->input_recording_index = 0;
|
||||
platform_api->file_close( & memory->active_recording_file );
|
||||
}
|
||||
|
||||
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");
|
||||
StrPath file_path = {};
|
||||
file_path.concat( platform_api->path_scratch, file_name );
|
||||
if ( platform_api->file_check_exists( file_path ) )
|
||||
{
|
||||
state->ActivePlaybackFile.Path = file_path;
|
||||
state->InputPlayingIndex = 1;
|
||||
memory->active_playback_file.path = file_path;
|
||||
memory->input_playback_index = 1;
|
||||
}
|
||||
|
||||
#if Snapshot_New_Way
|
||||
#else
|
||||
if ( state->ActiveInputRecordingFile.OpaqueHandle == nullptr )
|
||||
{
|
||||
platform_api->file_read_stream( & state->ActivePlaybackFile, scast(u32, state->game_memory.PersistentSize), state->game_memory.Persistent );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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_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 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 )
|
||||
continue;
|
||||
|
||||
if ( controller->DSPad )
|
||||
snapshot.Controllers[idx].DSPad = *controller->DSPad;
|
||||
if ( controller->ds_pad )
|
||||
snapshot.controllers[idx].ds_pad = *controller->ds_pad;
|
||||
|
||||
if ( controller->XPad )
|
||||
snapshot.Controllers[idx].XPad = *controller->XPad;
|
||||
if ( 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 )
|
||||
snapshot.Controllers[idx].Mouse = *controller->Mouse;
|
||||
if ( controller->mouse )
|
||||
snapshot.controllers[idx].mouse = *controller->mouse;
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
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 );
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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 );
|
||||
begin_playback_input( state, input, platform_api );
|
||||
end_playback_input( memory, input, platform_api );
|
||||
load_snapshot( memory->active_snapshot_slot, memory, platform_api );
|
||||
begin_playback_input( memory, input, platform_api );
|
||||
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 )
|
||||
continue;
|
||||
|
||||
if ( controller->DSPad )
|
||||
*controller->DSPad = new_input.Controllers[idx].DSPad;
|
||||
if ( controller->ds_pad )
|
||||
*controller->ds_pad = new_input.controllers[idx].ds_pad;
|
||||
|
||||
if ( controller->XPad )
|
||||
*controller->XPad = new_input.Controllers[idx].XPad;
|
||||
if ( controller->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 )
|
||||
*controller->Mouse = new_input.Controllers[idx].Mouse;
|
||||
if ( controller->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
|
||||
void input_poll_engine_actions( InputState* input, EngineActions* actions )
|
||||
{
|
||||
ControllerState* controller = & input->Controllers[0];
|
||||
KeyboardState* keyboard = controller->Keyboard;
|
||||
ControllerState* controller = & input->controllers[0];
|
||||
KeyboardState* keyboard = controller->keyboard;
|
||||
|
||||
actions->move_right |= keyboard->D.EndedDown;
|
||||
actions->move_left |= keyboard->A.EndedDown;
|
||||
actions->move_up |= keyboard->W.EndedDown;
|
||||
actions->move_down |= keyboard->S.EndedDown;
|
||||
// actions->move_right |= keyboard->D.EndedDown;
|
||||
// actions->move_left |= keyboard->A.EndedDown;
|
||||
// actions->move_up |= keyboard->W.EndedDown;
|
||||
// actions->move_down |= keyboard->S.EndedDown;
|
||||
|
||||
actions->raise_volume |= keyboard->Up.EndedDown;
|
||||
actions->lower_volume |= keyboard->Down.EndedDown;
|
||||
actions->raise_volume |= keyboard->up.ended_down;
|
||||
actions->lower_volume |= keyboard->down.ended_down;
|
||||
|
||||
actions->raise_tone_hz |= keyboard->Right.EndedDown;
|
||||
actions->lower_tone_hz |= keyboard->Left.EndedDown;
|
||||
actions->raise_tone_hz |= keyboard->right.ended_down;
|
||||
actions->lower_tone_hz |= keyboard->left.ended_down;
|
||||
|
||||
#if Build_Development
|
||||
actions->pause_renderer |= pressed( keyboard->Pause );
|
||||
actions->pause_renderer |= pressed( keyboard->pause );
|
||||
#endif
|
||||
|
||||
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
|
||||
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_y_move_analog += pad->Stick.Left.Y.End;
|
||||
actions->player_x_move_analog += pad->stick.left.X.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->player_x_move_analog += pad->Stick.Left.X.End;
|
||||
actions->player_y_move_analog += pad->Stick.Left.Y.End;
|
||||
actions->player_x_move_analog += pad->stick.left.X.end;
|
||||
actions->player_y_move_analog += pad->stick.left.Y.end;
|
||||
}
|
||||
|
||||
if ( controller->Keyboard )
|
||||
if ( controller->keyboard )
|
||||
{
|
||||
KeyboardState* keyboard = controller->Keyboard;
|
||||
actions->jump |= pressed( keyboard->Space );
|
||||
KeyboardState* keyboard = controller->keyboard;
|
||||
actions->jump |= pressed( keyboard->space );
|
||||
|
||||
actions->player_x_move_digital += keyboard->D.EndedDown - keyboard->A.EndedDown;
|
||||
actions->player_y_move_digital += keyboard->W.EndedDown - keyboard->S.EndedDown;
|
||||
actions->player_x_move_digital += keyboard->D.ended_down - keyboard->A.ended_down;
|
||||
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
|
||||
void startup( Memory* memory, platform::ModuleAPI* platform_api )
|
||||
{
|
||||
EngineState* state = rcast( EngineState*, memory->Persistent );
|
||||
assert( sizeof(EngineState) <= memory->PersistentSize );
|
||||
memory->active_snapshot_slot = -1;
|
||||
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;
|
||||
state->YOffset = 0;
|
||||
EngineState* state = rcast( EngineState*, memory->persistent );
|
||||
assert( sizeof(EngineState) <= memory->persistent_size );
|
||||
|
||||
state->SampleWaveSwitch = false;
|
||||
state->WaveToneHz = 60;
|
||||
state->SampleWaveSineTime = 0.f;
|
||||
state->tone_volume = 1000;
|
||||
|
||||
state->RendererPaused = false;
|
||||
state->x_offset = 0;
|
||||
state->y_offset = 0;
|
||||
|
||||
state->InputRecordingIndex = 0;
|
||||
state->InputPlayingIndex = 0;
|
||||
state->sample_wave_switch = false;
|
||||
state->wave_tone_hz = 60;
|
||||
state->sample_wave_sine_time = 0.f;
|
||||
|
||||
state->ActiveInputRecordingFile = {};
|
||||
state->ActivePlaybackFile = {};
|
||||
state->renderer_paused = false;
|
||||
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;
|
||||
state->game_memory.Persistent = rcast(Byte*, memory->Persistent) + state->game_memory.PersistentSize;
|
||||
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 );
|
||||
assert( sizeof(hh::PlayerState) <= state->game_memory.persistent_size );
|
||||
|
||||
hh::PlayerState* player = rcast( hh::PlayerState*, state->game_memory.Persistent );
|
||||
assert( sizeof(hh::PlayerState) <= state->game_memory.PersistentSize );
|
||||
|
||||
player->Pos_X = 100;
|
||||
player->Pos_Y = 100;
|
||||
player->MidJump = false;
|
||||
player->pos_x = 100;
|
||||
player->pos_y = 100;
|
||||
player->mid_jump = false;
|
||||
player->jump_time = 0.f;
|
||||
}
|
||||
|
||||
Engine_API
|
||||
@ -422,137 +501,169 @@ void shutdown( Memory* memory, platform::ModuleAPI* platform_api )
|
||||
|
||||
Engine_API
|
||||
// TODO : I rather expose the back_buffer and sound_buffer using getters for access in any function.
|
||||
void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* platform_api )
|
||||
void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* platform_api, ThreadContext* thread )
|
||||
{
|
||||
EngineState* state = rcast( EngineState*, memory->Persistent );
|
||||
assert( sizeof(EngineState) <= memory->PersistentSize );
|
||||
EngineState* state = rcast( EngineState*, memory->persistent );
|
||||
assert( sizeof(EngineState) <= memory->persistent_size );
|
||||
|
||||
ControllerState* controller = & input->Controllers[0];
|
||||
ControllerState* controller = & input->controllers[0];
|
||||
|
||||
EngineActions engine_actions {};
|
||||
PlayerActions player_actions {};
|
||||
EngineActions engine_actions {};
|
||||
hh::PlayerActions player_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;
|
||||
state->XOffset -= 3 * engine_actions.move_left;
|
||||
state->YOffset += 3 * engine_actions.move_down;
|
||||
state->YOffset -= 3 * engine_actions.move_up;
|
||||
process_loop_mode( & take_engine_snapshot, & load_engine_snapshot, memory, state, input, platform_api );
|
||||
memory->engine_loop_active = memory->input_playback_index || memory->input_recording_index;
|
||||
}
|
||||
|
||||
// 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 )
|
||||
{
|
||||
state->ToneVolume += 10;
|
||||
state->tone_volume += 10;
|
||||
}
|
||||
if ( engine_actions.lower_volume )
|
||||
{
|
||||
state->ToneVolume -= 10;
|
||||
if ( state->ToneVolume <= 0 )
|
||||
state->ToneVolume = 0;
|
||||
state->tone_volume -= 10;
|
||||
if ( state->tone_volume <= 0 )
|
||||
state->tone_volume = 0;
|
||||
}
|
||||
|
||||
if ( engine_actions.raise_tone_hz )
|
||||
{
|
||||
state->WaveToneHz += 1;
|
||||
state->wave_tone_hz += 1;
|
||||
}
|
||||
if ( engine_actions.lower_tone_hz )
|
||||
{
|
||||
state->WaveToneHz -= 1;
|
||||
if ( state->WaveToneHz <= 0 )
|
||||
state->WaveToneHz = 1;
|
||||
state->wave_tone_hz -= 1;
|
||||
if ( state->wave_tone_hz <= 0 )
|
||||
state->wave_tone_hz = 1;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
#if Build_Development
|
||||
if ( engine_actions.pause_renderer )
|
||||
{
|
||||
if ( state->RendererPaused )
|
||||
if ( state->renderer_paused )
|
||||
{
|
||||
platform_api->debug_set_pause_rendering(false);
|
||||
state->RendererPaused = false;
|
||||
state->renderer_paused = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
platform_api->debug_set_pause_rendering(true);
|
||||
state->RendererPaused = true;
|
||||
state->renderer_paused = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( state->InputRecordingIndex )
|
||||
if ( ! memory->engine_loop_active )
|
||||
{
|
||||
record_input( state, input, platform_api );
|
||||
}
|
||||
if ( state->InputPlayingIndex )
|
||||
{
|
||||
play_input( state, input, platform_api );
|
||||
// Input recording and playback for game state
|
||||
if ( memory->input_recording_index )
|
||||
{
|
||||
record_input( memory, 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 );
|
||||
assert( sizeof(hh::PlayerState) <= state->game_memory.PersistentSize );
|
||||
hh::PlayerState* player = rcast( hh::PlayerState*, state->game_memory.persistent );
|
||||
assert( sizeof(hh::PlayerState) <= state->game_memory.persistent_size );
|
||||
|
||||
input_poll_player_actions( input, & player_actions );
|
||||
{
|
||||
player->Pos_X += player_actions.player_x_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_Y -= scast(u32, player_actions.player_y_move_analog * 5) - scast(u32, sinf( player->JumpTime * TAU ) * 10);
|
||||
player->pos_x += player_actions.player_x_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_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
|
||||
{
|
||||
player->JumpTime = 0.f;
|
||||
player->MidJump = false;
|
||||
player->jump_time = 0.f;
|
||||
player->mid_jump = false;
|
||||
}
|
||||
|
||||
if ( ! player->MidJump && player_actions.jump )
|
||||
if ( ! player->mid_jump && player_actions.jump )
|
||||
{
|
||||
player->JumpTime = 1.f;
|
||||
player->MidJump = true;
|
||||
player->jump_time = 1.f;
|
||||
player->mid_jump = true;
|
||||
}
|
||||
}
|
||||
|
||||
render_weird_graident( back_buffer, 0, 0 );
|
||||
render_player( back_buffer, player->Pos_X, player->Pos_Y );
|
||||
render_weird_graident( back_buffer, state->x_offset, state->y_offset );
|
||||
render_player( back_buffer, player->pos_x, player->pos_y );
|
||||
|
||||
if ( state->InputRecordingIndex )
|
||||
render_player( back_buffer, player->Pos_X + 20, player->Pos_Y - 20 );
|
||||
if ( memory->input_recording_index )
|
||||
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
|
||||
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_end
|
||||
|
||||
// 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 );
|
||||
else
|
||||
output_sound( state, audio_buffer, square_wave_sample_value );
|
||||
|
@ -14,7 +14,18 @@ NS_ENGINE_BEGIN
|
||||
struct Clocks
|
||||
{
|
||||
// TODO(Ed) : Clock values...
|
||||
f32 SecondsElapsed;
|
||||
f32 seconds_elapsed;
|
||||
};
|
||||
|
||||
struct ThreadContext
|
||||
{
|
||||
u32 placeholder;
|
||||
};
|
||||
|
||||
struct MemorySnapshot
|
||||
{
|
||||
Str file_path;
|
||||
void* memory;
|
||||
};
|
||||
|
||||
struct Memory
|
||||
@ -22,51 +33,75 @@ struct Memory
|
||||
// All memory for the engine is required to be zero initialized.
|
||||
|
||||
// Wiped on shutdown
|
||||
void* Persistent;
|
||||
u64 PersistentSize;
|
||||
void* persistent;
|
||||
u64 persistent_size;
|
||||
|
||||
// Wiped on a per-frame basis
|
||||
// void* Frame;
|
||||
// u64 FrameSize;
|
||||
|
||||
// Wiped whenever the engine wants to?
|
||||
void* Transient;
|
||||
u64 TransientSize;
|
||||
void* transient;
|
||||
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
|
||||
{
|
||||
void* Memory; // Lets use directly mess with the "pixel's memory buffer"
|
||||
u32 Width;
|
||||
u32 Height;
|
||||
u32 Pitch;
|
||||
u32 BytesPerPixel;
|
||||
void* memory; // Lets use directly mess with the "pixel's memory buffer"
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 pitch;
|
||||
u32 bytes_per_pixel;
|
||||
};
|
||||
|
||||
// TODO : Will be gutting this once we have other stuff lifted.
|
||||
struct AudioBuffer
|
||||
{
|
||||
s16* Samples;
|
||||
u32 RunningSampleIndex;
|
||||
s32 SamplesPerSecond;
|
||||
s32 NumSamples;
|
||||
s16* samples;
|
||||
u32 running_sample_index;
|
||||
s32 samples_per_second;
|
||||
s32 num_samples;
|
||||
};
|
||||
|
||||
struct DigitalBtn
|
||||
{
|
||||
s32 HalfTransitions;
|
||||
b32 EndedDown;
|
||||
s32 half_transitions;
|
||||
b32 ended_down;
|
||||
};
|
||||
|
||||
struct AnalogAxis
|
||||
{
|
||||
f32 Start;
|
||||
f32 End;
|
||||
f32 Min;
|
||||
f32 Max;
|
||||
f32 start;
|
||||
f32 end;
|
||||
f32 min;
|
||||
f32 max;
|
||||
|
||||
// Platform doesn't provide this, we process in the engine layer.
|
||||
f32 Average;
|
||||
f32 average;
|
||||
};
|
||||
|
||||
struct AnalogStick
|
||||
@ -77,62 +112,70 @@ struct AnalogStick
|
||||
|
||||
union KeyboardState
|
||||
{
|
||||
DigitalBtn Keys[12];
|
||||
DigitalBtn keys[12];
|
||||
struct {
|
||||
DigitalBtn Row_1;
|
||||
DigitalBtn row_1;
|
||||
DigitalBtn Q;
|
||||
DigitalBtn E;
|
||||
DigitalBtn W;
|
||||
DigitalBtn A;
|
||||
DigitalBtn S;
|
||||
DigitalBtn D;
|
||||
DigitalBtn K;
|
||||
DigitalBtn L;
|
||||
DigitalBtn Escape;
|
||||
DigitalBtn Backspace;
|
||||
DigitalBtn Up;
|
||||
DigitalBtn Down;
|
||||
DigitalBtn Left;
|
||||
DigitalBtn Right;
|
||||
DigitalBtn Space;
|
||||
DigitalBtn Pause;
|
||||
DigitalBtn escape;
|
||||
DigitalBtn backspace;
|
||||
DigitalBtn up;
|
||||
DigitalBtn down;
|
||||
DigitalBtn left;
|
||||
DigitalBtn right;
|
||||
DigitalBtn space;
|
||||
DigitalBtn pause;
|
||||
DigitalBtn right_shift;
|
||||
DigitalBtn left_shift;
|
||||
};
|
||||
};
|
||||
|
||||
struct MousesState
|
||||
{
|
||||
DigitalBtn Left;
|
||||
DigitalBtn Middle;
|
||||
DigitalBtn Right;
|
||||
DigitalBtn left;
|
||||
DigitalBtn middle;
|
||||
DigitalBtn right;
|
||||
|
||||
AnalogAxis X;
|
||||
AnalogAxis Y;
|
||||
AnalogAxis vertical_wheel;
|
||||
AnalogAxis horizontal_wheel;
|
||||
};
|
||||
|
||||
struct XInputPadState
|
||||
{
|
||||
struct
|
||||
{
|
||||
AnalogStick Left;
|
||||
AnalogStick Right;
|
||||
} Stick;
|
||||
AnalogStick left;
|
||||
AnalogStick right;
|
||||
} stick;
|
||||
|
||||
AnalogAxis LeftTrigger;
|
||||
AnalogAxis RightTrigger;
|
||||
AnalogAxis left_trigger;
|
||||
AnalogAxis right_trigger;
|
||||
|
||||
union {
|
||||
DigitalBtn Btns[14];
|
||||
DigitalBtn btns[14];
|
||||
struct {
|
||||
struct {
|
||||
DigitalBtn Up;
|
||||
DigitalBtn Down;
|
||||
DigitalBtn Left;
|
||||
DigitalBtn Right;
|
||||
} DPad;
|
||||
DigitalBtn up;
|
||||
DigitalBtn down;
|
||||
DigitalBtn left;
|
||||
DigitalBtn right;
|
||||
} dpad;
|
||||
DigitalBtn A;
|
||||
DigitalBtn B;
|
||||
DigitalBtn X;
|
||||
DigitalBtn Y;
|
||||
DigitalBtn Back;
|
||||
DigitalBtn Start;
|
||||
DigitalBtn LeftShoulder;
|
||||
DigitalBtn RightShoulder;
|
||||
DigitalBtn back;
|
||||
DigitalBtn start;
|
||||
DigitalBtn left_shoulder;
|
||||
DigitalBtn right_shoulder;
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -141,28 +184,28 @@ struct DualsensePadState
|
||||
{
|
||||
struct
|
||||
{
|
||||
AnalogStick Left;
|
||||
AnalogStick Right;
|
||||
} Stick;
|
||||
AnalogStick left;
|
||||
AnalogStick right;
|
||||
} stick;
|
||||
|
||||
AnalogAxis L2;
|
||||
AnalogAxis R2;
|
||||
|
||||
union {
|
||||
DigitalBtn Btns[14];
|
||||
DigitalBtn btns[14];
|
||||
struct {
|
||||
struct {
|
||||
DigitalBtn Up;
|
||||
DigitalBtn Down;
|
||||
DigitalBtn Left;
|
||||
DigitalBtn Right;
|
||||
} DPad;
|
||||
DigitalBtn X;
|
||||
DigitalBtn Circle;
|
||||
DigitalBtn Square;
|
||||
DigitalBtn Triangle;
|
||||
DigitalBtn Share;
|
||||
DigitalBtn Options;
|
||||
DigitalBtn up;
|
||||
DigitalBtn down;
|
||||
DigitalBtn left;
|
||||
DigitalBtn right;
|
||||
} dpad;
|
||||
DigitalBtn cross;
|
||||
DigitalBtn circle;
|
||||
DigitalBtn square;
|
||||
DigitalBtn triangle;
|
||||
DigitalBtn share;
|
||||
DigitalBtn options;
|
||||
DigitalBtn L1;
|
||||
DigitalBtn R1;
|
||||
};
|
||||
@ -171,39 +214,39 @@ struct DualsensePadState
|
||||
|
||||
struct ControllerState
|
||||
{
|
||||
KeyboardState* Keyboard;
|
||||
MousesState* Mouse;
|
||||
XInputPadState* XPad;
|
||||
DualsensePadState* DSPad;
|
||||
KeyboardState* keyboard;
|
||||
MousesState* mouse;
|
||||
XInputPadState* xpad;
|
||||
DualsensePadState* ds_pad;
|
||||
};
|
||||
|
||||
struct ControllerStateSnapshot
|
||||
{
|
||||
KeyboardState Keyboard;
|
||||
MousesState Mouse;
|
||||
XInputPadState XPad;
|
||||
DualsensePadState DSPad;
|
||||
KeyboardState keyboard;
|
||||
MousesState mouse;
|
||||
XInputPadState xpad;
|
||||
DualsensePadState ds_pad;
|
||||
};
|
||||
|
||||
struct InputState
|
||||
{
|
||||
ControllerState Controllers[4];
|
||||
ControllerState controllers[4];
|
||||
};
|
||||
|
||||
struct InputStateSnapshot
|
||||
{
|
||||
ControllerStateSnapshot Controllers[4];
|
||||
ControllerStateSnapshot controllers[4];
|
||||
};
|
||||
|
||||
using InputBindCallback = void( void* );
|
||||
using InputBindCallback_DigitalBtn = void( engine::DigitalBtn* Button );
|
||||
using InputBindCallback_AnalogAxis = void( engine::AnalogAxis* Axis );
|
||||
using InputBindCallback_AnalogStick = void( engine::AnalogStick* Stick );
|
||||
using InputBindCallback_DigitalBtn = void( engine::DigitalBtn* button );
|
||||
using InputBindCallback_AnalogAxis = void( engine::AnalogAxis* axis );
|
||||
using InputBindCallback_AnalogStick = void( engine::AnalogStick* stick );
|
||||
|
||||
struct InputMode
|
||||
{
|
||||
InputBindCallback* Binds;
|
||||
s32 NumBinds;
|
||||
InputBindCallback* binds;
|
||||
s32 num_binds;
|
||||
};
|
||||
|
||||
void input_mode_pop( InputMode* mode );
|
||||
@ -212,8 +255,8 @@ void input_mode_pop( InputMode* mode );
|
||||
#if 0
|
||||
struct RecordedInput
|
||||
{
|
||||
s32 Num;
|
||||
InputState* Stream;
|
||||
s32 num;
|
||||
InputState* stream;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -16,12 +16,12 @@ using ShutdownFn = void( Memory* memory, platform::ModuleAPI* platform_api
|
||||
|
||||
// Needs a contextual reference to four things:
|
||||
// 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.
|
||||
// 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.
|
||||
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
|
||||
{
|
||||
|
@ -10,8 +10,8 @@ Str const symbol_startup = str_ascii("?startup@engine@@YAXPEAUMemory@1@PEAUModu
|
||||
constexpr
|
||||
Str const symbol_shutdown = str_ascii("?shutdown@engine@@YAXPEAUMemory@1@PEAUModuleAPI@platform@@@Z");
|
||||
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
|
||||
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
|
||||
|
@ -11,22 +11,27 @@ struct Memory
|
||||
{
|
||||
// Subscection of engine memory for the game to use.
|
||||
|
||||
void* Persistent;
|
||||
u64 PersistentSize;
|
||||
void* persistent;
|
||||
u64 persistent_size;
|
||||
|
||||
// void* Frame;
|
||||
// u64 FrameSize;
|
||||
|
||||
void* Transient;
|
||||
u64 TransientSize;
|
||||
void* transient;
|
||||
u64 transient_size;
|
||||
|
||||
u64 total_size()
|
||||
{
|
||||
return persistent_size + transient_size;
|
||||
}
|
||||
};
|
||||
|
||||
// We want a 'binding' to have multiple binds to active it (most likely)
|
||||
struct Actionable
|
||||
{
|
||||
char const* Name;
|
||||
engine::InputBindCallback* Binds;
|
||||
s32 NumBinds;
|
||||
char const* name;
|
||||
engine::InputBindCallback* binds;
|
||||
s32 num_binds;
|
||||
};
|
||||
|
||||
struct ActionableMode
|
||||
@ -58,18 +63,28 @@ struct ActionableMode
|
||||
struct Player
|
||||
{
|
||||
// So far just has an assigned controller.
|
||||
engine::ControllerState* Controller;
|
||||
engine::ControllerState* controller;
|
||||
|
||||
// Possilby some other stuff in the future.
|
||||
};
|
||||
|
||||
struct PlayerState
|
||||
{
|
||||
s32 Pos_X;
|
||||
s32 Pos_Y;
|
||||
s32 pos_x;
|
||||
s32 pos_y;
|
||||
|
||||
b32 MidJump;
|
||||
f32 JumpTime;
|
||||
b32 mid_jump;
|
||||
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
|
||||
|
@ -11,6 +11,7 @@
|
||||
#pragma warning( disable: 4820 ) // Support auto-adding padding to structs
|
||||
#pragma warning( disable: 4711 ) // Support automatic inline expansion
|
||||
#pragma warning( disable: 4710 ) // Support automatic inline expansion
|
||||
#pragma warning( disable: 4805 ) // Support comparisons of s32 to bool.
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
|
@ -10,19 +10,19 @@
|
||||
|
||||
// Casting
|
||||
|
||||
#define ccast( Type, Value ) ( const_cast< Type >( (Value) ) )
|
||||
#define pcast( Type, Value ) ( * reinterpret_cast< Type* >( & ( Value ) ) )
|
||||
#define rcast( Type, Value ) reinterpret_cast< Type >( Value )
|
||||
#define scast( Type, Value ) static_cast< Type >( Value )
|
||||
#define ccast( type, value ) ( const_cast< type >( (value) ) )
|
||||
#define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) )
|
||||
#define rcast( type, value ) reinterpret_cast< type >( value )
|
||||
#define scast( type, value ) static_cast< type >( value )
|
||||
|
||||
#define do_once() \
|
||||
do \
|
||||
{ \
|
||||
local_persist \
|
||||
bool Done = false; \
|
||||
if ( Done ) \
|
||||
bool done = false; \
|
||||
if ( done ) \
|
||||
return; \
|
||||
Done = true; \
|
||||
done = true; \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
@ -30,10 +30,10 @@
|
||||
do \
|
||||
{ \
|
||||
local_persist \
|
||||
bool Done = false; \
|
||||
if ( Done ) \
|
||||
bool done = false; \
|
||||
if ( done ) \
|
||||
break; \
|
||||
Done = true;
|
||||
done = true;
|
||||
|
||||
#define do_once_end \
|
||||
} \
|
||||
|
@ -34,10 +34,10 @@ using DebugSetPauseRenderingFn = void (b32 value);
|
||||
|
||||
struct File
|
||||
{
|
||||
void* OpaqueHandle;
|
||||
Str Path;
|
||||
void* Data;
|
||||
u32 Size;
|
||||
void* opaque_handle;
|
||||
Str path;
|
||||
void* data;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
#pragma region Settings Exposure
|
||||
@ -57,7 +57,7 @@ using SetEngineFrameTargetFn = void ( u32 rate_in_hz );
|
||||
|
||||
struct BinaryModule
|
||||
{
|
||||
void* OpaqueHandle;
|
||||
void* opaque_handle;
|
||||
};
|
||||
|
||||
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 FileRewindFn = void ( File* file );
|
||||
|
||||
using MemoryCopyFn = void( void* dest, u64 src_size, void* src );
|
||||
|
||||
struct ModuleAPI
|
||||
{
|
||||
Str path_root;
|
||||
@ -106,6 +108,8 @@ struct ModuleAPI
|
||||
FileRewindFn* file_rewind; // Rewinds the file stream to the beginning
|
||||
FileWriteContentFn* file_write_content; // Writes content to file (overwrites)
|
||||
FileWriteStreamFn* file_write_stream; // Appends content to file
|
||||
|
||||
MemoryCopyFn* memory_copy;
|
||||
};
|
||||
|
||||
#pragma endregion Settings Exposure
|
||||
|
@ -12,32 +12,32 @@ u32 str_length( char const* str );
|
||||
// Length tracked raw strings.
|
||||
struct Str
|
||||
{
|
||||
u32 Len;
|
||||
char* Data;
|
||||
u32 len;
|
||||
char* ptr;
|
||||
|
||||
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 ) {
|
||||
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 )
|
||||
{
|
||||
str_concat( dest_size, dest->Data
|
||||
, str_a.Len, str_a.Data
|
||||
, str_b.Len, str_b.Data );
|
||||
dest->Len = str_a.Len + str_b.Len;
|
||||
str_concat( dest_size, dest->ptr
|
||||
, str_a.len, str_a.ptr
|
||||
, str_b.len, str_b.ptr );
|
||||
dest->len = str_a.len + str_b.len;
|
||||
}
|
||||
|
||||
operator char*() const {
|
||||
return Data;
|
||||
return ptr;
|
||||
}
|
||||
char& operator []( u32 idx ) {
|
||||
return Data[idx];
|
||||
return ptr[idx];
|
||||
}
|
||||
char const& operator []( u32 idx ) const {
|
||||
return Data[idx];
|
||||
return ptr[idx];
|
||||
}
|
||||
};
|
||||
|
||||
@ -47,35 +47,35 @@ struct StrFixed
|
||||
{
|
||||
constexpr static u32 Capacity = capacity;
|
||||
|
||||
u32 Len;
|
||||
char Data[capacity];
|
||||
u32 len;
|
||||
char ptr[capacity];
|
||||
|
||||
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 ) {
|
||||
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 )
|
||||
{
|
||||
str_concat( Capacity, Data
|
||||
, str_a.Len, str_a.Data
|
||||
, str_b.Len, str_b.Data );
|
||||
Len = str_a.Len + str_b.Len;
|
||||
str_concat( Capacity, ptr
|
||||
, str_a.len, str_a.ptr
|
||||
, str_b.len, str_b.ptr );
|
||||
len = str_a.len + str_b.len;
|
||||
}
|
||||
|
||||
operator char*() { return Data;}
|
||||
operator char const*() { return Data; }
|
||||
operator Str() { return { Len, Data }; }
|
||||
operator Str const() const { return { Len, Data }; }
|
||||
operator char*() { return ptr;}
|
||||
operator char const*() { return ptr; }
|
||||
operator Str() { return { len, ptr }; }
|
||||
operator Str const() const { return { len, ptr }; }
|
||||
char& operator []( u32 idx ) {
|
||||
assert( idx < Capacity );
|
||||
return Data[idx];
|
||||
return ptr[idx];
|
||||
}
|
||||
char const& operator []( u32 idx ) const {
|
||||
assert( idx < Capacity );
|
||||
return Data[idx];
|
||||
return ptr[idx];
|
||||
}
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user