From 8af1c59bb640eb8c0e5c6abe78f52ecb7503b745 Mon Sep 17 00:00:00 2001 From: igor Date: Sat, 21 Mar 2026 17:08:46 -0700 Subject: [PATCH] In process of migrating to ANSI C. --- Makefile | 15 +- core.h | 8 ++ handmade.cpp => handmade.c | 36 +++-- handmade.h | 51 ++++--- sdl_handmade.cpp => sdl_handmade.c | 222 +++++++++++++++++++---------- sdl_handmade.h | 23 +-- 6 files changed, 222 insertions(+), 133 deletions(-) rename handmade.cpp => handmade.c (77%) rename sdl_handmade.cpp => sdl_handmade.c (76%) diff --git a/Makefile b/Makefile index 00b3a6d..71a3329 100644 --- a/Makefile +++ b/Makefile @@ -12,18 +12,19 @@ else endif endif -CC = clang++ +CC = clang UFLAGS = -FLAGS = -Wall -Wextra -ggdb -fno-caret-diagnostics -fno-show-column -Wno-missing-field-initializers -Wno-unused-function -Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable - #-std=c99 -pedantic +FLAGS = -ansi -D_POSIX_C_SOURCE=200809L -pedantic -pedantic-errors -Wall -Wextra -fno-caret-diagnostics -fno-show-column -Wno-missing-field-initializers -Wno-unused-function -Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable + # -pedantic-errors ifeq ($(DETECTED_OS),macos) + UFLAGS = -gldb INCLUDE = -I./sdl/include/ LIBS = ./sdl/lib/arm-macos/libSDL2.a -lm FRAMEWORKS = -framework Cocoa -framework IOKit -framework CoreAudio -framework AudioToolbox -framework ForceFeedback -framework Carbon -framework GameController -framework Metal -framework QuartzCore -framework CoreHaptics - else ifeq ($(DETECTED_OS),linux) + UFLAGS = -ggdb INCLUDE = -I./sdl/include/ LIBS = ./sdl/lib/x86_64-linux/libSDL2.a -lm -lX11 FRAMEWORKS = @@ -41,11 +42,11 @@ EXE=handmadehero default: libhandmade $(EXE) -libhandmade: handmade.cpp +libhandmade: handmade.c @ $(CC) $(FLAGS) $(UFLAGS) -fPIC -shared $(INCLUDE) $^ $(LIBS) $(FRAMEWORKS) -o libhandmade.so -$(EXE): sdl_handmade.cpp libhandmade - @ $(CC) $(FLAGS) $(UFLAGS) $(INCLUDE) sdl_handmade.cpp $(LIBS) $(FRAMEWORKS) -o $@ +$(EXE): sdl_handmade.c libhandmade + @ $(CC) $(FLAGS) $(UFLAGS) $(INCLUDE) sdl_handmade.c $(LIBS) $(FRAMEWORKS) -o $@ run: ./$(EXE) diff --git a/core.h b/core.h index 92aeac5..34ec330 100644 --- a/core.h +++ b/core.h @@ -3,6 +3,14 @@ /* ---- Types ---------------------------------------------------------- */ +#ifndef BUILD_DEBUG +#define BUILD_DEBUG 1 +#endif + +#ifndef BUILD_INTERNAL +#define BUILD_INTERNAL 1 +#endif + #ifndef TRUE #define TRUE 1 #endif diff --git a/handmade.cpp b/handmade.c similarity index 77% rename from handmade.cpp rename to handmade.c index e50ce68..89d84b1 100644 --- a/handmade.cpp +++ b/handmade.c @@ -1,3 +1,4 @@ +#include "core.h" #include "handmade.h" #include "sdl_handmade.h" @@ -9,9 +10,11 @@ static void GameOutputSound(game_state *GameState, game_sound_output_buffer *Sou S32 WavePeriod = SoundBuffer->SamplesPerSecond / ToneHz; S16 *SampleOut = SoundBuffer->Samples; - for(S32 SampleIndex = 0; SampleIndex < SoundBuffer->SampleCount; SampleIndex++) { + + S32 SampleIndex; + for(SampleIndex = 0; SampleIndex < SoundBuffer->SampleCount; SampleIndex++) { F32 SineValue = sinf(GameState->tSine); - S16 SampleValue = S16(SineValue * ToneVolume); + S16 SampleValue = (S16)(SineValue * ToneVolume); *SampleOut++ = SampleValue; *SampleOut++ = SampleValue; @@ -28,9 +31,11 @@ static void RenderWeirdGradient(game_offscreen_buffer *Buffer, S32 XOffset, S32 S32 Height = Buffer->Height; U8 *Row = (U8 *)Buffer->Memory; - for(S32 Y = 0; Y < Height; Y++) { + S32 Y; + for(Y = 0; Y < Height; Y++) { U32 *Pixel = (U32 *)Row; - for(S32 X = 0; X < Width; X++) { + S32 X; + for(X = 0; X < Width; X++) { U8 Blue = (U8)(X + XOffset); U8 Green = (U8)(Y + YOffset); @@ -48,24 +53,27 @@ void UpdateAndRender(game_memory *Memory, game_input *Input, game_offscreen_buff game_state *GameState = (game_state *)Memory->PermanentStorage; if(!Memory->IsInitialized) { +#if BUILD_INTERNAL char FileName[] = "/home/igor/Developer/handmade/sdl_handmade.cpp"; debug_read_file_result BitmapMemory = Memory->DEBUGPlatformReadEntireFile(FileName); if(BitmapMemory.Contents) { Memory->DEBUGPlatformWriteEntireFile("test.out", BitmapMemory.ContentsSize, BitmapMemory.Contents); Memory->DEBUGPlatformFreeFileMemory(BitmapMemory.Contents); } +#endif GameState->ToneHz = 256; GameState->tSine = 0.0f; - // TODO: Maybe more appropriate to do in the platform layer? - Memory->IsInitialized = true; + /* TODO: Maybe more appropriate to do in the platform layer? */ + Memory->IsInitialized = TRUE; } - // GameState.ToneHz; - // GameState.GreenOffset; - // GameState.BlueOffset; + /* GameState.ToneHz; */ + /* GameState.GreenOffset; */ + /* GameState.BlueOffset; */ - for(U32 ControllerIndex = 0; ControllerIndex < ARRAY_SIZE(Input->Controllers); ControllerIndex++) { + U32 ControllerIndex; + for(ControllerIndex = 0; ControllerIndex < ARRAY_SIZE(Input->Controllers); ControllerIndex++) { game_controller_input *Controller = GetController(Input, ControllerIndex); if(Controller->IsAnalog) { GameState->GreenOffset += (int)(4.0f*(Controller->StickAverageY)); @@ -73,16 +81,16 @@ void UpdateAndRender(game_memory *Memory, game_input *Input, game_offscreen_buff GameState->ToneHz = 256 + (S32)(128.0f*(Controller->StickAverageY)); } else { if(Controller->MoveUp.EndedDown) { - GameState->GreenOffset -= 1; + GameState->GreenOffset -= 5; } if(Controller->MoveDown.EndedDown) { - GameState->GreenOffset += 2; + GameState->GreenOffset += 5; } if(Controller->MoveLeft.EndedDown) { - GameState->BlueOffset -= 1; + GameState->BlueOffset -= 5; } if(Controller->MoveRight.EndedDown) { - GameState->BlueOffset += 1; + GameState->BlueOffset += 5; } } } diff --git a/handmade.h b/handmade.h index f95f6a3..2d63469 100644 --- a/handmade.h +++ b/handmade.h @@ -1,16 +1,13 @@ -#ifndef HANDMADE_H -#define HANDMADE_H +#ifndef HANDMADE_H_SENTRY +#define HANDMADE_H_SENTRY -#include "sdl_handmade.h" #include "core.h" -/////////////////////////////////////////////////////////////////////////////// -// NOTE: Servcies that the platform layer provides to the game. // -/////////////////////////////////////////////////////////////////////////////// +/* --------------------------------------------------------------------- */ +/* NOTE: Servcies that the platform layer provides to the game. */ +/* --------------------------------------------------------------------- */ #if BUILD_INTERNAL -// NOTE: WARNING: Not for the shipping game. - typedef struct debug_read_file_result { U32 ContentsSize; void *Contents; @@ -21,12 +18,12 @@ B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, void *Mem void DEBUGPlatformFreeFileMemory(void *Memory); #endif -/////////////////////////////////////////////////////////////////////////////// -// NOTE: Servcies that the game provides to the platform layer. // -/////////////////////////////////////////////////////////////////////////////// +/* --------------------------------------------------------------------- */ +/* NOTE: Servcies that the game provides to the platform layer. */ +/* --------------------------------------------------------------------- */ typedef struct game_offscreen_buffer { - // Pixels are always 32-bit and have the bytes in BGRX (little-endian). + /* Pixels are always 32-bit and have the bytes in BGRX (little-endian). */ void *Memory; S32 Width; S32 Height; @@ -70,7 +67,7 @@ typedef struct game_controller_input { game_button_state Start; game_button_state Back; - // NOTE: All buttons must be added above this line. + /* NOTE: All buttons must be added above this line. */ game_button_state Terminator; }; @@ -78,11 +75,11 @@ typedef struct game_controller_input { } game_controller_input; typedef struct game_input { - // TODO: Insert clock value here . . . + /* TODO: Insert clock value here . . . */ game_controller_input Controllers[5]; } game_input; -inline game_controller_input *GetController(game_input *Input, S32 ControllerIndex) +game_controller_input *GetController(game_input *Input, S32 ControllerIndex) { Assert((U32)ControllerIndex < ARRAY_SIZE(Input->Controllers)); game_controller_input *Result = &(Input->Controllers[ControllerIndex]); @@ -93,26 +90,28 @@ typedef struct game_memory { B32 IsInitialized; U64 PermanentStorageSize; - void *PermanentStorage; // WARNING: This memory is REQUIRED to be zero initialized!!! (Done by the OS layer.) + void *PermanentStorage; /* WARNING: This memory is REQUIRED to be zero initialized!!! (Done by the OS layer.) */ U64 TransientStorageSize; - void *TransientStorage; // WARNING: This memory is REQUIRED to be zero initialized!!! (Done by the OS layer.) + void *TransientStorage; /* WARNING: This memory is REQUIRED to be zero initialized!!! (Done by the OS layer.) */ +#if BUILD_INTERNAL debug_read_file_result (*DEBUGPlatformReadEntireFile)(const char *); B32 (*DEBUGPlatformWriteEntireFile)(const char *, U32, void *); void (*DEBUGPlatformFreeFileMemory)(void *); +#endif } game_memory; -// typedef struct game_clocks { - // U64 Ticks; - // F32 SecondsElapsed; -// } game_clocks; +/*typedef struct game_clocks { + U64 Ticks; + F32 SecondsElapsed; +} game_clocks;*/ -extern "C" void UpdateAndRender(game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer, game_sound_output_buffer *SoundBuffer); +void UpdateAndRender(game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer, game_sound_output_buffer *SoundBuffer); -// -// -// +/**/ +/**/ +/**/ typedef struct game_state { S32 ToneHz; @@ -122,4 +121,4 @@ typedef struct game_state { F32 tSine; } game_state; -#endif // HANDMADE_H +#endif diff --git a/sdl_handmade.cpp b/sdl_handmade.c similarity index 76% rename from sdl_handmade.cpp rename to sdl_handmade.c index dacbb82..7353ac5 100644 --- a/sdl_handmade.cpp +++ b/sdl_handmade.c @@ -1,29 +1,31 @@ +/* NOTE: This layer only supports MacOS and Linux, for now. */ + #include "core.h" #include "handmade.h" #include "sdl_handmade.h" #include -#include // mmap -#include // malloc, calloc -#include // memset +#include /* mmap */ +#include /* malloc, calloc */ +#include /* memset */ #include -#include // fstat -#include // open -#include // close, read, readlink -#include // dlopen -#include // stat +#include /* fstat */ +#include /* open */ +#include /* close, write, read, readlink */ +#include /* dlopen */ +#include /* stat */ #if __APPLE__ && __MACH__ -#include +#include /* _NSGetExecutablePath */ #endif -// NOTE: This is so it compiles on ARM. +/* NOTE: This is so it compiles on ARM. */ #if __x86_64__ || __i386__ #include #endif -static bool GlobalRunning; +static B32 GlobalRunning; static U64 GlobalPerfCountFrequency; @@ -86,7 +88,7 @@ B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, void *Mem { S32 FileHandle = open(Filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if(FileHandle == -1) - return false; + return FALSE; U32 BytesToWrite = MemorySize; U8 *NextByteLocation = (U8*)Memory; @@ -94,7 +96,7 @@ B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, void *Mem U32 BytesWritten = write(FileHandle, NextByteLocation, BytesToWrite); if(BytesWritten == (U32)-1) { close(FileHandle); - return false; + return FALSE; } BytesToWrite -= BytesWritten; NextByteLocation += BytesWritten; @@ -102,7 +104,7 @@ B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, void *Mem close(FileHandle); - return true; + return TRUE; } void DEBUGPlatformFreeFileMemory(void *Memory) @@ -140,7 +142,7 @@ static void SDLResizeTexture(offscreen_buffer *Buffer, SDL_Renderer *Renderer, i static void SDLDisplayBufferInWindow(offscreen_buffer Buffer, SDL_Window *Window, SDL_Renderer *Renderer) { if(SDL_UpdateTexture(Buffer.Texture, 0, Buffer.Memory, Buffer.Pitch)) { - // TODO: Do something about this error! + /* TODO: Do something about this error! */ } SDL_RenderCopy(Renderer, Buffer.Texture, 0, 0); @@ -198,7 +200,7 @@ static void SDLClearSoundBuffer(sdl_sound_output *SoundOutput) memset(SoundOutput->Samples, 0, SoundOutput->SecondaryBufferSize); } -static void SDLProcessKeyboardMessage(game_button_state *NewState, bool IsDown) +static void SDLProcessKeyboardMessage(game_button_state *NewState, B32 IsDown) { Assert(NewState->EndedDown != IsDown); NewState->EndedDown = IsDown; @@ -216,7 +218,7 @@ static void HandleEvent(SDL_Event *Event) { switch(Event->type) { case SDL_QUIT: { - GlobalRunning = false; + GlobalRunning = FALSE; } break; case SDL_WINDOWEVENT: { @@ -236,7 +238,49 @@ static void HandleEvent(SDL_Event *Event) } } -static void SDLProcessMessages(game_controller_input *KeyboardController) +static void SDLBeginRecordingInput(sdl_state *SDLState, S32 InputRecordingIndex) +{ + SDLState->InputRecordingIndex = InputRecordingIndex; + const char *FileName = "foo.hmi"; + SDLState->RecordingHandle = open(FileName, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + write(SDLState->RecordingHandle, SDLState->GameMmemoryBlock, (size_t)(SDLState->TotalSize)); +} + +static void SDLEndRecordingInput(sdl_state *SDLState) +{ + close(SDLState->RecordingHandle); + SDLState->InputRecordingIndex = 0; +} + +static void SDLBeginInputPlayback(sdl_state *SDLState, S32 InputPlayingIndex) +{ + SDLState->InputPlayingIndex = InputPlayingIndex; + const char *FileName = "foo.hmi"; + SDLState->PlaybackHandle = open(FileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +} + +static void SDLEndInputPlayback(sdl_state *SDLState) +{ + close(SDLState->PlaybackHandle); + SDLState->InputPlayingIndex = 0; +} + +static void SDLRecordInput(sdl_state *SDLState, game_input *NewInput) +{ + write(SDLState->RecordingHandle, NewInput, sizeof(*NewInput)); +} + +static void SDLPlaybackInput(sdl_state *SDLState, game_input *NewInput) +{ + ssize_t size = read(SDLState->PlaybackHandle, NewInput, sizeof(*NewInput)); + if(size == EOF || size == -1) { + S32 PlayingIndex = SDLState->InputPlayingIndex; + SDLEndInputPlayback(SDLState); + SDLBeginInputPlayback(SDLState, PlayingIndex); + } +} + +static void SDLProcessMessages(sdl_state *SDLState, game_controller_input *KeyboardController) { SDL_Event Event; while(SDL_PollEvent(&Event)) { @@ -244,12 +288,12 @@ static void SDLProcessMessages(game_controller_input *KeyboardController) case SDL_KEYDOWN: case SDL_KEYUP: { SDL_Keycode KeyCode = Event.key.keysym.sym; - bool IsDown = (Event.key.state == SDL_PRESSED); - bool WasDown = false; + B32 IsDown = (Event.key.state == SDL_PRESSED); + B32 WasDown = FALSE; if(Event.key.state == SDL_RELEASED) { - WasDown = true; + WasDown = TRUE; } else if(Event.key.repeat != 0) { - WasDown = true; + WasDown = TRUE; } if(Event.key.repeat == 0) { @@ -280,12 +324,27 @@ static void SDLProcessMessages(game_controller_input *KeyboardController) } } - // NOTE: If your window manager already uses an Alt+F4 keybind to close programs, then we are likely to see SDL_QUIT event occur before our keybind. - bool AltKeyWasDown = (Event.key.keysym.mod & KMOD_ALT); - if(KeyCode == SDLK_F4 && AltKeyWasDown) - GlobalRunning = false; - if(KeyCode == SDLK_ESCAPE) - GlobalRunning = false; + if(WasDown) { +#if BUILD_INTERNAL + if(KeyCode == SDLK_l) { + if(SDLState->InputRecordingIndex == 0) { + SDLBeginRecordingInput(SDLState, 1); + } else { + SDLEndRecordingInput(SDLState); + SDLBeginInputPlayback(SDLState, 1); + } + } +#endif + + /* NOTE: If your window manager already uses an Alt+F4 keybind to close programs, then we are likely to see SDL_QUIT event occur before our keybind. */ + B32 AltKeyWasDown = (Event.key.keysym.mod & KMOD_ALT); + if(KeyCode == SDLK_F4 && AltKeyWasDown) + GlobalRunning = FALSE; +#if BUILD_INTERNAL + if(KeyCode == SDLK_ESCAPE) + GlobalRunning = FALSE; +#endif + } } break; default: { @@ -342,7 +401,7 @@ static U32 GetLastWriteTime(const char *FileName) struct stat file_info = {0}; if(stat(FileName, &file_info) != 0) { - // TODO: Diagnostic. perror("stat failed"); + /* TODO: Diagnostic. perror("stat failed"); */ } return (U32)file_info.st_mtime; @@ -360,12 +419,12 @@ static sdl_game_code SDLLoadGameCode(char *DLLPath) Result.UpdateAndRender = (void(*)(game_memory *, game_input *, game_offscreen_buffer *, game_sound_output_buffer *))dlsym(Result.GameCodeDLL, "UpdateAndRender"); if(!Result.UpdateAndRender) { - // TODO: Diagnostic. dlerror() + /* TODO: Diagnostic. dlerror() */ } Result.IsValid = Result.UpdateAndRender ? TRUE : FALSE; } else { - // TODO: Diagnostic. dlerror() + /* TODO: Diagnostic. dlerror() */ } if(!Result.IsValid) { @@ -378,26 +437,27 @@ static sdl_game_code SDLLoadGameCode(char *DLLPath) static void SDLUnloadGameCode(sdl_game_code *GameCode) { if(GameCode->GameCodeDLL) - dlclose(GameCode->GameCodeDLL); // NOTE: Might fail. + dlclose(GameCode->GameCodeDLL); /* NOTE: Might fail. */ GameCode->IsValid = FALSE; GameCode->UpdateAndRender = NULL; } char *GetExecutablePath() { - static char path[1024] = ""; // NOTE: We choose 1024 only because MacOS's MAXPATHLEN says such a value. - ssize_t size = (ssize_t)sizeof(path); // WARNING: size_t is usually an unsigned integer, whilst ssize_t is signed. We don't care because the path is not long. + static char path[1024] = ""; /* NOTE: We choose 1024 only because MacOS's MAXPATHLEN says such a value. For example, linux/limits.h PATH_MAX says 4096. */ + size_t path_size = sizeof(path); #if __APPLE__ && __MACH__ - if(_NSGetExecutablePath(path, &size) != 0) { // NOTE: Not an absolute path. - // TODO: Diagnostics. + U32 size = path_size; + if(_NSGetExecutablePath(path, &size) != 0) { /* NOTE: Not an absolute path. */ + /* TODO: Diagnostics. */ } #else - size = readlink("/proc/self/exe", path, size - 1); + ssize_t size = readlink("/proc/self/exe", path, path_size - 1); if(size != -1) { path[size] = '\0'; } else { - // TODO: Diagnostics. + /* TODO: Diagnostics. */ } #endif @@ -426,13 +486,14 @@ S32 main(S32 argc, char *argv[]) SDL_Window *Window = SDL_CreateWindow("Handmade Hero", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 700, 500, SDL_WINDOW_RESIZABLE); if(Window) { - //SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, 0); + /*SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, 0); */ SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_PRESENTVSYNC); - // "Wayland needs an event loop and rendering or it won't function." https://github.com/libsdl-org/SDL/issues/7699#issuecomment-1545684792 - // NOTE: This means that we need to readraw to even resize the window, otherwise the window frame will appear outdated to its actual size. - // SDL_RenderPresent(Renderer) is enough to display the window. + /* "Wayland needs an event loop and rendering or it won't function." https://github.com/libsdl-org/SDL/issues/7699#issuecomment-1545684792 */ + /* NOTE: This means that we need to readraw to even resize the window, otherwise the window frame will appear outdated to its actual size. */ + /* SDL_RenderPresent(Renderer) is enough to display the window. */ if(Renderer) { - GlobalRunning = true; + sdl_state SDLState = {0}; + GlobalRunning = TRUE; sdl_window_dimension Dimension = SDLGetWindowDimension(Window); SDLResizeTexture(&GlobalBackbuffer, Renderer, Dimension.Width, Dimension.Height); @@ -448,8 +509,8 @@ S32 main(S32 argc, char *argv[]) SDL_PauseAudio(0); SoundOutput.Samples = calloc(SoundOutput.SamplesPerSecond, SoundOutput.BytesPerSample); - // SoundOutput.Samples = malloc(SoundOutput.SecondaryBufferSize); - // SDLClearSoundBuffer(&SoundOutput); // NOTE: calloc auto clears to zero + /* SoundOutput.Samples = malloc(SoundOutput.SecondaryBufferSize); */ + /* SDLClearSoundBuffer(&SoundOutput); */ /* NOTE: calloc auto clears to zero */ #if BUILD_DEBUG void *BaseAddress = (void *)TB(2); @@ -458,19 +519,17 @@ S32 main(S32 argc, char *argv[]) #endif game_memory GameMemory = {0}; - GameMemory.PermanentStorageSize = MB(64); GameMemory.TransientStorageSize = GB(4); - U64 TotalStorageSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize; - - // NOTE: On MacOS and Linux, mmap seems to zero-fill anonymous memory as a side-effect of security. - GameMemory.PermanentStorage = mmap(BaseAddress, TotalStorageSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - GameMemory.TransientStorage = (U8 *)(GameMemory.PermanentStorage) + GameMemory.PermanentStorageSize; - GameMemory.DEBUGPlatformReadEntireFile = &DEBUGPlatformReadEntireFile; GameMemory.DEBUGPlatformWriteEntireFile = &DEBUGPlatformWriteEntireFile; GameMemory.DEBUGPlatformFreeFileMemory = &DEBUGPlatformFreeFileMemory; + SDLState.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize; + SDLState.GameMmemoryBlock = mmap(BaseAddress, SDLState.TotalSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); /* NOTE: On MacOS and Linux, mmap seems to zero-fill anonymous memory as a side-effect of security. */ + GameMemory.PermanentStorage = SDLState.GameMmemoryBlock; + GameMemory.TransientStorage = (U8 *)(GameMemory.PermanentStorage) + GameMemory.PermanentStorageSize; + if(SoundOutput.Samples && GameMemory.PermanentStorage && GameMemory.TransientStorage) { game_input Input[2]; game_input *NewInput = &Input[0]; @@ -490,11 +549,11 @@ S32 main(S32 argc, char *argv[]) LastCounter = SDLGetWallClock(); #if __x86_64__ || __i386__ - LastCycleCount = __rdtsc(); // NOTE: rdtsc reports clock cylces, however it is not meant for really precise profiler work as the value returned is varied. -#endif // Also, __rdtsc is not available on MacOS ARM; I have not checked MacOS x64. + LastCycleCount = __rdtsc(); /* NOTE: rdtsc reports clock cylces, however it is not meant for really precise profiler work as the value returned is varied. */ +#endif /* Also, __rdtsc is not available on MacOS ARM; I have not checked MacOS x64. */ S32 MonitorRefreshHz = SDLGetWindowRefreshRate(Window); - S32 GameUpdateHz = MonitorRefreshHz / 2; + S32 GameUpdateHz = MonitorRefreshHz; F32 TargetSecondsPerFrame = 1.0f / (F32)GameUpdateHz; U32 NewDLLWriteTime = GetLastWriteTime(game_dll_path); @@ -507,50 +566,50 @@ S32 main(S32 argc, char *argv[]) game_controller_input *NewKeyboardController = GetController(NewInput, 0); game_controller_input ZeroController = {0}; *NewKeyboardController = ZeroController; - NewKeyboardController->IsConnected = true; + NewKeyboardController->IsConnected = TRUE; for(unsigned int ButtonIndex = 0; ButtonIndex < ARRAY_SIZE(NewKeyboardController->Buttons); ButtonIndex++) { NewKeyboardController->Buttons[ButtonIndex].EndedDown = OldKeyboardController->Buttons[ButtonIndex].EndedDown; } - SDLProcessMessages(NewKeyboardController); + SDLProcessMessages(&SDLState, NewKeyboardController); for(unsigned int ControllerIndex = 0; ControllerIndex < MAX_CONTROLLERS; ControllerIndex++) { game_controller_input *OldController = GetController(OldInput, ControllerIndex+1); game_controller_input *NewController = GetController(NewInput, ControllerIndex+1); if(ControllerHandles[ControllerIndex] != 0 && SDL_GameControllerGetAttached(ControllerHandles[ControllerIndex])) { - NewController->IsConnected = true; + NewController->IsConnected = TRUE; S16 StickX = SDL_GameControllerGetAxis(ControllerHandles[ControllerIndex], SDL_CONTROLLER_AXIS_LEFTX); S16 StickY = SDL_GameControllerGetAxis(ControllerHandles[ControllerIndex], SDL_CONTROLLER_AXIS_LEFTY); - NewController->IsAnalog = true; + NewController->IsAnalog = TRUE; NewController->StickAverageX = SDLProcessInputStickValue((F32)StickX, CONTROLLER_LEFT_THUMB_DEADZONE); NewController->StickAverageY = SDLProcessInputStickValue((F32)StickY, CONTROLLER_LEFT_THUMB_DEADZONE); if((NewController->StickAverageX != 0.0f) || (NewController->StickAverageY != 0.0f)) { - NewController->IsAnalog = true; + NewController->IsAnalog = TRUE; } if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_UP)) { NewController->StickAverageY = -1.0f; - NewController->IsAnalog = false; + NewController->IsAnalog = FALSE; } if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_DOWN)) { NewController->StickAverageY = 1.0f; - NewController->IsAnalog = false; + NewController->IsAnalog = FALSE; } if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_LEFT)) { NewController->StickAverageX = -1.0f; - NewController->IsAnalog = false; + NewController->IsAnalog = FALSE; } if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) { NewController->StickAverageX = 1.0f; - NewController->IsAnalog = false; + NewController->IsAnalog = FALSE; } float Threshold = 0.5f; @@ -569,8 +628,8 @@ S32 main(S32 argc, char *argv[]) SDLProcessInputDigitalButton(ControllerHandles[ControllerIndex], &OldController->Start, SDL_CONTROLLER_BUTTON_START, &NewController->Start); SDLProcessInputDigitalButton(ControllerHandles[ControllerIndex], &OldController->Back, SDL_CONTROLLER_BUTTON_BACK, &NewController->Back); } else { - // NOTE: This controller is not plugged in. - NewController->IsConnected = false; + /* NOTE: This controller is not plugged in. */ + NewController->IsConnected = FALSE; } } @@ -586,8 +645,17 @@ S32 main(S32 argc, char *argv[]) Buffer.Width = GlobalBackbuffer.Width; Buffer.Height = GlobalBackbuffer.Height; Buffer.Pitch = GlobalBackbuffer.Pitch; + + if(SDLState.InputRecordingIndex) { + SDLRecordInput(&SDLState, NewInput); + } + if(SDLState.InputPlayingIndex) { + SDLPlaybackInput(&SDLState, NewInput); + } + if(Game.UpdateAndRender) Game.UpdateAndRender(&GameMemory, NewInput, &Buffer, &SoundBuffer); + SDLFillSoundBuffer(&SoundOutput, BytesToWrite); U64 WorkCounter = SDLGetWallClock(); @@ -600,8 +668,8 @@ S32 main(S32 argc, char *argv[]) SDL_Delay((unsigned int)((TargetSecondsPerFrame - SecondsElapsedForFrame) * 1000.0)); } } else { - // TODO: Missed frame rate! - // TODO: Logging. + /* TODO: Missed frame rate! */ + /* TODO: Logging. */ } U64 EndCounter = SDLGetWallClock(); @@ -626,21 +694,21 @@ S32 main(S32 argc, char *argv[]) SWAP(game_input *, NewInput, OldInput); } } else { - // TODO: Failed to allocate Samples and Sound memory . . . + /* TODO: Failed to allocate Samples and Sound memory . . . */ } } else { - // TODO: This didn't work . . . + /* TODO: This didn't work . . . */ } } else { - // TODO: This didn't work . . . + /* TODO: This didn't work . . . */ } - // NOTE: Let the OS clean things up. - // SDLDeinitControllers(); // NOTE: This, however, might need to be closed? Is there maybe some clean up state that close communicates to the controller? - // SDL_CloseAudio(); - // SDL_DestroyRenderer(Renderer); - // SDL_DestroyWindow(Window); - // SDL_Quit(); + /* NOTE: Let the OS clean things up. */ + /* SDLDeinitControllers(); // NOTE: This, however, might need to be closed? Is there maybe some clean up state that close communicates to the controller? */ + /* SDL_CloseAudio(); */ + /* SDL_DestroyRenderer(Renderer); */ + /* SDL_DestroyWindow(Window); */ + /* SDL_Quit(); */ return 0; } diff --git a/sdl_handmade.h b/sdl_handmade.h index 12963b0..9f42391 100644 --- a/sdl_handmade.h +++ b/sdl_handmade.h @@ -1,16 +1,10 @@ #ifndef SDL_HANDMADE_H #define SDL_HANDMADE_H -#include "core.h" #include -#if !defined(BUILD_DEBUG) -# define BUILD_DEBUG 1 -#endif - -#if !defined(BUILD_INTERNAL) // NOTE: Added in by igor. -# define BUILD_INTERNAL 1 -#endif +#include "core.h" +#include "handmade.h" typedef struct sdl_window_dimension { S32 Width; @@ -18,7 +12,7 @@ typedef struct sdl_window_dimension { } sdl_window_dimension; typedef struct offscreen_buffer { - // Pixels are always 32-bit and have the bytes in BGRX (little-endian). + /* Pixels are always 32-bit and have the bytes in BGRX (little-endian). */ SDL_Texture *Texture; void *Memory; S32 Width; @@ -35,4 +29,15 @@ typedef struct sdl_sound_output { void *Samples; } sdl_sound_output; +typedef struct sdl_state { + U64 TotalSize; + void *GameMmemoryBlock; + + S32 RecordingHandle; + S32 InputRecordingIndex; + + S32 PlaybackHandle; + S32 InputPlayingIndex; +} sdl_state; + #endif