Day 21 complete

This commit is contained in:
2023-09-26 17:26:35 -04:00
parent 1c3cf08687
commit 9220550dd4
22 changed files with 640 additions and 254 deletions

View File

@ -1,15 +1,21 @@
#include "engine.hpp"
//#include "win32.h"
#include "engine.hpp"
#include "platform/platform_engine_api.hpp"
#include "handmade.hpp"
NS_ENGINE_BEGIN
struct EngineState
{
s32 WaveSwitch;
s32 WaveToneHz;
s32 ToneVolume;
s32 XOffset;
s32 YOffset;
b32 RendererPaused;
f32 SampleWaveSineTime;
b32 SampleWaveSwitch;
};
using GetSoundSampleValueFn = s16( EngineState* state, AudioBuffer* sound_buffer );
@ -28,7 +34,7 @@ square_wave_sample_value( EngineState* state, AudioBuffer* sound_buffer )
internal s16
sine_wave_sample_value( EngineState* state, AudioBuffer* sound_buffer )
{
local_persist f32 time = 0.f;
f32& time = state->SampleWaveSineTime;
s32 wave_period = sound_buffer->SamplesPerSecond / state->WaveToneHz;
@ -104,7 +110,6 @@ render_weird_graident(OffscreenBuffer* buffer, u32 x_offset, u32 y_offset )
u8 red = 0;
#endif
*pixel++ = u32(red << 16) | u32(green << 8) | blue;
}
wildcard += 0.5375f;
@ -112,66 +117,55 @@ render_weird_graident(OffscreenBuffer* buffer, u32 x_offset, u32 y_offset )
}
}
b32 input_using_analog()
Engine_API
void on_module_reload( Memory* memory, platform::ModuleAPI* platfom_api )
{
return false;
}
void startup()
Engine_API
void startup( Memory* memory, platform::ModuleAPI* platform_api )
{
}
void shutdown()
{
}
// 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 )
{
// Graphics & Input Test
local_persist u32 x_offset = 0;
local_persist u32 y_offset = 0;
// Wave Sound Test
local_persist bool wave_switch = false;
#if 0
if ( input_using_analog() )
{
// TODO(Ed) : Use analog movement tuning
}
else
{
// TODO(Ed) : Use digital movement tuning
}
#endif
EngineState* state = rcast( EngineState*, memory->Persistent );
assert( sizeof(EngineState) <= memory->PersistentSize );
do_once_start
assert( sizeof(EngineState) <= memory->PersistentSize );
state->ToneVolume = 1000;
state->ToneVolume = 1000;
state->WaveToneHz = 120;
state->XOffset = 0;
state->YOffset = 0;
state->XOffset = 0;
state->YOffset = 0;
state->WaveSwitch = false;
state->SampleWaveSwitch = false;
state->WaveToneHz = 120;
state->SampleWaveSineTime = 0.f;
#if Build_Debug && 0
state->RendererPaused = false;
#if Build_Debug && 0
{
using namespace platform;
char const* file_path = __FILE__;
Debug_FileContent file_content = platform_api->debug_file_read_content( file_path );
if ( file_content.Size )
{
using namespace platform;
char const* file_path = __FILE__;
Debug_FileContent file_content = debug_file_read_content( file_path );
if ( file_content.Size )
{
debug_file_write_content( "test.out", file_content.Size, file_content.Data );
debug_file_free_content( & file_content );
}
platform_api->debug_file_write_content( "test.out", file_content.Size, file_content.Data );
platform_api->debug_file_free_content( & file_content );
}
#endif
do_once_end
}
#endif
}
Engine_API
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 )
{
EngineState* state = rcast( EngineState*, memory->Persistent );
assert( sizeof(EngineState) <= memory->PersistentSize );
ControllerState* controller = & input->Controllers[0];
@ -195,7 +189,6 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory*
b32 toggle_wave_tone = false;
b32 pause_renderer = false;
local_persist b32 renderer_paused = false;
f32 analog_threshold = 0.5f;
@ -255,10 +248,10 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory*
toggle_wave_tone |= pressed( keyboard->Space );
}
x_offset += 3 * move_right;
x_offset -= 3 * move_left;
y_offset += 3 * move_down;
y_offset -= 3 * move_up;
state->XOffset += 3 * move_right;
state->XOffset -= 3 * move_left;
state->YOffset += 3 * move_down;
state->YOffset -= 3 * move_up;
if ( raise_volume )
{
@ -284,26 +277,27 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory*
if ( toggle_wave_tone )
{
state->WaveSwitch ^= true;
state->SampleWaveSwitch ^= true;
}
render_weird_graident( back_buffer, x_offset, y_offset );
render_weird_graident( back_buffer, state->XOffset, state->YOffset );
if ( pause_renderer )
{
if ( renderer_paused )
if ( state->RendererPaused )
{
platform::set_pause_rendering(false);
renderer_paused = false;
platform_api->debug_set_pause_rendering(false);
state->RendererPaused = false;
}
else
{
platform::set_pause_rendering(true);
renderer_paused = true;
platform_api->debug_set_pause_rendering(true);
state->RendererPaused = true;
}
}
}
void update_audio( AudioBuffer* audio_buffer, Memory* memory )
Engine_API
void update_audio( AudioBuffer* audio_buffer, Memory* memory, platform::ModuleAPI* platform_api )
{
EngineState* state = rcast( EngineState*, memory->Persistent );
do_once_start
@ -311,11 +305,10 @@ void update_audio( AudioBuffer* audio_buffer, Memory* memory )
do_once_end
// TODO(Ed) : Allow sample offsets here for more robust platform options
if ( ! state->WaveSwitch )
if ( ! state->SampleWaveSwitch )
output_sound( state, audio_buffer, sine_wave_sample_value );
else
output_sound( state, audio_buffer, square_wave_sample_value );
}
NS_ENGINE_END

