Day 19 complete

This commit is contained in:
Edward R. Gonzalez 2023-09-23 21:03:33 -04:00
parent e0463670c9
commit 5cfbc204a7
20 changed files with 554 additions and 228 deletions

View File

@ -8,10 +8,10 @@
<ShowEmptyFolders>true</ShowEmptyFolders> <ShowEmptyFolders>true</ShowEmptyFolders>
<IsVirtual>false</IsVirtual> <IsVirtual>false</IsVirtual>
<IsFolder>false</IsFolder> <IsFolder>false</IsFolder>
<BuildCommand>pwsh $(WorkspaceDirectory)/scripts/build.ps1 msvc dev debug</BuildCommand> <BuildCommand>pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(WorkspaceDirectory)/scripts/build.ps1 msvc dev optimized</BuildCommand>
<RebuildCommand>pwsh $(WorkspaceDirectory)/scripts/clean.ps1; $(WorkspaceDirectory)scripts/build.ps1 msvc dev debug</RebuildCommand> <RebuildCommand></RebuildCommand>
<BuildFileCommand></BuildFileCommand> <BuildFileCommand></BuildFileCommand>
<CleanCommand>pwsh $(WorkspaceDirectory)/scripts/clean.ps1</CleanCommand> <CleanCommand>pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(WorkspaceDirectory)/scripts/clean.ps1</CleanCommand>
<BuildWorkingDirectory></BuildWorkingDirectory> <BuildWorkingDirectory></BuildWorkingDirectory>
<CancelBuild></CancelBuild> <CancelBuild></CancelBuild>
<RunCommand>$(WorkspaceDirectory)/build/handmade_win32.exe</RunCommand> <RunCommand>$(WorkspaceDirectory)/build/handmade_win32.exe</RunCommand>
@ -19,10 +19,10 @@
<DebugCommand>$(WorkspaceDirectory)/build/handmade_win32.exe</DebugCommand> <DebugCommand>$(WorkspaceDirectory)/build/handmade_win32.exe</DebugCommand>
<ExePathCommand>$(WorkspaceDirectory)/build/handmade_win32.exe</ExePathCommand> <ExePathCommand>$(WorkspaceDirectory)/build/handmade_win32.exe</ExePathCommand>
<DebugSln></DebugSln> <DebugSln></DebugSln>
<UseVisualStudioEnvBat>false</UseVisualStudioEnvBat> <UseVisualStudioEnvBat>true</UseVisualStudioEnvBat>
<Configurations> <Configurations>
<Configuration>Dev Optimzied</Configuration> <Configuration>Dev Optimzied</Configuration>
<Configuration>Dev </Configuration> <Configuration>Dev</Configuration>
<Configuration>Optimized</Configuration> <Configuration>Optimized</Configuration>
</Configurations> </Configurations>
<Platforms> <Platforms>
@ -31,11 +31,11 @@
<AdditionalIncludePaths> <AdditionalIncludePaths>
<AdditionalIncludePath>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include</AdditionalIncludePath> <AdditionalIncludePath>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\VS\include</AdditionalIncludePath> <AdditionalIncludePath>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\VS\include</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt</AdditionalIncludePath> <AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um</AdditionalIncludePath> <AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\um</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared</AdditionalIncludePath> <AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\shared</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt</AdditionalIncludePath> <AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041..0\\winrt</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt</AdditionalIncludePath> <AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\cppwinrt</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um</AdditionalIncludePath> <AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um</AdditionalIncludePath>
</AdditionalIncludePaths> </AdditionalIncludePaths>
<Defines> <Defines>
@ -51,10 +51,28 @@
<Defines></Defines> <Defines></Defines>
<ForceIncludes></ForceIncludes> <ForceIncludes></ForceIncludes>
</ConfigAndPlatform> </ConfigAndPlatform>
<ConfigAndPlatform>
<Name>Dev :x64</Name>
<Defines></Defines>
<ForceIncludes></ForceIncludes>
</ConfigAndPlatform>
<ConfigAndPlatform>
<Name>Dev Optimzied:x64</Name>
<Defines></Defines>
<ForceIncludes></ForceIncludes>
</ConfigAndPlatform>
<Config> <Config>
<Name>Debug</Name> <Name>Debug</Name>
<Defines></Defines> <Defines></Defines>
</Config> </Config>
<Config>
<Name>Dev</Name>
<Defines></Defines>
</Config>
<Config>
<Name>Dev Optimzied</Name>
<Defines></Defines>
</Config>
<Platform> <Platform>
<Name>x64</Name> <Name>x64</Name>
<Defines></Defines> <Defines></Defines>

20
HandmadeHero.sln Normal file
View File

@ -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

