Day 25 done.

This commit is contained in:
2026-03-25 14:33:23 -07:00
parent 64ccae4637
commit 4be3d0df80
5 changed files with 182 additions and 64 deletions
+4 -4
View File
@@ -51,13 +51,13 @@ typedef double F64;
/* ---- Asserts -------------------------------------------------------- */ /* ---- Asserts -------------------------------------------------------- */
#define Trap() __builtin_trap() #define TRAP() __builtin_trap()
#define AssertAlways(x) do { if(!(x)) { Trap(); } } while(0) #define ASSERT_ALWAYS(x) do { if(!(x)) { TRAP(); } } while(0)
#if BUILD_DEBUG #if BUILD_DEBUG
#define Assert(x) AssertAlways(x) #define ASSERT(x) ASSERT_ALWAYS(x)
#else #else
#define Assert(x) (void)(x) #define ASSERT(x) (void)(x)
#endif #endif
/* ---- Helper Macros -------------------------------------------------- */ /* ---- Helper Macros -------------------------------------------------- */
+39 -7
View File
@@ -63,17 +63,39 @@ static void RenderWeirdGradient(game_offscreen_buffer *Buffer, S32 XOffset,
} }
} }
void UpdateAndRender(game_memory *Memory, game_input *Input, static void RenderRectangle(game_offscreen_buffer *Buffer, S32 MouseX,
game_offscreen_buffer *Buffer, S32 MouseY)
{
U8 *Row;
U32 *Pixel;
S32 X, Y;
for(Y = MouseY; Y < MouseY+10; Y++) {
if(Y >= Buffer->Height)
break;
Row = (U8 *)Buffer->Memory + (Buffer->Pitch * Y);
for(X = MouseX; X < MouseX+10; X++) {
if(X >= Buffer->Width)
break;
Pixel = (U32 *)Row + X;
*Pixel = 0xFFFFFF;
}
}
}
void UpdateAndRender(thread_context *Thread, game_memory *Memory,
game_input *Input, game_offscreen_buffer *Buffer,
game_sound_output_buffer *SoundBuffer) game_sound_output_buffer *SoundBuffer)
{ {
game_state *GameState; game_state *GameState;
U32 ControllerIndex; U32 ControllerIndex;
Assert((&Input->Controllers[0].u.buttons.Terminator - ASSERT((&Input->Controllers[0].u.buttons.Terminator -
&Input->Controllers[0].u.Buttons[0]) == &Input->Controllers[0].u.Buttons[0]) ==
ARRAY_SIZE(Input->Controllers[0].u.Buttons)); ARRAY_SIZE(Input->Controllers[0].u.Buttons));
Assert(sizeof(game_state) <= Memory->PermanentStorageSize); ASSERT(sizeof(game_state) <= Memory->PermanentStorageSize);
GameState = (game_state *)Memory->PermanentStorage; GameState = (game_state *)Memory->PermanentStorage;
if(!Memory->IsInitialized) { if(!Memory->IsInitialized) {
@@ -82,12 +104,13 @@ void UpdateAndRender(game_memory *Memory, game_input *Input,
debug_read_file_result BitmapMemory; debug_read_file_result BitmapMemory;
FileName = "/home/igor/Developer/handmade/sdl_handmade.cpp"; FileName = "/home/igor/Developer/handmade/sdl_handmade.cpp";
BitmapMemory = Memory->DEBUGPlatformReadEntireFile(FileName); BitmapMemory = Memory->DEBUGPlatformReadEntireFile(Thread, FileName);
if(BitmapMemory.Contents) { if(BitmapMemory.Contents) {
Memory->DEBUGPlatformWriteEntireFile("test.out", Memory->DEBUGPlatformWriteEntireFile(Thread, "test.out",
BitmapMemory.ContentsSize, BitmapMemory.ContentsSize,
BitmapMemory.Contents); BitmapMemory.Contents);
Memory->DEBUGPlatformFreeFileMemory(BitmapMemory.Contents); Memory->DEBUGPlatformFreeFileMemory(Thread,
BitmapMemory.Contents);
} }
#endif #endif
@@ -133,4 +156,13 @@ void UpdateAndRender(game_memory *Memory, game_input *Input,
GameOutputSound(GameState, SoundBuffer, GameState->ToneHz); GameOutputSound(GameState, SoundBuffer, GameState->ToneHz);
RenderWeirdGradient(Buffer, GameState->BlueOffset, RenderWeirdGradient(Buffer, GameState->BlueOffset,
GameState->GreenOffset); GameState->GreenOffset);
{
S32 i;
for(i = 0; i < (S32)ARRAY_SIZE(Input->MouseButtons); i++) {
if(Input->MouseButtons[i].EndedDown)
RenderRectangle(Buffer, 10 + 20 * i, 10);
}
}
RenderRectangle(Buffer, Input->MouseX, Input->MouseY);
} }
+20 -9
View File
@@ -7,16 +7,22 @@
/* NOTE: Servcies that the platform layer provides to the game. */ /* NOTE: Servcies that the platform layer provides to the game. */
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
typedef struct thread_context {
S32 Placeholder;
} thread_context;
#if BUILD_INTERNAL #if BUILD_INTERNAL
typedef struct debug_read_file_result { typedef struct debug_read_file_result {
U32 ContentsSize; U32 ContentsSize;
void *Contents; void *Contents;
} debug_read_file_result; } debug_read_file_result;
debug_read_file_result DEBUGPlatformReadEntireFile(const char *Filename); debug_read_file_result DEBUGPlatformReadEntireFile(thread_context *Thread,
B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, const char *Filename);
B32 DEBUGPlatformWriteEntireFile(thread_context *Thread,
const char *Filename, U32 MemorySize,
void *Memory); void *Memory);
void DEBUGPlatformFreeFileMemory(void *Memory); void DEBUGPlatformFreeFileMemory(thread_context *Thread, void *Memory);
#endif #endif
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
@@ -77,6 +83,9 @@ typedef struct game_controller_input {
} game_controller_input; } game_controller_input;
typedef struct game_input { typedef struct game_input {
game_button_state MouseButtons[5];
S32 MouseX, MouseY, MouseZ; /* NOTE: MouseZ is the wheel. */
/* TODO: Insert clock value here . . . */ /* TODO: Insert clock value here . . . */
game_controller_input Controllers[5]; game_controller_input Controllers[5];
} game_input; } game_input;
@@ -85,7 +94,7 @@ game_controller_input *GetController(game_input *Input, S32 ControllerIndex)
{ {
game_controller_input *Result; game_controller_input *Result;
Assert((U32)ControllerIndex < ARRAY_SIZE(Input->Controllers)); ASSERT((U32)ControllerIndex < ARRAY_SIZE(Input->Controllers));
Result = &(Input->Controllers[ControllerIndex]); Result = &(Input->Controllers[ControllerIndex]);
return Result; return Result;
} }
@@ -104,9 +113,11 @@ typedef struct game_memory {
layer.) */ layer.) */
#if BUILD_INTERNAL #if BUILD_INTERNAL
debug_read_file_result (*DEBUGPlatformReadEntireFile)(const char *); debug_read_file_result (*DEBUGPlatformReadEntireFile)(
B32 (*DEBUGPlatformWriteEntireFile)(const char *, U32, void *); thread_context *Thread,const char *);
void (*DEBUGPlatformFreeFileMemory)(void *); B32 (*DEBUGPlatformWriteEntireFile)(thread_context *Thread,
const char *, U32, void *);
void (*DEBUGPlatformFreeFileMemory)(thread_context *Thread, void *);
#endif #endif
} game_memory; } game_memory;
@@ -115,8 +126,8 @@ typedef struct game_memory {
F32 SecondsElapsed; F32 SecondsElapsed;
} game_clocks;*/ } game_clocks;*/
void UpdateAndRender(game_memory *Memory, game_input *Input, void UpdateAndRender(thread_context *Thread, game_memory *Memory,
game_offscreen_buffer *Buffer, game_input *Input, game_offscreen_buffer *Buffer,
game_sound_output_buffer *SoundBuffer); game_sound_output_buffer *SoundBuffer);
/* /*
+86 -18
View File
@@ -8,7 +8,7 @@
#include <SDL.h> #include <SDL.h>
#include <sys/mman.h> /* mmap */ #include <sys/mman.h> /* mmap */
#include <stdlib.h> /* malloc, calloc */ #include <stdlib.h> /* malloc, calloc */
#include <string.h> /* memset */ #include <string.h> /* memset, memcpy */
#include <stdio.h> #include <stdio.h>
#include <sys/stat.h> /* fstat */ #include <sys/stat.h> /* fstat */
@@ -47,12 +47,13 @@ static U32 SafeTruncateUInt64(U64 Value)
{ {
U32 Result; U32 Result;
Assert(Value <= 0xFFFFFFFF); ASSERT(Value <= 0xFFFFFFFF);
Result = (U32)Value; Result = (U32)Value;
return Result; return Result;
} }
debug_read_file_result DEBUGPlatformReadEntireFile(const char *Filename) debug_read_file_result DEBUGPlatformReadEntireFile(thread_context *Thread,
const char *Filename)
{ {
debug_read_file_result Result; debug_read_file_result Result;
S32 FileHandle; S32 FileHandle;
@@ -101,7 +102,8 @@ debug_read_file_result DEBUGPlatformReadEntireFile(const char *Filename)
return Result; return Result;
} }
B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, B32 DEBUGPlatformWriteEntireFile(thread_context *Thread,
const char *Filename, U32 MemorySize,
void *Memory) void *Memory)
{ {
S32 FileHandle; S32 FileHandle;
@@ -132,7 +134,7 @@ B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize,
return TRUE; return TRUE;
} }
void DEBUGPlatformFreeFileMemory(void *Memory) void DEBUGPlatformFreeFileMemory(thread_context *Thread, void *Memory)
{ {
if(Memory) if(Memory)
free(Memory); free(Memory);
@@ -254,10 +256,11 @@ static void SDLClearSoundBuffer(sdl_sound_output *SoundOutput)
static void SDLProcessKeyboardMessage(game_button_state *NewState, static void SDLProcessKeyboardMessage(game_button_state *NewState,
B32 IsDown) B32 IsDown)
{ {
Assert(NewState->EndedDown != IsDown); if(NewState->EndedDown != IsDown) {
NewState->EndedDown = IsDown; NewState->EndedDown = IsDown;
++NewState->HalfTransitionCount; ++NewState->HalfTransitionCount;
} }
}
static void SDLProcessInputDigitalButton(SDL_GameController *Controller, static void SDLProcessInputDigitalButton(SDL_GameController *Controller,
game_button_state *OldState, game_button_state *OldState,
@@ -308,7 +311,7 @@ static void HandleEvent(SDL_Event *Event)
} break; } break;
case SDL_WINDOWEVENT_FOCUS_LOST: { case SDL_WINDOWEVENT_FOCUS_LOST: {
if(SDL_SetWindowOpacity(Window, 0.5f) != 0) { if(SDL_SetWindowOpacity(Window, 0.3f) != 0) {
/* TODO: This didn't work . . . SDL_GetError() */ /* TODO: This didn't work . . . SDL_GetError() */
} }
} break; } break;
@@ -322,14 +325,24 @@ static void SDLGetInputFileLocation(sdl_state *SDLState, char *path,
{ {
const char *file_name = "loop.hmi"; const char *file_name = "loop.hmi";
Assert(SlotIndex == 1); ASSERT(SlotIndex == 1);
snprintf(path, path_size, "%s%s", SDLState->EXEDirPath, file_name); snprintf(path, path_size, "%s%s", SDLState->EXEDirPath, file_name);
} }
sdl_replay_buffer *SDLGetReplayBuffer(sdl_state *SDLState,
S32 Index)
{
ASSERT(Index < (S32)ARRAY_SIZE(SDLState->ReplayBuffers));
return &(SDLState->ReplayBuffers[Index]);
}
static void SDLBeginRecordingInput(sdl_state *SDLState, static void SDLBeginRecordingInput(sdl_state *SDLState,
S32 InputRecordingIndex) S32 InputRecordingIndex)
{ {
sdl_replay_buffer *ReplayBuffer =
SDLGetReplayBuffer(SDLState, InputRecordingIndex);
if(ReplayBuffer->MemoryBlock) {
char FileName[SDL_STATE_PATH_SIZE]; char FileName[SDL_STATE_PATH_SIZE];
SDLGetInputFileLocation(SDLState, FileName, sizeof(FileName), SDLGetInputFileLocation(SDLState, FileName, sizeof(FileName),
@@ -344,9 +357,12 @@ static void SDLBeginRecordingInput(sdl_state *SDLState,
SDLState->RecordingHandle = SDLState->RecordingHandle =
open(FileName, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | open(FileName, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR |
S_IRGRP | S_IROTH); S_IRGRP | S_IROTH);
write(SDLState->RecordingHandle, SDLState->GameMmemoryBlock, /* write(SDLState->RecordingHandle, SDLState->GameMmemoryBlock,
(size_t)(SDLState->TotalSize)); */
memcpy(ReplayBuffer->MemoryBlock, SDLState->GameMmemoryBlock,
(size_t)(SDLState->TotalSize)); (size_t)(SDLState->TotalSize));
} }
}
static void SDLEndRecordingInput(sdl_state *SDLState) static void SDLEndRecordingInput(sdl_state *SDLState)
{ {
@@ -357,6 +373,9 @@ static void SDLEndRecordingInput(sdl_state *SDLState)
static void SDLBeginInputPlayback(sdl_state *SDLState, static void SDLBeginInputPlayback(sdl_state *SDLState,
S32 InputPlayingIndex) S32 InputPlayingIndex)
{ {
sdl_replay_buffer *ReplayBuffer =
SDLGetReplayBuffer(SDLState, InputPlayingIndex);
if(ReplayBuffer->MemoryBlock) {
char FileName[SDL_STATE_PATH_SIZE]; char FileName[SDL_STATE_PATH_SIZE];
ssize_t size; ssize_t size;
@@ -367,9 +386,12 @@ static void SDLBeginInputPlayback(sdl_state *SDLState,
SDLState->PlaybackHandle = SDLState->PlaybackHandle =
open(FileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | open(FileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR |
S_IRGRP | S_IROTH); S_IRGRP | S_IROTH);
size = read(SDLState->PlaybackHandle, SDLState->GameMmemoryBlock, /* size = read(SDLState->PlaybackHandle, SDLState->GameMmemoryBlock,
(size_t)(SDLState->TotalSize)); */
memcpy(SDLState->GameMmemoryBlock, ReplayBuffer->MemoryBlock,
(size_t)(SDLState->TotalSize)); (size_t)(SDLState->TotalSize));
} }
}
static void SDLEndInputPlayback(sdl_state *SDLState) static void SDLEndInputPlayback(sdl_state *SDLState)
{ {
@@ -475,12 +497,16 @@ static void SDLProcessMessages(sdl_state *SDLState,
#if BUILD_INTERNAL #if BUILD_INTERNAL
if(KeyCode == SDLK_l) { if(KeyCode == SDLK_l) {
if(SDLState->InputPlayingIndex == 0) {
if(SDLState->InputRecordingIndex == 0) { if(SDLState->InputRecordingIndex == 0) {
SDLBeginRecordingInput(SDLState, 1); SDLBeginRecordingInput(SDLState, 1);
} else { } else {
SDLEndRecordingInput(SDLState); SDLEndRecordingInput(SDLState);
SDLBeginInputPlayback(SDLState, 1); SDLBeginInputPlayback(SDLState, 1);
} }
} else {
SDLEndInputPlayback(SDLState);
}
} }
#endif #endif
@@ -550,8 +576,8 @@ typedef struct sdl_game_code {
void *GameCodeDLL; void *GameCodeDLL;
U32 DLLLastWriteTime; U32 DLLLastWriteTime;
void (*UpdateAndRender)(game_memory *, game_input *, void (*UpdateAndRender)(thread_context *Thread, game_memory *,
game_offscreen_buffer *, game_input *, game_offscreen_buffer *,
game_sound_output_buffer *); game_sound_output_buffer *);
B32 IsValid; B32 IsValid;
@@ -582,9 +608,9 @@ static sdl_game_code SDLLoadGameCode(char *DLLPath)
Result.DLLLastWriteTime = GetLastWriteTime(DLLPath); Result.DLLLastWriteTime = GetLastWriteTime(DLLPath);
Result.UpdateAndRender = Result.UpdateAndRender =
(void(*)(game_memory *, game_input *, game_offscreen_buffer *, (void(*)(thread_context *, game_memory *, game_input *,
game_sound_output_buffer *))dlsym(Result.GameCodeDLL, game_offscreen_buffer *, game_sound_output_buffer *))
"UpdateAndRender"); dlsym(Result.GameCodeDLL, "UpdateAndRender");
if(!Result.UpdateAndRender) { if(!Result.UpdateAndRender) {
/* TODO: Diagnostic. dlerror() */ /* TODO: Diagnostic. dlerror() */
} }
@@ -696,6 +722,7 @@ S32 main(S32 argc, char *argv[])
sdl_window_dimension Dimension; sdl_window_dimension Dimension;
sdl_sound_output SoundOutput; sdl_sound_output SoundOutput;
game_memory GameMemory; game_memory GameMemory;
S32 ReplayIndex;
#if BUILD_DEBUG #if BUILD_DEBUG
void *BaseAddress = (void *)TB(2); void *BaseAddress = (void *)TB(2);
@@ -747,13 +774,30 @@ S32 main(S32 argc, char *argv[])
/* NOTE: On MacOS and Linux, mmap seems to zero-fill anonymous /* NOTE: On MacOS and Linux, mmap seems to zero-fill anonymous
* memory as a side-effect of security. */ * memory as a side-effect of security. */
SDLState.GameMmemoryBlock = SDLState.GameMmemoryBlock =
mmap(BaseAddress, SDLState.TotalSize, PROT_READ | mmap(BaseAddress, (size_t)SDLState.TotalSize, PROT_READ |
PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
GameMemory.PermanentStorage = SDLState.GameMmemoryBlock; GameMemory.PermanentStorage = SDLState.GameMmemoryBlock;
GameMemory.TransientStorage = GameMemory.TransientStorage =
(U8 *)(GameMemory.PermanentStorage) + (U8 *)(GameMemory.PermanentStorage) +
GameMemory.PermanentStorageSize; GameMemory.PermanentStorageSize;
for(ReplayIndex = 0;
ReplayIndex < (S32)ARRAY_SIZE(SDLState.ReplayBuffers);
ReplayIndex++)
{
sdl_replay_buffer *ReplayBuffer =
&SDLState.ReplayBuffers[ReplayIndex];
ReplayBuffer->MemoryBlock = mmap(NULL,
(size_t)SDLState.TotalSize,
PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE,
-1, 0);
if(ReplayBuffer->MemoryBlock) {
} else {
/* TODO: Change this to log message. */
}
}
if(SoundOutput.Samples && if(SoundOutput.Samples &&
GameMemory.PermanentStorage && GameMemory.PermanentStorage &&
GameMemory.TransientStorage) GameMemory.TransientStorage)
@@ -775,9 +819,11 @@ S32 main(S32 argc, char *argv[])
Game = SDLLoadGameCode(SDLState.DLLPath); Game = SDLLoadGameCode(SDLState.DLLPath);
while(GlobalRunning) { while(GlobalRunning) {
thread_context Context;
S32 MonitorRefreshHz, GameUpdateHz; S32 MonitorRefreshHz, GameUpdateHz;
F32 TargetSecondsPerFrame; F32 TargetSecondsPerFrame;
U32 NewDLLWriteTime, ButtonIndex, ControllerIndex; U32 NewDLLWriteTime, ButtonIndex, ControllerIndex,
SDLMouseButtons;
game_controller_input *OldKeyboardController, game_controller_input *OldKeyboardController,
*NewKeyboardController; *NewKeyboardController;
game_controller_input ZeroController; game_controller_input ZeroController;
@@ -813,6 +859,23 @@ S32 main(S32 argc, char *argv[])
Game = SDLLoadGameCode(SDLState.DLLPath); Game = SDLLoadGameCode(SDLState.DLLPath);
} }
SDLMouseButtons = SDL_GetMouseState(&(NewInput->MouseX),
&(NewInput->MouseY));
NewInput->MouseZ = 0; /* TODO: Support mouse wheel? */
SDLProcessKeyboardMessage(&(NewInput->MouseButtons[0]),
SDL_BUTTON_LMASK & SDLMouseButtons);
SDLProcessKeyboardMessage(&(NewInput->MouseButtons[1]),
SDL_BUTTON_MMASK & SDLMouseButtons);
SDLProcessKeyboardMessage(&(NewInput->MouseButtons[2]),
SDL_BUTTON_RMASK & SDLMouseButtons);
/* WARNING: TODO: SDL_BUTTON_X1MASK and
* SDL_BUTTON_X2MASK cannot be on at the
* same time for some reason. */
SDLProcessKeyboardMessage(&(NewInput->MouseButtons[3]),
SDL_BUTTON_X1MASK & SDLMouseButtons);
SDLProcessKeyboardMessage(&(NewInput->MouseButtons[4]),
SDL_BUTTON_X2MASK & SDLMouseButtons);
OldKeyboardController = GetController(OldInput, 0); OldKeyboardController = GetController(OldInput, 0);
NewKeyboardController = GetController(NewInput, 0); NewKeyboardController = GetController(NewInput, 0);
memset(&ZeroController, 0, sizeof(ZeroController)); memset(&ZeroController, 0, sizeof(ZeroController));
@@ -997,6 +1060,8 @@ S32 main(S32 argc, char *argv[])
BytesToWrite / SoundOutput.BytesPerSample; BytesToWrite / SoundOutput.BytesPerSample;
SoundBuffer.Samples = (short *)SoundOutput.Samples; SoundBuffer.Samples = (short *)SoundOutput.Samples;
memset(&Context, 0, sizeof(Context));
Buffer.Memory = GlobalBackbuffer.Memory; Buffer.Memory = GlobalBackbuffer.Memory;
Buffer.Width = GlobalBackbuffer.Width; Buffer.Width = GlobalBackbuffer.Width;
Buffer.Height = GlobalBackbuffer.Height; Buffer.Height = GlobalBackbuffer.Height;
@@ -1010,7 +1075,8 @@ S32 main(S32 argc, char *argv[])
} }
if(Game.UpdateAndRender) if(Game.UpdateAndRender)
Game.UpdateAndRender(&GameMemory, NewInput, &Buffer, Game.UpdateAndRender(&Context, &GameMemory,
NewInput, &Buffer,
&SoundBuffer); &SoundBuffer);
SDLFillSoundBuffer(&SoundOutput, BytesToWrite); SDLFillSoundBuffer(&SoundOutput, BytesToWrite);
@@ -1044,6 +1110,7 @@ S32 main(S32 argc, char *argv[])
LastCounter = EndCounter; LastCounter = EndCounter;
#if 0
#if __x86_64__ || __i386__ #if __x86_64__ || __i386__
EndCycleCount = __rdtsc(); EndCycleCount = __rdtsc();
CyclesElapsed = EndCycleCount - LastCycleCount; CyclesElapsed = EndCycleCount - LastCycleCount;
@@ -1054,6 +1121,7 @@ S32 main(S32 argc, char *argv[])
#else #else
fprintf(stderr, "%.02f ms/f, %.02f/s\n", fprintf(stderr, "%.02f ms/f, %.02f/s\n",
MSPerFrame, FPS); MSPerFrame, FPS);
#endif
#endif #endif
SWAP(game_input *, NewInput, OldInput); SWAP(game_input *, NewInput, OldInput);
+7
View File
@@ -33,9 +33,16 @@ typedef struct sdl_sound_output {
/* NOTE: We choose 1024 only because MacOS's MAXPATHLEN says such a value. /* NOTE: We choose 1024 only because MacOS's MAXPATHLEN says such a value.
* For example, linux/limits.h PATH_MAX says 4096. */ * For example, linux/limits.h PATH_MAX says 4096. */
#define SDL_STATE_PATH_SIZE 1024 #define SDL_STATE_PATH_SIZE 1024
typedef struct sdl_replay_buffer {
char ReplayFilename[SDL_STATE_PATH_SIZE];
void *MemoryBlock;
} sdl_replay_buffer;
typedef struct sdl_state { typedef struct sdl_state {
U64 TotalSize; U64 TotalSize;
void *GameMmemoryBlock; void *GameMmemoryBlock;
sdl_replay_buffer ReplayBuffers[4];
S32 RecordingHandle; S32 RecordingHandle;
S32 InputRecordingIndex; S32 InputRecordingIndex;