View File

@ -197,56 +197,3 @@ void input_mode_pop( InputMode* mode );
void input_mode_pop( InputMode* mode );
NS_ENGINE_END
// TODO(Ed) : Move this to handmade game layer later.
#define NS_HANDMADE_BEGIN namespace handmade {
#define NS_HANDMADE_END }
NS_HANDMADE_BEGIN
// We want a 'binding' to have multiple binds to active it (most likely)
struct Actionable
{
char const* Name;
engine::InputBindCallback* Binds;
s32 NumBinds;
char _PAD_[4];
};
struct ActionableMode
{
};
/*
Platform Layer:
Controller : Keyboard & Mouse, XPad, DSPad
---VV---
Engine Layer:
InputBinding callbacks (per-game-logic frame basis)
Push/Pop input modes (binding sets)
---VV---
Game Layer:
Actionables : Binding Sets where a raw input, or input interpretation leads to an player action.
ActionSet : Actionables.Push/Pop -> Input.Push/Pop ?
Player : Controller, Actionables, ActionSets
*/
struct Player
{
// So far just has an assigned controller.
engine::ControllerState* Controller;
// Possilby some other stuff in the future.
};
NS_HANDMADE_END

View File

@ -0,0 +1,11 @@
#include "platform/win32.hpp"
#include "engine.hpp"
b32 WINAPI DllMain(
HINSTANCE instance,
DWORD reason_for_call,
LPVOID reserved
)
{
return true;
}

View File

@ -4,5 +4,5 @@
#pragma once
#include "engine.hpp"
#include "engine/engine.hpp"

67
project/handmade.hpp Normal file
View File

@ -0,0 +1,67 @@
#pragma once
#include "engine/engine.hpp"
#define NS_HANDMADE_BEGIN namespace handmade {
#define NS_HANDMADE_END }
NS_HANDMADE_BEGIN
struct Memory
{
// Subscection of engine memory for the game to use.
void* Persistent;
u64 PersistentSize;
// void* Frame;
// u64 FrameSize;
void* Transient;
u64 TransientSize;
};
// We want a 'binding' to have multiple binds to active it (most likely)
struct Actionable
{
char const* Name;
engine::InputBindCallback* Binds;
s32 NumBinds;
char _PAD_[4];
};
struct ActionableMode
{
};
/*
Platform Layer:
Controller : Keyboard & Mouse, XPad, DSPad
---VV---
Engine Layer:
InputBinding callbacks (per-game-logic frame basis)
Push/Pop input modes (binding sets)
---VV---
Game Layer:
Actionables : Binding Sets where a raw input, or input interpretation leads to an player action.
ActionSet : Actionables.Push/Pop -> Input.Push/Pop ?
Player : Controller, Actionables, ActionSets
*/
struct Player
{
// So far just has an assigned controller.
engine::ControllerState* Controller;
// Possilby some other stuff in the future.
};
NS_HANDMADE_END