70
HandmadeHero.vcxproj Normal file
View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>{E1CF01B8-BB9F-42F4-9EDB-9F1274D3685A}</ProjectGuid>
<RootNamespace>HandmadeHero</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>HandmadeHero</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<!-- Development Configuration for x64 -->
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Development|x64">
<Configuration>Development</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Development|x64'">
<IncludePath>$(ProjectDir)project;$(IncludePath)</IncludePath>
<LibraryPath>$(ProjectDir)data;$(windir)System32;$(LibraryPath)</LibraryPath>
<NMakeBuildCommandLine>pwsh -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(ProjectDir)scripts\build.ps1 msvc dev</NMakeBuildCommandLine>
<NMakeCleanCommandLine>pwsh ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(ProjectDir)scripts\clean.ps1</NMakeCleanCommandLine>
<NMakePreprocessorDefinitions>GEN_TIME;Build_Development;Build_Debug;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
<ExternalIncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath)</ExternalIncludePath>
</PropertyGroup>
<ItemGroup>
<ClInclude Include="project\engine.h" />
<ClInclude Include="project\platform\generics.h" />
<ClInclude Include="project\platform\grime.h" />
<ClInclude Include="project\platform\jsl.h" />
<ClInclude Include="project\platform\macros.h" />
<ClInclude Include="project\platform\math_constants.h" />
<ClInclude Include="project\platform\platform.h" />
<ClInclude Include="project\platform\platform_engine_api.h" />
<ClInclude Include="project\platform\types.h" />
<ClInclude Include="project\platform\win32.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="project\engine.cpp" />
<ClCompile Include="project\handmade.cpp" />
<ClCompile Include="project\handmade_win32.cpp" />
<ClCompile Include="project\platform\platform_win32.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="docs\Day 001.md" />
<None Include="docs\Day 002.md" />
<None Include="docs\Day 003.md" />
<None Include="docs\Day 004.md" />
<None Include="docs\Day 011.md" />
<None Include="docs\Day 012.md" />
<None Include="docs\Day 013.md" />
<None Include="docs\Day 014.md" />
<None Include="docs\Day 015.md" />
<None Include="docs\Day 016.md" />
<None Include="docs\Day 017.md" />
<None Include="docs\Day 019.md" />
<None Include="scripts\build.ps1" />
<None Include="scripts\clean.ps1" />
<None Include="scripts\helpers\devshell.ps1" />
<None Include="scripts\helpers\target_arch.psm1" />
<None Include="scripts\update_deps.ps1" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Development|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Targets" />
</Project>

11
HandmadeHero.vcxproj.user Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ShowAllFiles>true</ShowAllFiles>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Development|x64'">
<LocalDebuggerWorkingDirectory>$(ProjectDir)data</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommand>$(ProjectDir)build\handmade_win32.exe</LocalDebuggerCommand>
</PropertyGroup>
</Project>

View File

@ -25,5 +25,5 @@ The build is done in two stages:
## Gallery ## Gallery
![img](https://files.catbox.moe/fwjm1m.png) ![img](https://files.catbox.moe/xyh7u7.png)
![img](https://files.catbox.moe/b7ifa8.png) ![img](https://files.catbox.moe/b7ifa8.png)

20
docs/Day 019.md Normal file
View File

@ -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"

View File

@ -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 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] >> 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] >> 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] >> 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] >> 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] >> 7) << JSOFFSET_RCLICK) & JSMASK_RCLICK;
jc->simple_state.buttons |= ((int) (packet[indexOffset + 8] >> 5) << JSOFFSET_OPTIONS) & JSMASK_OPTIONS; 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 + 8]) << JSOFFSET_L) & JSMASK_L;
jc->simple_state.buttons |= ((int) (packet[indexOffset + 9]) << JSOFFSET_PS) & JSMASK_PS; 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. // 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] >> 2) << JSOFFSET_MIC) & JSMASK_MIC;
jc->simple_state.buttons |= jc->simple_state.buttons |= ((int)(packet[indexOffset + 9] >> 4) << JSOFFSET_FNL) & JSMASK_FNL;
((int) (packet[indexOffset + 9] >> 1) << JSOFFSET_TOUCHPAD_CLICK) & JSMASK_TOUCHPAD_CLICK; 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.zr = (packet[indexOffset+6] >> 3) & 1;
//jc->btns.zl = (packet[indexOffset+6] >> 2) & 1; //jc->btns.zl = (packet[indexOffset+6] >> 2) & 1;
jc->simple_state.rTrigger = packet[indexOffset + 5] / 255.0f; jc->simple_state.rTrigger = packet[indexOffset + 5] / 255.0f;

View File

