From 5cfbc204a7ef877df4c9dcbad264d933a9d3ceff Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 23 Sep 2023 21:03:33 -0400 Subject: [PATCH] Day 19 complete --- HandmadeHero.10x | 38 +- HandmadeHero.sln | 20 + HandmadeHero.vcxproj | 70 +++ HandmadeHero.vcxproj.user | 11 + README.md | 2 +- docs/Day 019.md | 20 + .../JoyShockLibrary/InputHelpers.cpp | 9 +- .../JoyShockLibrary/JoyShockLibrary.h | 58 +-- project/engine.cpp | 15 +- project/engine.h | 8 +- project/handmade_win32.cpp | 16 + project/platform/jsl.h | 4 +- project/platform/memory.h | 0 project/platform/platform.h | 31 +- project/platform/platform_engine_api.h | 16 + ...{handmade_win32.cpp => platform_win32.cpp} | 429 +++++++++++------- scripts/build.ps1 | 30 +- scripts/clean.ps1 | 4 +- scripts/handmade.rdbg | Bin 829 -> 811 bytes scripts/rebuild.ps1 | 1 + 20 files changed, 554 insertions(+), 228 deletions(-) create mode 100644 HandmadeHero.sln create mode 100644 HandmadeHero.vcxproj create mode 100644 HandmadeHero.vcxproj.user create mode 100644 docs/Day 019.md create mode 100644 project/handmade_win32.cpp delete mode 100644 project/platform/memory.h create mode 100644 project/platform/platform_engine_api.h rename project/platform/{handmade_win32.cpp => platform_win32.cpp} (72%) create mode 100644 scripts/rebuild.ps1 diff --git a/HandmadeHero.10x b/HandmadeHero.10x index 40db348..e907d32 100644 --- a/HandmadeHero.10x +++ b/HandmadeHero.10x @@ -8,10 +8,10 @@ true false false - pwsh $(WorkspaceDirectory)/scripts/build.ps1 msvc dev debug - pwsh $(WorkspaceDirectory)/scripts/clean.ps1; $(WorkspaceDirectory)scripts/build.ps1 msvc dev debug + pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(WorkspaceDirectory)/scripts/build.ps1 msvc dev optimized + - pwsh $(WorkspaceDirectory)/scripts/clean.ps1 + pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(WorkspaceDirectory)/scripts/clean.ps1 $(WorkspaceDirectory)/build/handmade_win32.exe @@ -19,10 +19,10 @@ $(WorkspaceDirectory)/build/handmade_win32.exe $(WorkspaceDirectory)/build/handmade_win32.exe - false + true Dev Optimzied - Dev + Dev Optimized @@ -31,11 +31,11 @@ C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\VS\include - C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt - C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um - C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared - C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt - C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt + C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt + C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\um + C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\shared + C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041..0\\winrt + C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\cppwinrt C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um @@ -51,10 +51,28 @@ + + Dev :x64 + + + + + Dev Optimzied:x64 + + + Debug + + Dev + + + + Dev Optimzied + + x64 diff --git a/HandmadeHero.sln b/HandmadeHero.sln new file mode 100644 index 0000000..7cdc0fe --- /dev/null +++ b/HandmadeHero.sln @@ -0,0 +1,20 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.0 +MinimumVisualStudioVersion = 17.0.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HandmadeHero", "HandmadeHero.vcxproj", "{E1CF01B8-BB9F-42F4-9EDB-9F1274D3685A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Development|x64 = Development|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E1CF01B8-BB9F-42F4-9EDB-9F1274D3685A}.Development|x64.ActiveCfg = Development|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B3809CB4-EBEF-4551-B09E-0A1344DEB578} + EndGlobalSection +EndGlobal diff --git a/HandmadeHero.vcxproj b/HandmadeHero.vcxproj new file mode 100644 index 0000000..f8703d3 --- /dev/null +++ b/HandmadeHero.vcxproj @@ -0,0 +1,70 @@ + + + + {E1CF01B8-BB9F-42F4-9EDB-9F1274D3685A} + HandmadeHero + 10.0 + HandmadeHero + + + + + + Development + x64 + + + + $(ProjectDir)project;$(IncludePath) + $(ProjectDir)data;$(windir)System32;$(LibraryPath) + pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(ProjectDir)scripts\build.ps1 msvc dev + pwsh ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(ProjectDir)scripts\clean.ps1 + GEN_TIME;Build_Development;Build_Debug;$(NMakePreprocessorDefinitions) + $(VC_IncludePath);$(WindowsSDK_IncludePath) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Makefile + true + v143 + Unicode + + + + \ No newline at end of file diff --git a/HandmadeHero.vcxproj.user b/HandmadeHero.vcxproj.user new file mode 100644 index 0000000..556ee01 --- /dev/null +++ b/HandmadeHero.vcxproj.user @@ -0,0 +1,11 @@ + + + + true + + + $(ProjectDir)data + WindowsLocalDebugger + $(ProjectDir)build\handmade_win32.exe + + \ No newline at end of file diff --git a/README.md b/README.md index 9e84aee..bed3e43 100644 --- a/README.md +++ b/README.md @@ -25,5 +25,5 @@ The build is done in two stages: ## Gallery -![img](https://files.catbox.moe/fwjm1m.png) +![img](https://files.catbox.moe/xyh7u7.png) ![img](https://files.catbox.moe/b7ifa8.png) diff --git a/docs/Day 019.md b/docs/Day 019.md new file mode 100644 index 0000000..5a298d4 --- /dev/null +++ b/docs/Day 019.md @@ -0,0 +1,20 @@ +# Day 19 + +I started to do some cleanup while also following along. +`handmade_win32.cpp` now just holds the cpp build order when running the build script for unity builds. + +I want to eventually support segemnted builds as well, that way I can make sure there isn't some unhandled usaged of a global or some other symbol in one of the source files. +Evetually I can also use gencpp perform some static analysis to make sure differnt layers are not accessing symbols that they should not. + +I started to setup also pulling the polling of input out to a different function. +There are a few routes to go about it: + +* Make a separate function per input type: ( poll_keyboard, poll_xinput, poll_jsl ). +* Make a single function that handles all input polling (poll_input or process_input). +* (problably more...) + +I'm gravitating toward the second option, the amount of content is not that large, and would keep the code all together along with its control flow. + +Overall this was pretty brutual to follow along with for the vod. Thankfully handmade-notes exists.. +Reading the end of the notes page for the episode showed a forum link to mmozeiko discussing use of the Windows Core Audio API to alleviate the large amount of latency required to operate with DirectSound. +I'm going to wait until after day 20 since Casey has that one titled "Debugging the Aduio Sync" diff --git a/project/dependencies/JoyShockLibrary/InputHelpers.cpp b/project/dependencies/JoyShockLibrary/InputHelpers.cpp index 5d62b97..58a49df 100644 --- a/project/dependencies/JoyShockLibrary/InputHelpers.cpp +++ b/project/dependencies/JoyShockLibrary/InputHelpers.cpp @@ -224,9 +224,9 @@ bool handle_input(JoyShock *jc, uint8_t *packet, int len, bool &hasIMU) { if ((hat > 4) & (hat < 8)) jc->simple_state.buttons |= JSMASK_LEFT; // left = SW | W | NW jc->simple_state.buttons |= ((int) (packet[indexOffset + 7] >> 4) << JSOFFSET_W) & JSMASK_W; - jc->simple_state.buttons |= ((int) (packet[indexOffset + 7] >> 7) << JSOFFSET_N) & JSMASK_N; jc->simple_state.buttons |= ((int) (packet[indexOffset + 7] >> 5) << JSOFFSET_S) & JSMASK_S; jc->simple_state.buttons |= ((int) (packet[indexOffset + 7] >> 6) << JSOFFSET_E) & JSMASK_E; + jc->simple_state.buttons |= ((int) (packet[indexOffset + 7] >> 7) << JSOFFSET_N) & JSMASK_N; jc->simple_state.buttons |= ((int) (packet[indexOffset + 8] >> 6) << JSOFFSET_LCLICK) & JSMASK_LCLICK; jc->simple_state.buttons |= ((int) (packet[indexOffset + 8] >> 7) << JSOFFSET_RCLICK) & JSMASK_RCLICK; jc->simple_state.buttons |= ((int) (packet[indexOffset + 8] >> 5) << JSOFFSET_OPTIONS) & JSMASK_OPTIONS; @@ -235,9 +235,12 @@ bool handle_input(JoyShock *jc, uint8_t *packet, int len, bool &hasIMU) { jc->simple_state.buttons |= ((int) (packet[indexOffset + 8]) << JSOFFSET_L) & JSMASK_L; jc->simple_state.buttons |= ((int) (packet[indexOffset + 9]) << JSOFFSET_PS) & JSMASK_PS; // The DS5 has a mute button that is normally ignored on PC. We can use this. + jc->simple_state.buttons |= ((int) (packet[indexOffset + 9] >> 1) << JSOFFSET_TOUCHPAD_CLICK) & JSMASK_TOUCHPAD_CLICK; jc->simple_state.buttons |= ((int) (packet[indexOffset + 9] >> 2) << JSOFFSET_MIC) & JSMASK_MIC; - jc->simple_state.buttons |= - ((int) (packet[indexOffset + 9] >> 1) << JSOFFSET_TOUCHPAD_CLICK) & JSMASK_TOUCHPAD_CLICK; + jc->simple_state.buttons |= ((int)(packet[indexOffset + 9] >> 4) << JSOFFSET_FNL) & JSMASK_FNL; + jc->simple_state.buttons |= ((int)(packet[indexOffset + 9] >> 5) << JSOFFSET_FNR) & JSMASK_FNR; + jc->simple_state.buttons |= ((int)(packet[indexOffset + 9] >> 6) << JSOFFSET_SL) & JSMASK_SL; + jc->simple_state.buttons |= ((int) (packet[indexOffset + 9] >> 7) << JSOFFSET_SR) & JSMASK_SR; //jc->btns.zr = (packet[indexOffset+6] >> 3) & 1; //jc->btns.zl = (packet[indexOffset+6] >> 2) & 1; jc->simple_state.rTrigger = packet[indexOffset + 5] / 255.0f; diff --git a/project/dependencies/JoyShockLibrary/JoyShockLibrary.h b/project/dependencies/JoyShockLibrary/JoyShockLibrary.h index 101940f..cbfdeb0 100644 --- a/project/dependencies/JoyShockLibrary/JoyShockLibrary.h +++ b/project/dependencies/JoyShockLibrary/JoyShockLibrary.h @@ -17,31 +17,33 @@ #define JS_SPLIT_TYPE_RIGHT 2 #define JS_SPLIT_TYPE_FULL 3 -#define JSMASK_UP 0x00001 -#define JSMASK_DOWN 0x00002 -#define JSMASK_LEFT 0x00004 -#define JSMASK_RIGHT 0x00008 -#define JSMASK_PLUS 0x00010 -#define JSMASK_OPTIONS 0x00010 -#define JSMASK_MINUS 0x00020 -#define JSMASK_SHARE 0x00020 -#define JSMASK_LCLICK 0x00040 -#define JSMASK_RCLICK 0x00080 -#define JSMASK_L 0x00100 -#define JSMASK_R 0x00200 -#define JSMASK_ZL 0x00400 -#define JSMASK_ZR 0x00800 -#define JSMASK_S 0x01000 -#define JSMASK_E 0x02000 -#define JSMASK_W 0x04000 -#define JSMASK_N 0x08000 -#define JSMASK_HOME 0x10000 -#define JSMASK_PS 0x10000 -#define JSMASK_CAPTURE 0x20000 -#define JSMASK_TOUCHPAD_CLICK 0x20000 -#define JSMASK_MIC 0x40000 -#define JSMASK_SL 0x40000 -#define JSMASK_SR 0x80000 +#define JSMASK_UP 0x000001 +#define JSMASK_DOWN 0x000002 +#define JSMASK_LEFT 0x000004 +#define JSMASK_RIGHT 0x000008 +#define JSMASK_PLUS 0x000010 +#define JSMASK_OPTIONS 0x000010 +#define JSMASK_MINUS 0x000020 +#define JSMASK_SHARE 0x000020 +#define JSMASK_LCLICK 0x000040 +#define JSMASK_RCLICK 0x000080 +#define JSMASK_L 0x000100 +#define JSMASK_R 0x000200 +#define JSMASK_ZL 0x000400 +#define JSMASK_ZR 0x000800 +#define JSMASK_S 0x001000 +#define JSMASK_E 0x002000 +#define JSMASK_W 0x004000 +#define JSMASK_N 0x008000 +#define JSMASK_HOME 0x010000 +#define JSMASK_PS 0x010000 +#define JSMASK_CAPTURE 0x020000 +#define JSMASK_TOUCHPAD_CLICK 0x020000 +#define JSMASK_MIC 0x040000 +#define JSMASK_SL 0x080000 +#define JSMASK_SR 0x100000 +#define JSMASK_FNL 0x200000 +#define JSMASK_FNR 0x400000 #define JSOFFSET_UP 0 #define JSOFFSET_DOWN 1 @@ -66,8 +68,10 @@ #define JSOFFSET_CAPTURE 17 #define JSOFFSET_TOUCHPAD_CLICK 17 #define JSOFFSET_MIC 18 -#define JSOFFSET_SL 18 -#define JSOFFSET_SR 19 +#define JSOFFSET_SL 19 +#define JSOFFSET_SR 20 +#define JSOFFSET_FNL 21 +#define JSOFFSET_FNR 22 // PS5 Player maps for the DS Player Lightbar #define DS5_PLAYER_1 4 diff --git a/project/engine.cpp b/project/engine.cpp index b56f09c..1462479 100644 --- a/project/engine.cpp +++ b/project/engine.cpp @@ -1,5 +1,5 @@ #include "engine.h" -#include "win32.h" +//#include "win32.h" NS_ENGINE_BEGIN @@ -109,13 +109,11 @@ b32 input_using_analog() return false; } -internal void -startup() +void startup() { } -internal void -shutdown() +void shutdown() { } @@ -146,17 +144,17 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBu assert( sizeof(EngineState) <= memory->PersistentSize ); state->ToneVolume = 1000; - state->WaveToneHz = 262; + state->WaveToneHz = 120; state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz; state->XOffset = 0; state->YOffset = 0; - #if Build_Debug + #if Build_Debug && 0 { using namespace platform; - char* file_path = __FILE__; + char const* file_path = __FILE__; Debug_FileContent file_content = debug_file_read_content( file_path ); if ( file_content.Size ) { @@ -282,3 +280,4 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBu } NS_ENGINE_END + diff --git a/project/engine.h b/project/engine.h index 6aec9e6..c3623f2 100644 --- a/project/engine.h +++ b/project/engine.h @@ -4,7 +4,7 @@ #pragma once -#include "platform.h" +#include "platform/platform.h" #define NS_ENGINE_BEGIN namespace engine { #define NS_ENGINE_END } @@ -58,8 +58,6 @@ struct DigitalBtn s32 HalfTransitions; b32 EndedDown; }; -#define DigitalBtn_Up 0 -#define DigitalBtn_Down 1 struct AnalogAxis { @@ -197,10 +195,6 @@ struct InputMode void input_mode_pop( InputMode* mode ); void input_mode_pop( InputMode* mode ); -// Needs a contextual reference to four things: -// Timing, Input, Bitmap Buffer, Sound Buffer -void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer, Memory* memory ); - NS_ENGINE_END // TODO(Ed) : Move this to handmade game layer later. diff --git a/project/handmade_win32.cpp b/project/handmade_win32.cpp new file mode 100644 index 0000000..8b6e08a --- /dev/null +++ b/project/handmade_win32.cpp @@ -0,0 +1,16 @@ +#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 + +#if Build_Unity +#include "handmade.cpp" +#include "engine.cpp" +#include "platform/platform_win32.cpp" +#endif diff --git a/project/platform/jsl.h b/project/platform/jsl.h index 577bc95..8e376d7 100644 --- a/project/platform/jsl.h +++ b/project/platform/jsl.h @@ -10,10 +10,10 @@ # pragma warning( disable: 4820 ) #endif -#include "JoyShockLibrary/JoyShockLibrary.h" +#include "dependencies/JoyShockLibrary/JoyShockLibrary.h" #ifdef COMPILER_CLANG # pragma clang diagnostic pop #elif COMPILER_MSVC # pragma warning( pop ) -#endif \ No newline at end of file +#endif diff --git a/project/platform/memory.h b/project/platform/memory.h deleted file mode 100644 index e69de29..0000000 diff --git a/project/platform/platform.h b/project/platform/platform.h index 8bcb0b5..e0c529f 100644 --- a/project/platform/platform.h +++ b/project/platform/platform.h @@ -1,6 +1,8 @@ /* Platform abstraction layer for the project. Services the platform provides to the engine & game. + + This should be the only file the engine or game layer can include */ #pragma once @@ -14,6 +16,10 @@ #pragma warning( disable: 4505 ) // Support for unused static functions #pragma warning( disable: 5045 ) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +// TODO(Ed) : REMOVE THESE WHEN HE GETS TO THEM +#include // TODO : Implement math ourselves +#include // TODO : Implement output logging ourselves + #include "grime.h" #include "macros.h" #include "generics.h" @@ -38,8 +44,29 @@ struct Debug_FileContent }; void debug_file_free_content ( Debug_FileContent* file_content ); -Debug_FileContent debug_file_read_content ( char* file_path ); -b32 debug_file_write_content( char* file_path, u32 content_size, void* content_memory ); +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 ); #endif NS_PLATFORM_END + +// 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 variables for user configuration in settings + +// Returns the current monitor refresh rate. +u32 const get_monitor_refresh_rate(); + +// 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 ); + +u32 const get_engine_frame_rate_target(); + +void set_engine_frame_rate_target( u32 rate_in_hz ); + +#pragma endregion Settings Exposure diff --git a/project/platform/platform_engine_api.h b/project/platform/platform_engine_api.h new file mode 100644 index 0000000..6e227b0 --- /dev/null +++ b/project/platform/platform_engine_api.h @@ -0,0 +1,16 @@ +/* + This represents the API only accessible to the platform layer to fullfill for the engine layer. +*/ +#pragma once +#include "engine.h" + +NS_ENGINE_BEGIN + +void startup(); +void shutdown(); + +// Needs a contextual reference to four things: +// Timing, Input, Bitmap Buffer, Sound Buffer +void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer, Memory* memory ); + +NS_ENGINE_END diff --git a/project/platform/handmade_win32.cpp b/project/platform/platform_win32.cpp similarity index 72% rename from project/platform/handmade_win32.cpp rename to project/platform/platform_win32.cpp index 89aeea0..ff6159a 100644 --- a/project/platform/handmade_win32.cpp +++ b/project/platform/platform_win32.cpp @@ -17,22 +17,6 @@ - GetKeyboardLayout (for French keyboards, international WASD support) */ -#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 // TODO : Implement math ourselves -#include // TODO : Implement output logging ourselves -#include "engine.cpp" - - // Platform Layer headers #include "platform.h" #include "jsl.h" // Using this to get dualsense controllers @@ -41,10 +25,12 @@ // Engine layer headers #include "engine.h" +#include "platform_engine_api.h" // TOOD(Ed): Redo these macros properly later. +#if 1 #define congrats( message ) do { \ JslSetLightColour( 0, (255 << 16) | (215 << 8) ); \ MessageBoxA( 0, message, "Congratulations!", MB_OK | MB_ICONEXCLAMATION ); \ @@ -67,14 +53,11 @@ ensure_impl( bool condition, char const* message ) { MessageBoxA( 0, message, "Fatal Error", MB_OK | MB_ICONERROR ); \ JslSetLightColour( 0, (255 << 8 ) ); \ } while (0) +#endif NS_PLATFORM_BEGIN using namespace win32; -// TODO(Ed) : This is a global for now. -global bool Running; - - struct OffscreenBuffer { BITMAPINFO Info; @@ -93,33 +76,57 @@ struct WinDimensions }; // TODO : This will def need to be looked over. -struct SoundOutput +struct DirectSoundBuffer { - DWORD IsPlaying; - u32 RunningSampleIndex; - s32 LatencySampleCount; + LPDIRECTSOUNDBUFFER SecondaryBuffer; + s16* Samples; + u32 SecondaryBufferSize; + u32 SamplesPerSecond; + u32 BytesPerSample; + + DWORD IsPlaying; + u32 RunningSampleIndex; + u32 LatencySampleCount; }; -// HRESULT WINAPI DirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter ); + +#pragma region Static Data +// TODO(Ed) : This is a global for now. +global bool Running; + +// Max controllers for the platform layer and thus for all other layers is 4. (Sanity and xinput limit) +constexpr u32 Max_Controllers = 4; + +global WinDimensions Window_Dimensions; +global OffscreenBuffer Surface_Back_Buffer; + using DirectSoundCreateFn = HRESULT WINAPI (LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter ); global DirectSoundCreateFn* direct_sound_create; -global OffscreenBuffer BackBuffer; -global WinDimensions WindowDimensions; - -global LPDIRECTSOUNDBUFFER DS_SecondaryBuffer; -global s32 DS_SecondaryBuffer_Size; -global s32 DS_SecondaryBuffer_SamplesPerSecond; -global s32 DS_SecondaryBuffer_BytesPerSample; - -global s16* SoundBufferSamples; - constexpr u64 Tick_To_Millisecond = 1000; constexpr u64 Tick_To_Microsecond = 1000 * 1000; global u64 Performance_Counter_Frequency; - + +// As of 2023 the highest refreshrate on the market is 500 hz. I'll just make this higher if something comes out beyond that... +constexpr u32 Monitor_Refresh_Max_Supported = 500; + +// Anything at or below the high performance frame-time is too low latency to sleep against the window's scheduler. +constexpr f32 High_Perf_Frametime_MS = 1000.f / 240.f; + +global u32 Monitor_Refresh_Hz = 60; +global u32 Engine_Refresh_Hz = Monitor_Refresh_Hz / 2; +global f32 Engine_Frame_Target_MS = 1000.f / scast(f32, Engine_Refresh_Hz); +#pragma endregion Static Data + + #if Build_Debug +struct DebugTimeMarker +{ + DWORD PlayCursor; + DWORD WriteCursor; +}; + void debug_file_free_content( Debug_FileContent* content ) { if ( content->Data) @@ -129,7 +136,7 @@ void debug_file_free_content( Debug_FileContent* content ) } } -Debug_FileContent debug_file_read_content( char* file_path ) +Debug_FileContent debug_file_read_content( char const* file_path ) { Debug_FileContent result {}; @@ -168,7 +175,7 @@ Debug_FileContent debug_file_read_content( char* file_path ) return result; } -b32 debug_file_write_content( char* file_path, u32 content_size, void* content_memory ) +b32 debug_file_write_content( char const* file_path, u32 content_size, void* content_memory ) { HANDLE file_handle = CreateFileA( file_path , GENERIC_WRITE, 0, 0 @@ -190,6 +197,54 @@ b32 debug_file_write_content( char* file_path, u32 content_size, void* content_m CloseHandle( file_handle ); return true; } + +internal void +debug_draw_vertical( u32 x_pos, u32 top, u32 bottom, u32 color ) +{ + u8* + pixel_byte = rcast(u8*, Surface_Back_Buffer.Memory); + pixel_byte += x_pos * Surface_Back_Buffer.BytesPerPixel; + pixel_byte += top * Surface_Back_Buffer.Pitch; + + for ( u32 y = top; y < bottom; ++ y ) + { + u32* pixel = rcast(u32*, pixel_byte); + *pixel = color; + + pixel_byte += Surface_Back_Buffer.Pitch; + } +} + +inline void +debug_draw_sound_buffer_marker( DirectSoundBuffer* sound_buffer, f32 coefficient + , u32 pad_x, u32 pad_y + , u32 top, u32 bottom + , DWORD value, u32 color ) +{ + assert( value < sound_buffer->SecondaryBufferSize ); + u32 x = pad_x + scast(u32, coefficient * scast(f32, value )); + debug_draw_vertical( x, top, bottom, color ); +} + +internal void +debug_sync_display( DirectSoundBuffer* sound_buffer + , u32 num_markers, DebugTimeMarker* markers + , f32 ms_per_frame ) +{ + u32 pad_x = 16; + u32 pad_y = 16; + f32 coefficient = scast(f32, Surface_Back_Buffer.Width) / scast(f32, sound_buffer->SecondaryBufferSize); + + u32 top = pad_y; + u32 bottom = Surface_Back_Buffer.Height - pad_y; + + for ( u32 marker_index = 0; marker_index < num_markers; ++ marker_index ) + { + DebugTimeMarker* marker = & markers[marker_index]; + debug_draw_sound_buffer_marker( sound_buffer, coefficient, pad_x, pad_y, top, bottom, marker->PlayCursor, 0xFFFFFFFF ); + debug_draw_sound_buffer_marker( sound_buffer, coefficient, pad_x, pad_y, top, bottom, marker->WriteCursor, 0xFFFF0000 ); + } +} #endif inline u64 @@ -205,6 +260,7 @@ timing_get_seconds_elapsed( u64 start, u64 end ) { u64 delta = end - start; f32 result = scast(f32, delta) / scast(f32, Performance_Counter_Frequency); + return result; } inline f32 @@ -269,16 +325,13 @@ input_process_axis_value( f32 value, f32 deadzone_threshold ) } internal void -input_process_keyboard_key( engine::DigitalBtn* key, b32 is_down ) +poll_input( engine::InputState* input ) { - // This assert fails all the time, have no idea why. I'm just going to use GetAsyncKeyState instead, using the messaging events is horrible. - // assert( key->EndedDown != is_down ) - key->EndedDown = is_down; - key->HalfTransitions += is_down; + } internal void -init_sound(HWND window_handle, s32 samples_per_second, s32 buffer_size ) +init_sound(HWND window_handle, DirectSoundBuffer* sound_buffer ) { // Load library HMODULE sound_library = LoadLibraryA( "dsound.dll" ); @@ -313,7 +366,7 @@ init_sound(HWND window_handle, s32 samples_per_second, s32 buffer_size ) wave_format {}; wave_format.wFormatTag = WAVE_FORMAT_PCM; /* format type */ wave_format.nChannels = 2; /* number of channels (i.e. mono, stereo...) */ - wave_format.nSamplesPerSec = scast(u32, samples_per_second); /* sample rate */ + wave_format.nSamplesPerSec = scast(u32, sound_buffer->SamplesPerSecond); /* sample rate */ wave_format.wBitsPerSample = 16; /* number of bits per sample of mono data */ wave_format.nBlockAlign = wave_format.nChannels * wave_format.wBitsPerSample / 8 ; /* block size of data */ wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign; /* for buffer estimation */ @@ -338,29 +391,29 @@ init_sound(HWND window_handle, s32 samples_per_second, s32 buffer_size ) DSBUFFERDESC buffer_description { sizeof(buffer_description) }; - buffer_description.dwFlags = 0; - buffer_description.dwBufferBytes = buffer_size; + buffer_description.dwFlags = DSBCAPS_GETCURRENTPOSITION2; + buffer_description.dwBufferBytes = sound_buffer->SecondaryBufferSize; buffer_description.lpwfxFormat = & wave_format; - if ( ! SUCCEEDED( direct_sound->CreateSoundBuffer( & buffer_description, & DS_SecondaryBuffer, 0 ) )) + if ( ! SUCCEEDED( direct_sound->CreateSoundBuffer( & buffer_description, & sound_buffer->SecondaryBuffer, 0 ) )) { // TODO : Diagnostic } - if ( ! SUCCEEDED( DS_SecondaryBuffer->SetFormat( & wave_format ) ) ) + if ( ! SUCCEEDED( sound_buffer->SecondaryBuffer->SetFormat( & wave_format ) ) ) { // TODO : Diagnostic } } internal void -ds_clear_sound_buffer( SoundOutput* sound_output ) +ds_clear_sound_buffer( DirectSoundBuffer* sound_buffer ) { LPVOID region_1; DWORD region_1_size; LPVOID region_2; DWORD region_2_size; - HRESULT ds_lock_result = DS_SecondaryBuffer->Lock( 0, DS_SecondaryBuffer_Size + HRESULT ds_lock_result = sound_buffer->SecondaryBuffer->Lock( 0, sound_buffer->SecondaryBufferSize , & region_1, & region_1_size , & region_2, & region_2_size , 0 ); @@ -383,21 +436,21 @@ ds_clear_sound_buffer( SoundOutput* sound_output ) ++ sample_out; } - if ( ! SUCCEEDED( DS_SecondaryBuffer->Unlock( region_1, region_1_size, region_2, region_2_size ) )) + if ( ! SUCCEEDED( sound_buffer->SecondaryBuffer->Unlock( region_1, region_1_size, region_2, region_2_size ) )) { return; } } internal void -ds_fill_sound_buffer( SoundOutput* sound_output, DWORD byte_to_lock, DWORD bytes_to_write, engine::SoundBuffer* sound_buffer ) +ds_fill_sound_buffer( DirectSoundBuffer* sound_buffer, DWORD byte_to_lock, DWORD bytes_to_write ) { LPVOID region_1; DWORD region_1_size; LPVOID region_2; DWORD region_2_size; - HRESULT ds_lock_result = DS_SecondaryBuffer->Lock( byte_to_lock, bytes_to_write + HRESULT ds_lock_result = sound_buffer->SecondaryBuffer->Lock( byte_to_lock, bytes_to_write , & region_1, & region_1_size , & region_2, & region_2_size , 0 ); @@ -408,7 +461,7 @@ ds_fill_sound_buffer( SoundOutput* sound_output, DWORD byte_to_lock, DWORD bytes // TODO : Assert that region sizes are valid - DWORD region_1_sample_count = region_1_size / DS_SecondaryBuffer_BytesPerSample; + DWORD region_1_sample_count = region_1_size / sound_buffer->BytesPerSample; s16* sample_out = rcast( s16*, region_1 ); s16* sample_in = sound_buffer->Samples; for ( DWORD sample_index = 0; sample_index < region_1_sample_count; ++ sample_index ) @@ -421,10 +474,10 @@ ds_fill_sound_buffer( SoundOutput* sound_output, DWORD byte_to_lock, DWORD bytes ++ sample_out; ++ sample_in; - ++ sound_output->RunningSampleIndex; + ++ sound_buffer->RunningSampleIndex; } - DWORD region_2_sample_count = region_2_size / DS_SecondaryBuffer_BytesPerSample; + DWORD region_2_sample_count = region_2_size / sound_buffer->BytesPerSample; sample_out = rcast( s16*, region_2 ); for ( DWORD sample_index = 0; sample_index < region_2_sample_count; ++ sample_index ) { @@ -436,10 +489,10 @@ ds_fill_sound_buffer( SoundOutput* sound_output, DWORD byte_to_lock, DWORD bytes ++ sample_out; ++ sample_in; - ++ sound_output->RunningSampleIndex; + ++ sound_buffer->RunningSampleIndex; } - if ( ! SUCCEEDED( DS_SecondaryBuffer->Unlock( region_1, region_1_size, region_2, region_2_size ) )) + if ( ! SUCCEEDED( sound_buffer->SecondaryBuffer->Unlock( region_1, region_1_size, region_2, region_2_size ) )) { return; } @@ -512,12 +565,10 @@ display_buffer_in_window( HDC device_context, u32 window_width, u32 window_heigh } internal LRESULT CALLBACK -main_window_callback( - HWND handle, - UINT system_messages, - WPARAM w_param, - LPARAM l_param -) +main_window_callback( HWND handle + , UINT system_messages + , WPARAM w_param + , LPARAM l_param ) { LRESULT result = 0; @@ -554,7 +605,7 @@ main_window_callback( WinDimensions dimensions = get_window_dimensions( handle ); - display_buffer_in_window( device_context, dimensions.Width, dimensions.Height, &BackBuffer + display_buffer_in_window( device_context, dimensions.Width, dimensions.Height, &Surface_Back_Buffer , x, y , width, height ); EndPaint( handle, & info ); @@ -617,16 +668,10 @@ process_pending_window_messages( engine::KeyboardState* keyboard ) } } } - NS_PLATFORM_END int CALLBACK -WinMain( - HINSTANCE instance, - HINSTANCE prev_instance, - LPSTR commandline, - int show_command -) +WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int show_command ) { using namespace win32; using namespace platform; @@ -637,20 +682,12 @@ WinMain( u64 launch_cycle = __rdtsc(); #endif - // TODO(Ed): Make this more flexible later - f32 monitor_refresh_hz = 165.f; - f32 engine_update_hz - // = monitor_refresh_hz / 2.f; - = monitor_refresh_hz; - f32 engine_frame_target_ms = 1000.f / engine_update_hz; - // Sets the windows scheduler granulaity for this process to 1 ms - u32 desired_scheduler_ms = 1; + constexpr u32 desired_scheduler_ms = 1; b32 sleep_is_granular = ( timeBeginPeriod( desired_scheduler_ms ) == TIMERR_NOERROR ); - - // Anything at or below the high performance frame-time is too low latency to sleep against the window's scheduler. - f32 high_perf_frametime_ms = 1000.f / 120.f; - b32 sub_ms_granularity_required = engine_frame_target_ms <= high_perf_frametime_ms; + + // If its a high-perofmrance frame-time (a refresh rate that produces a target frametime at or below 4.16~ ms, we cannot allow the scheduler to mess things up) + b32 sub_ms_granularity_required = scast(f32, Engine_Refresh_Hz) <= High_Perf_Frametime_MS; QueryPerformanceFrequency( rcast(LARGE_INTEGER*, & Performance_Counter_Frequency) ); @@ -666,13 +703,12 @@ WinMain( + engine_memory.TransientSize; #if Build_Debug - void* Base_Address = rcast(void*, terabytes( 1 )); + void* base_address = rcast(void*, terabytes( 1 )); #else - void* Base_Address = 0; + void* base_address = 0; #endif - engine_memory.Persistent = VirtualAlloc( Base_Address, total_size - , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ); + engine_memory.Persistent = VirtualAlloc( base_address, total_size , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ); engine_memory.Transient = rcast( u8*, engine_memory.Persistent ) + engine_memory.PersistentSize; if ( engine_memory.Persistent == nullptr @@ -721,33 +757,49 @@ WinMain( } } // WinDimensions dimensions = get_window_dimensions( window_handle ); - resize_dib_section( &BackBuffer, 1280, 720 ); + resize_dib_section( &Surface_Back_Buffer, 1280, 720 ); - SoundOutput sound_output; + DWORD last_play_cursor = 0; + b32 sound_is_valid = false; + DirectSoundBuffer ds_sound_buffer; { - sound_output.IsPlaying = 0; - DS_SecondaryBuffer_SamplesPerSecond = 48000; - DS_SecondaryBuffer_BytesPerSample = sizeof(s16) * 2; + ds_sound_buffer.IsPlaying = 0; + ds_sound_buffer.SamplesPerSecond = 48000; + ds_sound_buffer.BytesPerSample = sizeof(s16) * 2; - DS_SecondaryBuffer_Size = DS_SecondaryBuffer_SamplesPerSecond * DS_SecondaryBuffer_BytesPerSample; - init_sound( window_handle, DS_SecondaryBuffer_SamplesPerSecond, DS_SecondaryBuffer_Size ); + ds_sound_buffer.SecondaryBufferSize = ds_sound_buffer.SamplesPerSecond * ds_sound_buffer.BytesPerSample; + init_sound( window_handle, & ds_sound_buffer ); - SoundBufferSamples = rcast( s16*, VirtualAlloc( 0, 48000 * 2 * sizeof(s16) + ds_sound_buffer.Samples = rcast( s16*, VirtualAlloc( 0, 48000 * 2 * sizeof(s16) , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write )); - assert( SoundBufferSamples ); - - sound_output.RunningSampleIndex = 0; - sound_output.LatencySampleCount = DS_SecondaryBuffer_SamplesPerSecond / 15; + assert( ds_sound_buffer.Samples ); + ds_sound_buffer.RunningSampleIndex = 0; // ds_clear_sound_buffer( & sound_output ); - DS_SecondaryBuffer->Play( 0, 0, DSBPLAY_LOOPING ); - } + ds_sound_buffer.SecondaryBuffer->Play( 0, 0, DSBPLAY_LOOPING ); - constexpr u32 Max_Controllers = 4; - // Max controllers for the platform layer and thus for all other layers is 4. (Sanity and xinput limit) + // Direct sound requires 3 frames of audio latency for no bugs to show u + constexpr u32 frames_of_audio_latency = 3; + ds_sound_buffer.LatencySampleCount = frames_of_audio_latency * ( ds_sound_buffer.SamplesPerSecond / Engine_Refresh_Hz ); + } +#if Build_Development + u32 debug_marker_index = 0; + DebugTimeMarker debug_markers[ Monitor_Refresh_Max_Supported ] {}; + u32 debug_marker_history_size = Engine_Refresh_Hz / 2; + assert( debug_marker_history_size <= Monitor_Refresh_Max_Supported ) +#endif engine::InputState input {}; + // There can be 4 of any of each input API type : KB & Mouse, XInput, JSL. + +#if 0 + using EngineKeyboardStates = engine::KeyboardState[ Max_Controllers ]; + EngineKeyboardStates keyboard_states[2] {}; + EngineKeyboardStates* old_keyboards = & keyboard_states[0]; + EngineKeyboardStates* new_keyboards = & keyboard_states[1]; +#endif + engine::KeyboardState keyboard_states[2] {}; engine::KeyboardState* old_keyboard = & keyboard_states[0]; engine::KeyboardState* new_keyboard = & keyboard_states[1]; @@ -801,14 +853,37 @@ WinMain( f32 startup_ms = timing_get_ms_elapsed( launch_clock, last_frame_clock ); #endif + Running = true; +#if 0 +// This tests the play & write cursor update frequency. + while ( Running ) + { + DWORD play_cursor; + DWORD write_cursor; + + ds_sound_buffer.SecondaryBuffer->GetCurrentPosition( & play_cursor, & write_cursor ); + char text_buffer[256]; + sprintf_s( text_buffer, sizeof(text_buffer), "PC:%u WC:%u\n", (u32)play_cursor, (u32)write_cursor ); + OutputDebugStringA( text_buffer ); + } +#endif while( Running ) { process_pending_window_messages( new_keyboard ); + // TODO(Ed): Offload polling to these functions later. + // poll_xinput( & input, old_xpads, new_xpads ); + // poll_jsl( & input, old_jsl_pads, new_jsl_pads ); + + // or + // poll_input(); + // Input - // TODO(Ed) : Setup user definable deadzones for triggers and sticks. + // void poll_input(); { + // TODO(Ed) : Setup user definable deadzones for triggers and sticks. + // Swapping at the beginning of the input frame instead of the end. swap( old_keyboard, new_keyboard ); swap( old_xpads, new_xpads ); @@ -941,21 +1016,21 @@ WinMain( } // Pain... - b32 sound_is_valid = false; - DWORD ds_play_cursor; - DWORD ds_write_cursor; + // DWORD ds_play_cursor; + // DWORD ds_write_cursor; DWORD byte_to_lock = 0; DWORD bytes_to_write = 0; - if ( SUCCEEDED( DS_SecondaryBuffer->GetCurrentPosition( & ds_play_cursor, & ds_write_cursor ) )) + DWORD target_cursor = 0; + // if ( SUCCEEDED( ds_sound_buffer.SecondaryBuffer->GetCurrentPosition( & ds_play_cursor, & ds_write_cursor ) )) + if ( sound_is_valid ) { - - byte_to_lock = (sound_output.RunningSampleIndex * DS_SecondaryBuffer_BytesPerSample) % DS_SecondaryBuffer_Size; - DWORD target_cursor = (ds_play_cursor + (sound_output.LatencySampleCount * DS_SecondaryBuffer_BytesPerSample)) % DS_SecondaryBuffer_Size; + byte_to_lock = (ds_sound_buffer.RunningSampleIndex * ds_sound_buffer.BytesPerSample) % ds_sound_buffer.SecondaryBufferSize; + target_cursor = (last_play_cursor + (ds_sound_buffer.LatencySampleCount * ds_sound_buffer.BytesPerSample)) % ds_sound_buffer.SecondaryBufferSize; if ( byte_to_lock > target_cursor) { // Infront of play cursor |--play--byte_to_write-->--| - bytes_to_write = DS_SecondaryBuffer_Size - byte_to_lock; + bytes_to_write = ds_sound_buffer.SecondaryBufferSize - byte_to_lock; bytes_to_write += target_cursor; } else @@ -963,40 +1038,72 @@ WinMain( // Behind play cursor |--byte_to_write-->--play--| bytes_to_write = target_cursor - byte_to_lock; } - - sound_is_valid = true; + // sound_is_valid = true; } // s16 samples[ 48000 * 2 ]; engine::SoundBuffer sound_buffer {}; - sound_buffer.NumSamples = bytes_to_write / DS_SecondaryBuffer_BytesPerSample; - sound_buffer.RunningSampleIndex = sound_output.RunningSampleIndex; - sound_buffer.SamplesPerSecond = DS_SecondaryBuffer_SamplesPerSecond; - sound_buffer.Samples = SoundBufferSamples; + sound_buffer.NumSamples = bytes_to_write / ds_sound_buffer.BytesPerSample; + sound_buffer.RunningSampleIndex = ds_sound_buffer.RunningSampleIndex; + sound_buffer.SamplesPerSecond = ds_sound_buffer.SamplesPerSecond; + sound_buffer.Samples = ds_sound_buffer.Samples; - engine::update_and_render( & input, rcast(engine::OffscreenBuffer*, & BackBuffer.Memory), & sound_buffer, & engine_memory ); + engine::update_and_render( & input, rcast(engine::OffscreenBuffer*, & Surface_Back_Buffer.Memory), & sound_buffer, & engine_memory ); + + // Update audio buffer + do { + DWORD ds_status = 0; + if ( SUCCEEDED( ds_sound_buffer.SecondaryBuffer->GetStatus( & ds_status ) ) ) + { + ds_sound_buffer.IsPlaying = ds_status & DSBSTATUS_PLAYING; + } + + if ( ! sound_is_valid ) + break; + + ds_fill_sound_buffer( & ds_sound_buffer, byte_to_lock, bytes_to_write ); + + #if Build_Development && 0 + DWORD play_cursor; + DWORD write_cursor; + + ds_sound_buffer.SecondaryBuffer->GetCurrentPosition( & play_cursor, & write_cursor ); + char text_buffer[256]; + sprintf_s( text_buffer, sizeof(text_buffer), "LPC:%u BTL:%u TC:%u BTW:%u - PC:%u WC:%u\n" + , (u32)last_play_cursor, (u32)byte_to_lock, (u32)target_cursor, (u32)bytes_to_write, (u32)play_cursor, (u32)write_cursor ); + OutputDebugStringA( text_buffer ); + #endif + + if ( ds_sound_buffer.IsPlaying ) + break; + + ds_sound_buffer.SecondaryBuffer->Play( 0, 0, DSBPLAY_LOOPING ); + } while(0); u64 work_frame_end_cycle = __rdtsc(); u64 work_frame_end_clock = timing_get_wall_clock(); - f32 work_frame_ms = timing_get_ms_elapsed( last_frame_clock, work_frame_end_clock ); + f32 work_frame_ms = timing_get_ms_elapsed( last_frame_clock, work_frame_end_clock ); // WorkSecondsElapsed f32 work_cycles = timing_get_ms_elapsed( last_frame_cycle, work_frame_end_cycle ); - f32 frame_elapsed_ms = work_frame_ms; - if ( frame_elapsed_ms < engine_frame_target_ms ) + f32 frame_elapsed_ms = work_frame_ms; // SecondsElapsedForFrame + if ( frame_elapsed_ms < Engine_Frame_Target_MS ) { - - DWORD sleep_ms = scast(DWORD, (engine_frame_target_ms - frame_elapsed_ms)) - 1; - if ( ! sub_ms_granularity_required && sleep_is_granular ) + s32 sleep_ms = scast(DWORD, (Engine_Frame_Target_MS - frame_elapsed_ms)) - 1; + if ( sleep_ms > 0 && ! sub_ms_granularity_required && sleep_is_granular ) { - Sleep( sleep_ms ); + Sleep( scast(DWORD, sleep_ms) ); } u64 frame_clock = timing_get_wall_clock(); frame_elapsed_ms = timing_get_ms_elapsed( last_frame_clock, frame_clock ); - - assert( frame_elapsed_ms < engine_frame_target_ms ); - while ( frame_elapsed_ms < engine_frame_target_ms ) + if ( frame_elapsed_ms < Engine_Frame_Target_MS ) + { + // TODO(Ed) : Log ms discrepancy here. + } + + assert( frame_elapsed_ms < Engine_Frame_Target_MS ); + while ( frame_elapsed_ms < Engine_Frame_Target_MS ) { frame_clock = timing_get_wall_clock(); frame_elapsed_ms = timing_get_ms_elapsed( last_frame_clock, frame_clock ); @@ -1007,40 +1114,54 @@ WinMain( // TODO(Ed) : Missed the display sync window! } - // Update audio buffer - do { - DWORD ds_status = 0; - if ( SUCCEEDED( DS_SecondaryBuffer->GetStatus( & ds_status ) ) ) - { - sound_output.IsPlaying = ds_status & DSBSTATUS_PLAYING; - } + last_frame_clock = timing_get_wall_clock(); // LastCouner + last_frame_cycle = __rdtsc(); - if ( ! sound_is_valid ) - break; - - ds_fill_sound_buffer( & sound_output, byte_to_lock, bytes_to_write, & sound_buffer ); - - if ( sound_output.IsPlaying ) - break; - - DS_SecondaryBuffer->Play( 0, 0, DSBPLAY_LOOPING ); - } while(0); - - // Update framebuffer + // Update surface back buffer { WinDimensions dimensions = get_window_dimensions( window_handle ); HDC device_context = GetDC( window_handle ); - display_buffer_in_window( device_context, dimensions.Width, dimensions.Height, &BackBuffer + + #if Build_Development + debug_sync_display( & ds_sound_buffer, debug_marker_history_size, debug_markers, Engine_Frame_Target_MS ); + #endif + + display_buffer_in_window( device_context, dimensions.Width, dimensions.Height, &Surface_Back_Buffer , 0, 0 , dimensions.Width, dimensions.Height ); } - printf("%f\n", frame_elapsed_ms ); + { + DWORD play_cursor = 0; + DWORD write_cursor = 0; - last_frame_clock = timing_get_wall_clock(); - last_frame_cycle = __rdtsc(); + if ( SUCCEEDED( ds_sound_buffer.SecondaryBuffer->GetCurrentPosition( & play_cursor, & write_cursor ) ) ) + { + last_play_cursor = play_cursor; + if ( ! sound_is_valid ) + { + ds_sound_buffer.RunningSampleIndex = write_cursor / ds_sound_buffer.BytesPerSample; + sound_is_valid = true; + } + } + else + { + sound_is_valid = false; + } + + #if Build_Development + assert( debug_marker_index < debug_marker_history_size ) + debug_markers[debug_marker_index] = { play_cursor, write_cursor }; + debug_marker_index++; + + if ( debug_marker_index >= debug_marker_history_size ) + debug_marker_index = 0; + #endif + } } + engine::shutdown(); + if ( jsl_num_devices > 0 ) { for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index ) diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 81dfd68..d0e33e7 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -1,8 +1,10 @@ Clear-Host -Import-Module ./helpers/target_arch.psm1 -$devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1' -$path_root = git rev-parse --show-toplevel +$target_arch = Join-Path $PSScriptRoot 'helpers/target_arch.psm1' +$devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1' +$path_root = git rev-parse --show-toplevel + +Import-Module $target_arch Push-Location $path_root @@ -30,8 +32,7 @@ if ( $args ) { $args | ForEach-Object { #region Configuration if ($IsWindows) { - # This library was really designed to only run on 64-bit systems. - # (Its a development tool after all) + # This HandmadeHero implementation is only designed for 64-bit systems & $devshell -arch amd64 } @@ -154,12 +155,14 @@ if ( $vendor -match "clang" ) $flag_warnings_as_errors = '-Werror' $flag_win_nologo = '/nologo' - $ignore_warning_ms_include = 'no-microsoft-include' + $ignore_warning_ms_include = 'no-microsoft-include' + $ignore_warning_return_type_c_linkage = 'no-return-type-c-linkage' $target_arch = Get-TargetArchClang $warning_ignores = @( - $ignore_warning_ms_include + $ignore_warning_ms_include, + $ignore_warning_return_type_c_linkage ) # https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170 @@ -216,7 +219,7 @@ if ( $vendor -match "clang" ) if ( $debug ) { $linker_args += $flag_link_win_debug $linker_args += $flag_link_win_pdb + $pdb - $linker_args += $flag_link_mapfile + $map + # $linker_args += $flag_link_mapfile + $map } $libraries | ForEach-Object { @@ -338,7 +341,7 @@ if ( $vendor -match "msvc" ) if ( $debug ) { $linker_args += $flag_link_win_debug $linker_args += $flag_link_win_pdb + $pdb - $linker_args += $flag_link_mapfile + $map + # $linker_args += $flag_link_mapfile + $map } else { } @@ -376,7 +379,7 @@ if ( (Test-Path $path_deps) -eq $false ) { $includes = @( $path_project, $path_gen, - $path_deps, + # $path_deps, $path_platform ) $compiler_args = @() @@ -420,8 +423,8 @@ $lib_winmm = 'Winmm.lib' # Github $lib_jsl = Join-Path $path_deps 'JoyShockLibrary/x64/JoyShockLibrary.lib' -$unit = Join-Path $path_platform 'handmade_win32.cpp' -$executable = Join-Path $path_build 'handmade_win32.exe' +$unit = Join-Path $path_project 'handmade_win32.cpp' +$executable = Join-Path $path_build 'handmade_win32.exe' $stack_size = 1024 * 1024 * 4 @@ -434,6 +437,9 @@ $compiler_args = @( $flag_optimize_intrinsics ($flag_define + 'Build_DLL=0' ) + + # For now this script only supports unity builds... (for the full binary) + ($flag_define + 'Build_Unity=1' ) ) if ( $dev ) { diff --git a/scripts/clean.ps1 b/scripts/clean.ps1 index 7e45057..6b3630e 100644 --- a/scripts/clean.ps1 +++ b/scripts/clean.ps1 @@ -5,6 +5,6 @@ $path_project = join-path $path_root "project" $path_build = join-path $path_root "build" $path_dependencies = join-path $path_project "dependencies" -if ( Test-Path $path_project ) { - Remove-Item $path_build -Recurse +if ( Test-Path $path_build ) { + Remove-Item -verbose $path_build -Recurse } diff --git a/scripts/handmade.rdbg b/scripts/handmade.rdbg index fb5812db633818f4eb8138aab5e9ba7a7929848e..64c7312e5ac9e39d61064b357475f152ab490c91 100644 GIT binary patch literal 811 zcmb_b&r8EF6z)8zAc{vXLOi)KoVebKC+Ck{L{X1{kfpD)E=^*ZGX3v;={nmEDIOMh z@bU4z?|UyHFSj=jS3wX=B5JJu0O4{v)f+|QDGyG3KsClYjgmP2|2Uv$#OKle{u{;Bo<@-qF62Krn zM!e!da+5=h96@e9MikwZhU~swvMyqEX#W&^qJ-`t%u#%`|)>&zI3!50J2LV>^mI#ZMrS&QN+QM{4*@*>Aq zBo8}WWE2o!jRe<=L@BedHH6AIH6Jvz_H-FP>XFo#lbqCSpL&P7Ww}CS+%yuU3<_)_ zwuq=?joiyO-0r~8=zuz$%;CIGzjK!P;If$~$?}KfO?Y-zM&1s$*{!kTx;#@0{*2So zfDMwu7n6T3&t%7H?THCT^=D}O*- zx`=iwfE!_;op^|^5$QraE&r;Qmht3eD&F_1E6&u56aN$T`2GIDzQ&)&D;pxF?^1V9 JBa3h2=m(4?vRD8B diff --git a/scripts/rebuild.ps1 b/scripts/rebuild.ps1 new file mode 100644 index 0000000..0ebc7b7 --- /dev/null +++ b/scripts/rebuild.ps1 @@ -0,0 +1 @@ +Clear-Host