View File

@ -0,0 +1,19 @@
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-const-variable"
#pragma clang diagnostic ignored "-Wswitch"
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wvarargs"
#pragma clang diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#endif
#include "platform/grime.hpp"
#if Build_Unity
# include "engine/engine.cpp"
# if SYSTEM_WINDOWS
# include "engine/win32_engine.cpp"
# endif
#endif

View File

@ -10,7 +10,5 @@
#endif
#if Build_Unity
#include "handmade.cpp"
#include "engine.cpp"
#include "platform/win32_platform.cpp"
#endif

View File

@ -61,6 +61,12 @@
# define assert( expression )
#endif
#ifdef COMPILER_CLANG
# define compiler_decorated_func_name __PRETTY_NAME__
#elif defined(COMPILER_MSVC)
# define compiler_decorated_func_name __FUNCDNAME__
#endif
// TODO(Ed) : Add this sauce later
#if 0
#define congrats( message )

View File

@ -32,7 +32,11 @@
NS_PLATFORM_BEGIN
#if Build_Debug
// On-Demand platform interface.
// Everything exposed here should be based on a feature a game may want to provide a user
// (Example: Letting the user change the refresh-rate of the monitor or the engine's target frame-rate)
#if Build_Development
/*
IMPORTANT : These are not for shipping code - they are blocking and the write isn't protected.
*/
@ -44,34 +48,42 @@ struct Debug_FileContent
char _PAD_[4];
};
void debug_file_free_content ( Debug_FileContent* file_content );
Debug_FileContent debug_file_read_content ( char const* file_path );
b32 debug_file_write_content( char const* file_path, u32 content_size, void* content_memory );
// Allows the engine or game to pause the renderering of any next frames.
// ( Prevents blipping of the black buffer )
void set_pause_rendering( b32 value );
using DebugFileFreeContentFn = void ( Debug_FileContent* file_content );
using DebugFileReadContentFn = Debug_FileContent ( char const* file_path );
using DebugFileWriteContentFn = b32 ( char const* file_path, u32 content_size, void* content_memory );
using DebugSetPauseRenderingFn = void (b32 value);
#endif
// On-Demand platform interface.
// Everything exposed here should be based on a feature a game may want to provide a user
// (Example: Letting the user change the refresh-rate of the monitor or the engine's target frame-rate)
// TODO(Ed) : Implement this later when settings UI is setup.
#pragma region Settings Exposure
// Exposing specific properties for user configuration in settings
// Returns the current monitor refresh rate.
u32 get_monitor_refresh_rate();
using GetMonitorRefreshRateFn = u32();
// Sets the monitor refresh rate
// Must be of the compatiable listing for the monitor the window surface is presenting to.
void set_monitor_refresh_rate( u32 rate_in_hz );
// Must be of the compatiable listing for the monitor the window surface is presenting to
using SetMonitorRefreshRateFn = void ( u32 rate_in_hz );
u32 get_engine_frame_target();
using GetEngineFrameTargetFn = u32 ();
using SetEngineFrameTargetFn = void ( u32 rate_in_hz );
void set_engine_frame_target( u32 rate_in_hz );
struct ModuleAPI
{
#if Build_Development
DebugFileFreeContentFn* debug_file_free_content;
DebugFileReadContentFn* debug_file_read_content;
DebugFileWriteContentFn* debug_file_write_content;
DebugSetPauseRenderingFn* debug_set_pause_rendering;
#endif
GetMonitorRefreshRateFn* get_monitor_refresh_rate;
SetMonitorRefreshRateFn* set_monitor_refresh_rate;
GetEngineFrameTargetFn* get_engine_frame_target;
SetEngineFrameTargetFn* set_engine_frame_target;
};
#pragma endregion Settings Exposure