@ -17,31 +17,33 @@
#define JS_SPLIT_TYPE_RIGHT 2 #define JS_SPLIT_TYPE_RIGHT 2
#define JS_SPLIT_TYPE_FULL 3 #define JS_SPLIT_TYPE_FULL 3
#define JSMASK_UP 0x00001 #define JSMASK_UP 0x000001
#define JSMASK_DOWN 0x00002 #define JSMASK_DOWN 0x000002
#define JSMASK_LEFT 0x00004 #define JSMASK_LEFT 0x000004
#define JSMASK_RIGHT 0x00008 #define JSMASK_RIGHT 0x000008
#define JSMASK_PLUS 0x00010 #define JSMASK_PLUS 0x000010
#define JSMASK_OPTIONS 0x00010 #define JSMASK_OPTIONS 0x000010
#define JSMASK_MINUS 0x00020 #define JSMASK_MINUS 0x000020
#define JSMASK_SHARE 0x00020 #define JSMASK_SHARE 0x000020
#define JSMASK_LCLICK 0x00040 #define JSMASK_LCLICK 0x000040
#define JSMASK_RCLICK 0x00080 #define JSMASK_RCLICK 0x000080
#define JSMASK_L 0x00100 #define JSMASK_L 0x000100
#define JSMASK_R 0x00200 #define JSMASK_R 0x000200
#define JSMASK_ZL 0x00400 #define JSMASK_ZL 0x000400
#define JSMASK_ZR 0x00800 #define JSMASK_ZR 0x000800
#define JSMASK_S 0x01000 #define JSMASK_S 0x001000
#define JSMASK_E 0x02000 #define JSMASK_E 0x002000
#define JSMASK_W 0x04000 #define JSMASK_W 0x004000
#define JSMASK_N 0x08000 #define JSMASK_N 0x008000
#define JSMASK_HOME 0x10000 #define JSMASK_HOME 0x010000
#define JSMASK_PS 0x10000 #define JSMASK_PS 0x010000
#define JSMASK_CAPTURE 0x20000 #define JSMASK_CAPTURE 0x020000
#define JSMASK_TOUCHPAD_CLICK 0x20000 #define JSMASK_TOUCHPAD_CLICK 0x020000
#define JSMASK_MIC 0x40000 #define JSMASK_MIC 0x040000
#define JSMASK_SL 0x40000 #define JSMASK_SL 0x080000
#define JSMASK_SR 0x80000 #define JSMASK_SR 0x100000
#define JSMASK_FNL 0x200000
#define JSMASK_FNR 0x400000
#define JSOFFSET_UP 0 #define JSOFFSET_UP 0
#define JSOFFSET_DOWN 1 #define JSOFFSET_DOWN 1
@ -66,8 +68,10 @@
#define JSOFFSET_CAPTURE 17 #define JSOFFSET_CAPTURE 17
#define JSOFFSET_TOUCHPAD_CLICK 17 #define JSOFFSET_TOUCHPAD_CLICK 17
#define JSOFFSET_MIC 18 #define JSOFFSET_MIC 18
#define JSOFFSET_SL 18 #define JSOFFSET_SL 19
#define JSOFFSET_SR 19 #define JSOFFSET_SR 20
#define JSOFFSET_FNL 21
#define JSOFFSET_FNR 22
// PS5 Player maps for the DS Player Lightbar // PS5 Player maps for the DS Player Lightbar
#define DS5_PLAYER_1 4 #define DS5_PLAYER_1 4

View File