View File

@ -2,20 +2,47 @@
This represents the API only accessible to the platform layer to fullfill for the engine layer.
*/
#pragma once
#include "engine.hpp"
#include "engine/engine.hpp"
#ifndef Engine_API
# define Engine_API
#endif
NS_ENGINE_BEGIN
void startup();
void shutdown();
using OnModuleRelaodFn = void( Memory* memory, platform::ModuleAPI* platform_api );
using StartupFn = void( Memory* memory, platform::ModuleAPI* platform_api );
using ShutdownFn = void( Memory* memory, platform::ModuleAPI* platform_api );
// Needs a contextual reference to four things:
// Timing, Input, Bitmap Buffer
void update_and_render( InputState* input, OffscreenBuffer* back_buffer, Memory* memory );
using UpdateAndRenderFn = void ( InputState* input, OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* platform_api );
// 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.
void update_audio( AudioBuffer* audio_buffer, Memory* memory );
using UpdateAudioFn = void ( AudioBuffer* audio_buffer, Memory* memory, platform::ModuleAPI* platform_api );
struct ModuleAPI
{
enum : u32
{
Sym_OnModuleReload,
Sym_Startup,
Sym_Shutdown,
Sym_UpdateAndRender,
Sym_UpdateAudio,
};
OnModuleRelaodFn* on_module_reload;
StartupFn* startup;
ShutdownFn* shutdown;
UpdateAndRenderFn* update_and_render;
UpdateAudioFn* update_audio;
b32 IsValid;
char _PAD_[4];
};
NS_ENGINE_END

View File

@ -0,0 +1,3 @@
/*
This represents the API only accessible to the platform layer to fullfill for the game layer.
*/

View File