@ -1,5 +1,5 @@
#include "engine.h" #include "engine.h"
#include "win32.h" //#include "win32.h"
NS_ENGINE_BEGIN NS_ENGINE_BEGIN
@ -109,13 +109,11 @@ b32 input_using_analog()
return false; return false;
} }
internal void void startup()
startup()
{ {
} }
internal void void shutdown()
shutdown()
{ {
} }
@ -146,17 +144,17 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBu
assert( sizeof(EngineState) <= memory->PersistentSize ); assert( sizeof(EngineState) <= memory->PersistentSize );
state->ToneVolume = 1000; state->ToneVolume = 1000;
state->WaveToneHz = 262; state->WaveToneHz = 120;
state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz; state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz;
state->XOffset = 0; state->XOffset = 0;
state->YOffset = 0; state->YOffset = 0;
#if Build_Debug #if Build_Debug && 0
{ {
using namespace platform; using namespace platform;
char* file_path = __FILE__; char const* file_path = __FILE__;
Debug_FileContent file_content = debug_file_read_content( file_path ); Debug_FileContent file_content = debug_file_read_content( file_path );
if ( file_content.Size ) if ( file_content.Size )
{ {
@ -282,3 +280,4 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBu
} }
NS_ENGINE_END NS_ENGINE_END

View File

@ -4,7 +4,7 @@
#pragma once #pragma once
#include "platform.h" #include "platform/platform.h"
#define NS_ENGINE_BEGIN namespace engine { #define NS_ENGINE_BEGIN namespace engine {
#define NS_ENGINE_END } #define NS_ENGINE_END }
@ -58,8 +58,6 @@ struct DigitalBtn
s32 HalfTransitions; s32 HalfTransitions;
b32 EndedDown; b32 EndedDown;
}; };
#define DigitalBtn_Up 0
#define DigitalBtn_Down 1
struct AnalogAxis struct AnalogAxis
{ {
@ -197,10 +195,6 @@ struct InputMode
void input_mode_pop( InputMode* mode ); void input_mode_pop( InputMode* mode );
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 NS_ENGINE_END
// TODO(Ed) : Move this to handmade game layer later. // TODO(Ed) : Move this to handmade game layer later.

View File

@ -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

View File

@ -10,7 +10,7 @@
# pragma warning( disable: 4820 ) # pragma warning( disable: 4820 )
#endif #endif
#include "JoyShockLibrary/JoyShockLibrary.h" #include "dependencies/JoyShockLibrary/JoyShockLibrary.h"
#ifdef COMPILER_CLANG #ifdef COMPILER_CLANG
# pragma clang diagnostic pop # pragma clang diagnostic pop

View File

@ -1,6 +1,8 @@
/* /*
Platform abstraction layer for the project. Platform abstraction layer for the project.
Services the platform provides to the engine & game. Services the platform provides to the engine & game.
This should be the only file the engine or game layer can include
*/ */
#pragma once #pragma once
@ -14,6 +16,10 @@
#pragma warning( disable: 4505 ) // Support for unused static functions #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 #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 <math.h> // TODO : Implement math ourselves
#include <stdio.h> // TODO : Implement output logging ourselves
#include "grime.h" #include "grime.h"
#include "macros.h" #include "macros.h"
#include "generics.h" #include "generics.h"
@ -38,8 +44,29 @@ struct Debug_FileContent
}; };
void debug_file_free_content ( Debug_FileContent* file_content ); void debug_file_free_content ( Debug_FileContent* file_content );
Debug_FileContent debug_file_read_content ( char* file_path ); Debug_FileContent debug_file_read_content ( char const* file_path );
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 );
#endif #endif
NS_PLATFORM_END 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

View File

@ -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

View File