@ -113,6 +113,14 @@ enum XI_State : DWORD
XI_PluggedIn = ERROR_SUCCESS,
};
template< typename ProcSignature >
ProcSignature* get_procedure_from_library( HMODULE library_module, char const* symbol )
{
void* address = rcast( void*, GetProcAddress( library_module, symbol ) );
return rcast( ProcSignature*, address );
}
#pragma region XInput
WIN_LIB_API DWORD WINAPI XInputGetState
(
@ -151,11 +159,14 @@ xinput_load_library_bindings()
{
HMODULE xinput_lib = LoadLibraryA( XINPUT_DLL_A );
#pragma warning( push )
#pragma warning( disable: 4191 )
xinput_get_state = rcast( XInputGetStateFn*, GetProcAddress( xinput_lib, "XInputGetState" ));
xinput_set_state = rcast( XInputSetStateFn*, GetProcAddress( xinput_lib, "XInputSetState" ));
#pragma warning( pop )
XInputGetStateFn* get_state = get_procedure_from_library< XInputGetStateFn >( xinput_lib, "XInputGetState" );
XInputSetStateFn* set_state = get_procedure_from_library< XInputSetStateFn >( xinput_lib, "XInputSetState" );
if ( get_state )
xinput_get_state = get_state;
if ( set_state )
xinput_set_state = set_state;
}
#pragma endregion XInput

View File

@ -23,7 +23,7 @@
#include "win32.hpp"
// Engine layer headers
#include "engine.hpp"
#include "engine/engine.hpp"
#include "platform_engine_api.hpp"
// Standard-Library stand-ins
@ -216,7 +216,7 @@ b32 debug_file_write_content( char const* file_path, u32 content_size, void* con
return true;
}
void set_pause_rendering( b32 value )
void debug_set_pause_rendering( b32 value )
{
Pause_Rendering = value;
}
@ -425,15 +425,12 @@ init_sound(HWND window_handle, DirectSoundBuffer* sound_buffer )
}
// Get direct sound object
#pragma warning( push )
#pragma warning( disable: 4191 )
direct_sound_create = rcast( DirectSoundCreateFn*, GetProcAddress( sound_library, "DirectSoundCreate" ));
direct_sound_create = get_procedure_from_library< DirectSoundCreateFn >( sound_library, "DirectSoundCreate" );
if ( ! ensure( direct_sound_create, "Failed to get direct_sound_create_procedure" ) )
{
// TOOD : Diagnostic
return;
}
#pragma warning( pop )
LPDIRECTSOUND direct_sound;
if ( ! SUCCEEDED(direct_sound_create( 0, & direct_sound, 0 )) )
@ -751,6 +748,131 @@ process_pending_window_messages( engine::KeyboardState* keyboard )
}
}
}
#pragma region Platfom API
u32 get_monitor_refresh_rate();
#pragma endregion Platform API
// TODO(Ed): This also assumes the symbol name is always within size of the provided buffer, needs to fail if not.
void get_symbol_from_module_table( Debug_FileContent symbol_table, u32 symbol_ID, char* symbol_name )
{
struct Token
{
char const* Ptr;
u32 Len;
char _PAD_[4];
};
Token tokens[256] = {};
s32 idx = 0;
char const* scanner = rcast( char const*, symbol_table.Data );
u32 left = symbol_table.Size;
while ( left )
{
if ( *scanner == '\n' || *scanner == '\r' )
{
++ scanner;
-- left;
}
else
{
tokens[idx].Ptr = scanner;
while ( left && *scanner != '\r' && *scanner != '\n' )
{
-- left;
++ scanner;
++ tokens[idx].Len;
}
++ idx;
}
}
Token& token = tokens[symbol_ID];
while ( token.Len -- )
{
*symbol_name = *token.Ptr;
++ symbol_name;
++ token.Ptr;
}
*symbol_name = '\0';
}
// Right now they are just the data directory
#define Path_To_Symbol_Tables
global HMODULE Lib_Handmade_Engine = nullptr;
engine::ModuleAPI load_engine_module_api()
{
using ModuleAPI = engine::ModuleAPI;
// TODO(Ed) : Need proper paything to the dll (not assume is in the base directory).
CopyFileA( "handmade_engine.dll", "handmade_engine_temp.dll", FALSE );
// Engine
Lib_Handmade_Engine = LoadLibraryA( "handmade_engine_temp.dll" );
if ( ! Lib_Handmade_Engine )
{
return {};
}
constexpr char const*
handmade_engine_symbols = Path_To_Symbol_Tables "handmade_engine.symbols";
Debug_FileContent symbol_table = debug_file_read_content( handmade_engine_symbols );
if ( symbol_table.Size == 0 )
{
fatal( "Failed to laod symbol table for handmade engine module!" );
return {};
}
// TODO(Ed) : Clean this up later when Casey makes strings. (If he doesn't we'll do it)
char symbol_on_module_reload[256];
char symboL_startup[256];
char symboL_shutdown[256];
char symboL_update_and_render[256];
char symbol_update_audio[256];
get_symbol_from_module_table( symbol_table, ModuleAPI::Sym_OnModuleReload, symbol_on_module_reload );
get_symbol_from_module_table( symbol_table, ModuleAPI::Sym_Startup, symboL_startup );
get_symbol_from_module_table( symbol_table, ModuleAPI::Sym_Shutdown, symboL_shutdown );
get_symbol_from_module_table( symbol_table, ModuleAPI::Sym_UpdateAndRender, symboL_update_and_render );
get_symbol_from_module_table( symbol_table, ModuleAPI::Sym_UpdateAudio, symbol_update_audio );
debug_file_free_content( & symbol_table );
engine::ModuleAPI engine_api {};
engine_api.on_module_reload = get_procedure_from_library< engine::OnModuleRelaodFn > ( Lib_Handmade_Engine, symbol_on_module_reload );
engine_api.startup = get_procedure_from_library< engine::StartupFn > ( Lib_Handmade_Engine, symboL_startup );
engine_api.shutdown = get_procedure_from_library< engine::ShutdownFn > ( Lib_Handmade_Engine, symboL_shutdown );
engine_api.update_and_render = get_procedure_from_library< engine::UpdateAndRenderFn >( Lib_Handmade_Engine, symboL_update_and_render );
engine_api.update_audio = get_procedure_from_library< engine::UpdateAudioFn > ( Lib_Handmade_Engine, symbol_update_audio );
engine_api.IsValid =
engine_api.on_module_reload
&& engine_api.startup
&& engine_api.shutdown
&& engine_api.update_and_render
&& engine_api.update_audio;
if ( engine_api.IsValid )
{
OutputDebugStringA( "Loaded engine module API\n" );
}
return engine_api;
}
void unload_engine_module_api( engine::ModuleAPI* engine_api )
{
if ( engine_api->IsValid )
{
FreeLibrary( Lib_Handmade_Engine );
*engine_api = {};
OutputDebugStringA( "Unloaded engine module API\n" );
}
}
NS_PLATFORM_END
int CALLBACK
@ -774,6 +896,22 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
QueryPerformanceFrequency( rcast(LARGE_INTEGER*, & Performance_Counter_Frequency) );
// Prepare platform API
ModuleAPI platform_api {};
{
#if Build_Development
platform_api.debug_file_free_content = & debug_file_free_content;
platform_api.debug_file_read_content = & debug_file_read_content;
platform_api.debug_file_write_content = & debug_file_write_content;
platform_api.debug_set_pause_rendering = & debug_set_pause_rendering;
#endif
platform_api.get_monitor_refresh_rate = nullptr;
platform_api.set_monitor_refresh_rate = nullptr;
platform_api.get_engine_frame_target = nullptr;
platform_api.set_engine_frame_target = nullptr;
}
// Memory
engine::Memory engine_memory {};
{
@ -802,6 +940,9 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
}
}
// Load engine module
engine::ModuleAPI engine_api = load_engine_module_api();
WNDCLASSW window_class {};
HWND window_handle = nullptr;
{
@ -935,6 +1076,8 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
}
}
engine_api.startup( & engine_memory, & platform_api );
u64 last_frame_clock = timing_get_wall_clock();
u64 last_frame_cycle = __rdtsc();
u64 flip_wall_clock = last_frame_clock;
@ -942,8 +1085,14 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
#if Build_Development
u64 startup_cycles = last_frame_cycle - launch_cycle;
f32 startup_ms = timing_get_ms_elapsed( launch_clock, last_frame_clock );
char text_buffer[256];
sprintf_s( text_buffer, sizeof(text_buffer), "Startup MS: %f\n", startup_ms );
OutputDebugStringA( text_buffer );
#endif
u64 module_reload_counter = 0;
Running = true;
#if 0
// This tests the play & write cursor update frequency.
@ -960,6 +1109,14 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
#endif
while( Running )
{
if ( module_reload_counter > 120 )
{
unload_engine_module_api( & engine_api );
engine_api = load_engine_module_api();
module_reload_counter = 0;
}
++ module_reload_counter;
process_pending_window_messages( new_keyboard );
// TODO(Ed): Offload polling to these functions later.
@ -1107,7 +1264,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
}
// Engine's logical iteration and rendering process
engine::update_and_render( & input, rcast(engine::OffscreenBuffer*, & Surface_Back_Buffer.Memory), & engine_memory );
engine_api.update_and_render( & input, rcast(engine::OffscreenBuffer*, & Surface_Back_Buffer.Memory), & engine_memory, & platform_api );
u64 audio_frame_start = timing_get_wall_clock();
f32 flip_to_audio_ms = timing_get_ms_elapsed( flip_wall_clock, audio_frame_start );
@ -1194,7 +1351,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
sound_buffer.RunningSampleIndex = ds_sound_buffer.RunningSampleIndex;
sound_buffer.SamplesPerSecond = ds_sound_buffer.SamplesPerSecond;
sound_buffer.Samples = ds_sound_buffer.Samples;
engine::update_audio( & sound_buffer, & engine_memory );
engine_api.update_audio( & sound_buffer, & engine_memory, & platform_api );
DebugTimeMarker* marker = & debug_markers[ debug_marker_index ];
marker->OutputPlayCusror = ds_play_cursor;
@ -1331,7 +1488,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
#endif
}
engine::shutdown();
engine_api.shutdown( & engine_memory, & platform_api );
if ( jsl_num_devices > 0 )
{