@ -17,22 +17,6 @@
- GetKeyboardLayout (for French keyboards, international WASD support) - 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 <math.h> // TODO : Implement math ourselves
#include <stdio.h> // TODO : Implement output logging ourselves
#include "engine.cpp"
// Platform Layer headers // Platform Layer headers
#include "platform.h" #include "platform.h"
#include "jsl.h" // Using this to get dualsense controllers #include "jsl.h" // Using this to get dualsense controllers
@ -41,10 +25,12 @@
// Engine layer headers // Engine layer headers
#include "engine.h" #include "engine.h"
#include "platform_engine_api.h"
// TOOD(Ed): Redo these macros properly later. // TOOD(Ed): Redo these macros properly later.
#if 1
#define congrats( message ) do { \ #define congrats( message ) do { \
JslSetLightColour( 0, (255 << 16) | (215 << 8) ); \ JslSetLightColour( 0, (255 << 16) | (215 << 8) ); \
MessageBoxA( 0, message, "Congratulations!", MB_OK | MB_ICONEXCLAMATION ); \ 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 ); \ MessageBoxA( 0, message, "Fatal Error", MB_OK | MB_ICONERROR ); \
JslSetLightColour( 0, (255 << 8 ) ); \ JslSetLightColour( 0, (255 << 8 ) ); \
} while (0) } while (0)
#endif
NS_PLATFORM_BEGIN NS_PLATFORM_BEGIN
using namespace win32; using namespace win32;
// TODO(Ed) : This is a global for now.
global bool Running;
struct OffscreenBuffer struct OffscreenBuffer
{ {
BITMAPINFO Info; BITMAPINFO Info;
@ -93,33 +76,57 @@ struct WinDimensions
}; };
// TODO : This will def need to be looked over. // TODO : This will def need to be looked over.
struct SoundOutput struct DirectSoundBuffer
{ {
DWORD IsPlaying; LPDIRECTSOUNDBUFFER SecondaryBuffer;
u32 RunningSampleIndex; s16* Samples;
s32 LatencySampleCount; 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 ); using DirectSoundCreateFn = HRESULT WINAPI (LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter );
global DirectSoundCreateFn* direct_sound_create; 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_Millisecond = 1000;
constexpr u64 Tick_To_Microsecond = 1000 * 1000; constexpr u64 Tick_To_Microsecond = 1000 * 1000;
global u64 Performance_Counter_Frequency; 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 #if Build_Debug
struct DebugTimeMarker
{
DWORD PlayCursor;
DWORD WriteCursor;
};
void debug_file_free_content( Debug_FileContent* content ) void debug_file_free_content( Debug_FileContent* content )
{ {
if ( content->Data) 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 {}; Debug_FileContent result {};
@ -168,7 +175,7 @@ Debug_FileContent debug_file_read_content( char* file_path )
return result; 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 HANDLE file_handle = CreateFileA( file_path
, GENERIC_WRITE, 0, 0 , 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 ); CloseHandle( file_handle );
return true; 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 #endif
inline u64 inline u64
@ -205,6 +260,7 @@ timing_get_seconds_elapsed( u64 start, u64 end )
{ {
u64 delta = end - start; u64 delta = end - start;
f32 result = scast(f32, delta) / scast(f32, Performance_Counter_Frequency); f32 result = scast(f32, delta) / scast(f32, Performance_Counter_Frequency);
return result;
} }
inline f32 inline f32
@ -269,16 +325,13 @@ input_process_axis_value( f32 value, f32 deadzone_threshold )
} }
internal void 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 internal void
init_sound(HWND window_handle, s32 samples_per_second, s32 buffer_size ) init_sound(HWND window_handle, DirectSoundBuffer* sound_buffer )
{ {
// Load library // Load library
HMODULE sound_library = LoadLibraryA( "dsound.dll" ); 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 {};
wave_format.wFormatTag = WAVE_FORMAT_PCM; /* format type */ wave_format.wFormatTag = WAVE_FORMAT_PCM; /* format type */
wave_format.nChannels = 2; /* number of channels (i.e. mono, stereo...) */ 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.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.nBlockAlign = wave_format.nChannels * wave_format.wBitsPerSample / 8 ; /* block size of data */
wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign; /* for buffer estimation */ 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 DSBUFFERDESC
buffer_description { sizeof(buffer_description) }; buffer_description { sizeof(buffer_description) };
buffer_description.dwFlags = 0; buffer_description.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
buffer_description.dwBufferBytes = buffer_size; buffer_description.dwBufferBytes = sound_buffer->SecondaryBufferSize;
buffer_description.lpwfxFormat = & wave_format; 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 // TODO : Diagnostic
} }
if ( ! SUCCEEDED( DS_SecondaryBuffer->SetFormat( & wave_format ) ) ) if ( ! SUCCEEDED( sound_buffer->SecondaryBuffer->SetFormat( & wave_format ) ) )
{ {
// TODO : Diagnostic // TODO : Diagnostic
} }
} }
internal void internal void
ds_clear_sound_buffer( SoundOutput* sound_output ) ds_clear_sound_buffer( DirectSoundBuffer* sound_buffer )
{ {
LPVOID region_1; LPVOID region_1;
DWORD region_1_size; DWORD region_1_size;
LPVOID region_2; LPVOID region_2;
DWORD region_2_size; 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_1, & region_1_size
, & region_2, & region_2_size , & region_2, & region_2_size
, 0 ); , 0 );
@ -383,21 +436,21 @@ ds_clear_sound_buffer( SoundOutput* sound_output )
++ sample_out; ++ 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; return;
} }
} }
internal void 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; LPVOID region_1;
DWORD region_1_size; DWORD region_1_size;
LPVOID region_2; LPVOID region_2;
DWORD region_2_size; 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_1, & region_1_size
, & region_2, & region_2_size , & region_2, & region_2_size
, 0 ); , 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 // 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_out = rcast( s16*, region_1 );
s16* sample_in = sound_buffer->Samples; s16* sample_in = sound_buffer->Samples;
for ( DWORD sample_index = 0; sample_index < region_1_sample_count; ++ sample_index ) 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_out;
++ sample_in; ++ 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 ); sample_out = rcast( s16*, region_2 );
for ( DWORD sample_index = 0; sample_index < region_2_sample_count; ++ sample_index ) 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_out;
++ sample_in; ++ 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; return;
} }
@ -512,12 +565,10 @@ display_buffer_in_window( HDC device_context, u32 window_width, u32 window_heigh
} }
internal LRESULT CALLBACK internal LRESULT CALLBACK
main_window_callback( main_window_callback( HWND handle
HWND handle, , UINT system_messages
UINT system_messages, , WPARAM w_param
WPARAM w_param, , LPARAM l_param )
LPARAM l_param
)
{ {
LRESULT result = 0; LRESULT result = 0;
@ -554,7 +605,7 @@ main_window_callback(
WinDimensions dimensions = get_window_dimensions( handle ); 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 , x, y
, width, height ); , width, height );
EndPaint( handle, & info ); EndPaint( handle, & info );
@ -617,16 +668,10 @@ process_pending_window_messages( engine::KeyboardState* keyboard )
} }
} }
} }
NS_PLATFORM_END NS_PLATFORM_END
int CALLBACK int CALLBACK
WinMain( WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int show_command )
HINSTANCE instance,
HINSTANCE prev_instance,
LPSTR commandline,
int show_command
)
{ {
using namespace win32; using namespace win32;
using namespace platform; using namespace platform;
@ -637,20 +682,12 @@ WinMain(
u64 launch_cycle = __rdtsc(); u64 launch_cycle = __rdtsc();
#endif #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 // 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 ); 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. // 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)
f32 high_perf_frametime_ms = 1000.f / 120.f; b32 sub_ms_granularity_required = scast(f32, Engine_Refresh_Hz) <= High_Perf_Frametime_MS;
b32 sub_ms_granularity_required = engine_frame_target_ms <= high_perf_frametime_ms;
QueryPerformanceFrequency( rcast(LARGE_INTEGER*, & Performance_Counter_Frequency) ); QueryPerformanceFrequency( rcast(LARGE_INTEGER*, & Performance_Counter_Frequency) );
@ -666,13 +703,12 @@ WinMain(
+ engine_memory.TransientSize; + engine_memory.TransientSize;
#if Build_Debug #if Build_Debug
void* Base_Address = rcast(void*, terabytes( 1 )); void* base_address = rcast(void*, terabytes( 1 ));
#else #else
void* Base_Address = 0; void* base_address = 0;
#endif #endif
engine_memory.Persistent = VirtualAlloc( Base_Address, total_size engine_memory.Persistent = VirtualAlloc( base_address, total_size , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write );
, MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write );
engine_memory.Transient = rcast( u8*, engine_memory.Persistent ) + engine_memory.PersistentSize; engine_memory.Transient = rcast( u8*, engine_memory.Persistent ) + engine_memory.PersistentSize;
if ( engine_memory.Persistent == nullptr if ( engine_memory.Persistent == nullptr
@ -721,33 +757,49 @@ WinMain(
} }
} }
// WinDimensions dimensions = get_window_dimensions( window_handle ); // 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_sound_buffer.IsPlaying = 0;
DS_SecondaryBuffer_SamplesPerSecond = 48000; ds_sound_buffer.SamplesPerSecond = 48000;
DS_SecondaryBuffer_BytesPerSample = sizeof(s16) * 2; ds_sound_buffer.BytesPerSample = sizeof(s16) * 2;
DS_SecondaryBuffer_Size = DS_SecondaryBuffer_SamplesPerSecond * DS_SecondaryBuffer_BytesPerSample; ds_sound_buffer.SecondaryBufferSize = ds_sound_buffer.SamplesPerSecond * ds_sound_buffer.BytesPerSample;
init_sound( window_handle, DS_SecondaryBuffer_SamplesPerSecond, DS_SecondaryBuffer_Size ); 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 )); , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ));
assert( SoundBufferSamples ); assert( ds_sound_buffer.Samples );
ds_sound_buffer.RunningSampleIndex = 0;
sound_output.RunningSampleIndex = 0;
sound_output.LatencySampleCount = DS_SecondaryBuffer_SamplesPerSecond / 15;
// ds_clear_sound_buffer( & sound_output ); // 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; // Direct sound requires 3 frames of audio latency for no bugs to show u
// Max controllers for the platform layer and thus for all other layers is 4. (Sanity and xinput limit) 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 {}; 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 keyboard_states[2] {};
engine::KeyboardState* old_keyboard = & keyboard_states[0]; engine::KeyboardState* old_keyboard = & keyboard_states[0];
engine::KeyboardState* new_keyboard = & keyboard_states[1]; engine::KeyboardState* new_keyboard = & keyboard_states[1];
@ -801,14 +853,37 @@ WinMain(
f32 startup_ms = timing_get_ms_elapsed( launch_clock, last_frame_clock ); f32 startup_ms = timing_get_ms_elapsed( launch_clock, last_frame_clock );
#endif #endif
Running = true; 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 ) while( Running )
{ {
process_pending_window_messages( new_keyboard ); 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 // 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. // Swapping at the beginning of the input frame instead of the end.
swap( old_keyboard, new_keyboard ); swap( old_keyboard, new_keyboard );
swap( old_xpads, new_xpads ); swap( old_xpads, new_xpads );
@ -941,21 +1016,21 @@ WinMain(
} }
// Pain... // Pain...
b32 sound_is_valid = false; // DWORD ds_play_cursor;
DWORD ds_play_cursor; // DWORD ds_write_cursor;
DWORD ds_write_cursor;
DWORD byte_to_lock = 0; DWORD byte_to_lock = 0;
DWORD bytes_to_write = 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 = (ds_sound_buffer.RunningSampleIndex * ds_sound_buffer.BytesPerSample) % ds_sound_buffer.SecondaryBufferSize;
byte_to_lock = (sound_output.RunningSampleIndex * DS_SecondaryBuffer_BytesPerSample) % DS_SecondaryBuffer_Size; target_cursor = (last_play_cursor + (ds_sound_buffer.LatencySampleCount * ds_sound_buffer.BytesPerSample)) % ds_sound_buffer.SecondaryBufferSize;
DWORD target_cursor = (ds_play_cursor + (sound_output.LatencySampleCount * DS_SecondaryBuffer_BytesPerSample)) % DS_SecondaryBuffer_Size;
if ( byte_to_lock > target_cursor) if ( byte_to_lock > target_cursor)
{ {
// Infront of play cursor |--play--byte_to_write-->--| // 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; bytes_to_write += target_cursor;
} }
else else
@ -963,40 +1038,72 @@ WinMain(
// Behind play cursor |--byte_to_write-->--play--| // Behind play cursor |--byte_to_write-->--play--|
bytes_to_write = target_cursor - byte_to_lock; bytes_to_write = target_cursor - byte_to_lock;
} }
// sound_is_valid = true;
sound_is_valid = true;
} }
// s16 samples[ 48000 * 2 ]; // s16 samples[ 48000 * 2 ];
engine::SoundBuffer sound_buffer {}; engine::SoundBuffer sound_buffer {};
sound_buffer.NumSamples = bytes_to_write / DS_SecondaryBuffer_BytesPerSample; sound_buffer.NumSamples = bytes_to_write / ds_sound_buffer.BytesPerSample;
sound_buffer.RunningSampleIndex = sound_output.RunningSampleIndex; sound_buffer.RunningSampleIndex = ds_sound_buffer.RunningSampleIndex;
sound_buffer.SamplesPerSecond = DS_SecondaryBuffer_SamplesPerSecond; sound_buffer.SamplesPerSecond = ds_sound_buffer.SamplesPerSecond;
sound_buffer.Samples = SoundBufferSamples; 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_cycle = __rdtsc();
u64 work_frame_end_clock = timing_get_wall_clock(); 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 work_cycles = timing_get_ms_elapsed( last_frame_cycle, work_frame_end_cycle );
f32 frame_elapsed_ms = work_frame_ms; f32 frame_elapsed_ms = work_frame_ms; // SecondsElapsedForFrame
if ( frame_elapsed_ms < engine_frame_target_ms ) if ( frame_elapsed_ms < Engine_Frame_Target_MS )
{ {
s32 sleep_ms = scast(DWORD, (Engine_Frame_Target_MS - frame_elapsed_ms)) - 1;
DWORD sleep_ms = scast(DWORD, (engine_frame_target_ms - frame_elapsed_ms)) - 1; if ( sleep_ms > 0 && ! sub_ms_granularity_required && sleep_is_granular )
if ( ! sub_ms_granularity_required && sleep_is_granular )
{ {
Sleep( sleep_ms ); Sleep( scast(DWORD, sleep_ms) );
} }
u64 frame_clock = timing_get_wall_clock(); u64 frame_clock = timing_get_wall_clock();
frame_elapsed_ms = timing_get_ms_elapsed( last_frame_clock, frame_clock ); frame_elapsed_ms = timing_get_ms_elapsed( last_frame_clock, frame_clock );
if ( frame_elapsed_ms < Engine_Frame_Target_MS )
{
// TODO(Ed) : Log ms discrepancy here.
}
assert( frame_elapsed_ms < engine_frame_target_ms ); assert( frame_elapsed_ms < Engine_Frame_Target_MS );
while ( frame_elapsed_ms < engine_frame_target_ms ) while ( frame_elapsed_ms < Engine_Frame_Target_MS )
{ {
frame_clock = timing_get_wall_clock(); frame_clock = timing_get_wall_clock();
frame_elapsed_ms = timing_get_ms_elapsed( last_frame_clock, frame_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! // TODO(Ed) : Missed the display sync window!
} }
// Update audio buffer last_frame_clock = timing_get_wall_clock(); // LastCouner
do { last_frame_cycle = __rdtsc();
DWORD ds_status = 0;
if ( SUCCEEDED( DS_SecondaryBuffer->GetStatus( & ds_status ) ) )
{
sound_output.IsPlaying = ds_status & DSBSTATUS_PLAYING;
}
if ( ! sound_is_valid ) // Update surface back buffer
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
{ {
WinDimensions dimensions = get_window_dimensions( window_handle ); WinDimensions dimensions = get_window_dimensions( window_handle );
HDC device_context = GetDC( 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 , 0, 0
, dimensions.Width, dimensions.Height ); , 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(); if ( SUCCEEDED( ds_sound_buffer.SecondaryBuffer->GetCurrentPosition( & play_cursor, & write_cursor ) ) )
last_frame_cycle = __rdtsc(); {
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 ) if ( jsl_num_devices > 0 )
{ {
for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index ) for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index )

View File

@ -1,8 +1,10 @@
Clear-Host Clear-Host
Import-Module ./helpers/target_arch.psm1 $target_arch = Join-Path $PSScriptRoot 'helpers/target_arch.psm1'
$devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1' $devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1'
$path_root = git rev-parse --show-toplevel $path_root = git rev-parse --show-toplevel
Import-Module $target_arch
Push-Location $path_root Push-Location $path_root
@ -30,8 +32,7 @@ if ( $args ) { $args | ForEach-Object {
#region Configuration #region Configuration
if ($IsWindows) { if ($IsWindows) {
# This library was really designed to only run on 64-bit systems. # This HandmadeHero implementation is only designed for 64-bit systems
# (Its a development tool after all)
& $devshell -arch amd64 & $devshell -arch amd64
} }
@ -154,12 +155,14 @@ if ( $vendor -match "clang" )
$flag_warnings_as_errors = '-Werror' $flag_warnings_as_errors = '-Werror'
$flag_win_nologo = '/nologo' $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 $target_arch = Get-TargetArchClang
$warning_ignores = @( $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 # 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 ) { if ( $debug ) {
$linker_args += $flag_link_win_debug $linker_args += $flag_link_win_debug
$linker_args += $flag_link_win_pdb + $pdb $linker_args += $flag_link_win_pdb + $pdb
$linker_args += $flag_link_mapfile + $map # $linker_args += $flag_link_mapfile + $map
} }
$libraries | ForEach-Object { $libraries | ForEach-Object {
@ -338,7 +341,7 @@ if ( $vendor -match "msvc" )
if ( $debug ) { if ( $debug ) {
$linker_args += $flag_link_win_debug $linker_args += $flag_link_win_debug
$linker_args += $flag_link_win_pdb + $pdb $linker_args += $flag_link_win_pdb + $pdb
$linker_args += $flag_link_mapfile + $map # $linker_args += $flag_link_mapfile + $map
} }
else { else {
} }
@ -376,7 +379,7 @@ if ( (Test-Path $path_deps) -eq $false ) {
$includes = @( $includes = @(
$path_project, $path_project,
$path_gen, $path_gen,
$path_deps, # $path_deps,
$path_platform $path_platform
) )
$compiler_args = @() $compiler_args = @()
@ -420,8 +423,8 @@ $lib_winmm = 'Winmm.lib'
# Github # Github
$lib_jsl = Join-Path $path_deps 'JoyShockLibrary/x64/JoyShockLibrary.lib' $lib_jsl = Join-Path $path_deps 'JoyShockLibrary/x64/JoyShockLibrary.lib'
$unit = Join-Path $path_platform 'handmade_win32.cpp' $unit = Join-Path $path_project 'handmade_win32.cpp'
$executable = Join-Path $path_build 'handmade_win32.exe' $executable = Join-Path $path_build 'handmade_win32.exe'
$stack_size = 1024 * 1024 * 4 $stack_size = 1024 * 1024 * 4
@ -434,6 +437,9 @@ $compiler_args = @(
$flag_optimize_intrinsics $flag_optimize_intrinsics
($flag_define + 'Build_DLL=0' ) ($flag_define + 'Build_DLL=0' )
# For now this script only supports unity builds... (for the full binary)
($flag_define + 'Build_Unity=1' )
) )
if ( $dev ) { if ( $dev ) {

View File

@ -5,6 +5,6 @@ $path_project = join-path $path_root "project"
$path_build = join-path $path_root "build" $path_build = join-path $path_root "build"
$path_dependencies = join-path $path_project "dependencies" $path_dependencies = join-path $path_project "dependencies"
if ( Test-Path $path_project ) { if ( Test-Path $path_build ) {
Remove-Item $path_build -Recurse Remove-Item -verbose $path_build -Recurse
} }

Binary file not shown.

1
scripts/rebuild.ps1 Normal file
View File

@ -0,0 +1 @@
Clear-Host