diff --git a/core.h b/core.h index 34ec330..eaa7e74 100644 --- a/core.h +++ b/core.h @@ -51,13 +51,13 @@ typedef double F64; /* ---- 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 -#define Assert(x) AssertAlways(x) +#define ASSERT(x) ASSERT_ALWAYS(x) #else -#define Assert(x) (void)(x) +#define ASSERT(x) (void)(x) #endif /* ---- Helper Macros -------------------------------------------------- */ diff --git a/handmade.c b/handmade.c index ae0af4f..5dcd69a 100644 --- a/handmade.c +++ b/handmade.c @@ -63,17 +63,39 @@ static void RenderWeirdGradient(game_offscreen_buffer *Buffer, S32 XOffset, } } -void UpdateAndRender(game_memory *Memory, game_input *Input, - game_offscreen_buffer *Buffer, +static void RenderRectangle(game_offscreen_buffer *Buffer, S32 MouseX, + 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_state *GameState; U32 ControllerIndex; - Assert((&Input->Controllers[0].u.buttons.Terminator - + ASSERT((&Input->Controllers[0].u.buttons.Terminator - &Input->Controllers[0].u.Buttons[0]) == ARRAY_SIZE(Input->Controllers[0].u.Buttons)); - Assert(sizeof(game_state) <= Memory->PermanentStorageSize); + ASSERT(sizeof(game_state) <= Memory->PermanentStorageSize); GameState = (game_state *)Memory->PermanentStorage; if(!Memory->IsInitialized) { @@ -82,12 +104,13 @@ void UpdateAndRender(game_memory *Memory, game_input *Input, debug_read_file_result BitmapMemory; FileName = "/home/igor/Developer/handmade/sdl_handmade.cpp"; - BitmapMemory = Memory->DEBUGPlatformReadEntireFile(FileName); + BitmapMemory = Memory->DEBUGPlatformReadEntireFile(Thread, FileName); if(BitmapMemory.Contents) { - Memory->DEBUGPlatformWriteEntireFile("test.out", + Memory->DEBUGPlatformWriteEntireFile(Thread, "test.out", BitmapMemory.ContentsSize, BitmapMemory.Contents); - Memory->DEBUGPlatformFreeFileMemory(BitmapMemory.Contents); + Memory->DEBUGPlatformFreeFileMemory(Thread, + BitmapMemory.Contents); } #endif @@ -133,4 +156,13 @@ void UpdateAndRender(game_memory *Memory, game_input *Input, GameOutputSound(GameState, SoundBuffer, GameState->ToneHz); RenderWeirdGradient(Buffer, GameState->BlueOffset, 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); } diff --git a/handmade.h b/handmade.h index d11478e..8a0283f 100644 --- a/handmade.h +++ b/handmade.h @@ -7,16 +7,22 @@ /* NOTE: Servcies that the platform layer provides to the game. */ /* --------------------------------------------------------------------- */ +typedef struct thread_context { + S32 Placeholder; +} thread_context; + #if BUILD_INTERNAL typedef struct debug_read_file_result { U32 ContentsSize; void *Contents; } debug_read_file_result; -debug_read_file_result DEBUGPlatformReadEntireFile(const char *Filename); -B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, +debug_read_file_result DEBUGPlatformReadEntireFile(thread_context *Thread, + const char *Filename); +B32 DEBUGPlatformWriteEntireFile(thread_context *Thread, + const char *Filename, U32 MemorySize, void *Memory); -void DEBUGPlatformFreeFileMemory(void *Memory); +void DEBUGPlatformFreeFileMemory(thread_context *Thread, void *Memory); #endif /* --------------------------------------------------------------------- */ @@ -77,6 +83,9 @@ typedef struct game_controller_input { } game_controller_input; typedef struct game_input { + game_button_state MouseButtons[5]; + S32 MouseX, MouseY, MouseZ; /* NOTE: MouseZ is the wheel. */ + /* TODO: Insert clock value here . . . */ game_controller_input Controllers[5]; } game_input; @@ -85,7 +94,7 @@ game_controller_input *GetController(game_input *Input, S32 ControllerIndex) { game_controller_input *Result; - Assert((U32)ControllerIndex < ARRAY_SIZE(Input->Controllers)); + ASSERT((U32)ControllerIndex < ARRAY_SIZE(Input->Controllers)); Result = &(Input->Controllers[ControllerIndex]); return Result; } @@ -104,9 +113,11 @@ typedef struct game_memory { layer.) */ #if BUILD_INTERNAL - debug_read_file_result (*DEBUGPlatformReadEntireFile)(const char *); - B32 (*DEBUGPlatformWriteEntireFile)(const char *, U32, void *); - void (*DEBUGPlatformFreeFileMemory)(void *); + debug_read_file_result (*DEBUGPlatformReadEntireFile)( + thread_context *Thread,const char *); + B32 (*DEBUGPlatformWriteEntireFile)(thread_context *Thread, + const char *, U32, void *); + void (*DEBUGPlatformFreeFileMemory)(thread_context *Thread, void *); #endif } game_memory; @@ -115,8 +126,8 @@ typedef struct game_memory { F32 SecondsElapsed; } game_clocks;*/ -void UpdateAndRender(game_memory *Memory, game_input *Input, - game_offscreen_buffer *Buffer, +void UpdateAndRender(thread_context *Thread, game_memory *Memory, + game_input *Input, game_offscreen_buffer *Buffer, game_sound_output_buffer *SoundBuffer); /* diff --git a/sdl_handmade.c b/sdl_handmade.c index 85e8539..bc4a181 100644 --- a/sdl_handmade.c +++ b/sdl_handmade.c @@ -8,7 +8,7 @@ #include #include /* mmap */ #include /* malloc, calloc */ -#include /* memset */ +#include /* memset, memcpy */ #include #include /* fstat */ @@ -47,12 +47,13 @@ static U32 SafeTruncateUInt64(U64 Value) { U32 Result; - Assert(Value <= 0xFFFFFFFF); + ASSERT(Value <= 0xFFFFFFFF); Result = (U32)Value; 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; S32 FileHandle; @@ -101,7 +102,8 @@ debug_read_file_result DEBUGPlatformReadEntireFile(const char *Filename) return Result; } -B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, +B32 DEBUGPlatformWriteEntireFile(thread_context *Thread, + const char *Filename, U32 MemorySize, void *Memory) { S32 FileHandle; @@ -132,7 +134,7 @@ B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, return TRUE; } -void DEBUGPlatformFreeFileMemory(void *Memory) +void DEBUGPlatformFreeFileMemory(thread_context *Thread, void *Memory) { if(Memory) free(Memory); @@ -254,9 +256,10 @@ static void SDLClearSoundBuffer(sdl_sound_output *SoundOutput) static void SDLProcessKeyboardMessage(game_button_state *NewState, B32 IsDown) { - Assert(NewState->EndedDown != IsDown); - NewState->EndedDown = IsDown; - ++NewState->HalfTransitionCount; + if(NewState->EndedDown != IsDown) { + NewState->EndedDown = IsDown; + ++NewState->HalfTransitionCount; + } } static void SDLProcessInputDigitalButton(SDL_GameController *Controller, @@ -308,7 +311,7 @@ static void HandleEvent(SDL_Event *Event) } break; 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() */ } } break; @@ -322,30 +325,43 @@ static void SDLGetInputFileLocation(sdl_state *SDLState, char *path, { const char *file_name = "loop.hmi"; - Assert(SlotIndex == 1); + ASSERT(SlotIndex == 1); 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, S32 InputRecordingIndex) { - char FileName[SDL_STATE_PATH_SIZE]; + sdl_replay_buffer *ReplayBuffer = + SDLGetReplayBuffer(SDLState, InputRecordingIndex); + if(ReplayBuffer->MemoryBlock) { + char FileName[SDL_STATE_PATH_SIZE]; - SDLGetInputFileLocation(SDLState, FileName, sizeof(FileName), - InputRecordingIndex); + SDLGetInputFileLocation(SDLState, FileName, sizeof(FileName), + InputRecordingIndex); - SDLState->InputRecordingIndex = InputRecordingIndex; + SDLState->InputRecordingIndex = InputRecordingIndex; - if(unlink(FileName) != 0) { - /* TODO: Diagnostics . . . */ + if(unlink(FileName) != 0) { + /* TODO: Diagnostics . . . */ + } + + 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)); */ + memcpy(ReplayBuffer->MemoryBlock, SDLState->GameMmemoryBlock, + (size_t)(SDLState->TotalSize)); } - - 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) @@ -357,18 +373,24 @@ static void SDLEndRecordingInput(sdl_state *SDLState) static void SDLBeginInputPlayback(sdl_state *SDLState, S32 InputPlayingIndex) { - char FileName[SDL_STATE_PATH_SIZE]; - ssize_t size; + sdl_replay_buffer *ReplayBuffer = + SDLGetReplayBuffer(SDLState, InputPlayingIndex); + if(ReplayBuffer->MemoryBlock) { + char FileName[SDL_STATE_PATH_SIZE]; + ssize_t size; - SDLGetInputFileLocation(SDLState, FileName, sizeof(FileName), - InputPlayingIndex); + SDLGetInputFileLocation(SDLState, FileName, sizeof(FileName), + InputPlayingIndex); - SDLState->InputPlayingIndex = InputPlayingIndex; - SDLState->PlaybackHandle = - open(FileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | - S_IRGRP | S_IROTH); - size = read(SDLState->PlaybackHandle, SDLState->GameMmemoryBlock, - (size_t)(SDLState->TotalSize)); + SDLState->InputPlayingIndex = InputPlayingIndex; + SDLState->PlaybackHandle = + open(FileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | + S_IRGRP | S_IROTH); + /* size = read(SDLState->PlaybackHandle, SDLState->GameMmemoryBlock, + (size_t)(SDLState->TotalSize)); */ + memcpy(SDLState->GameMmemoryBlock, ReplayBuffer->MemoryBlock, + (size_t)(SDLState->TotalSize)); + } } static void SDLEndInputPlayback(sdl_state *SDLState) @@ -475,11 +497,15 @@ static void SDLProcessMessages(sdl_state *SDLState, #if BUILD_INTERNAL if(KeyCode == SDLK_l) { - if(SDLState->InputRecordingIndex == 0) { - SDLBeginRecordingInput(SDLState, 1); + if(SDLState->InputPlayingIndex == 0) { + if(SDLState->InputRecordingIndex == 0) { + SDLBeginRecordingInput(SDLState, 1); + } else { + SDLEndRecordingInput(SDLState); + SDLBeginInputPlayback(SDLState, 1); + } } else { - SDLEndRecordingInput(SDLState); - SDLBeginInputPlayback(SDLState, 1); + SDLEndInputPlayback(SDLState); } } #endif @@ -550,8 +576,8 @@ typedef struct sdl_game_code { void *GameCodeDLL; U32 DLLLastWriteTime; - void (*UpdateAndRender)(game_memory *, game_input *, - game_offscreen_buffer *, + void (*UpdateAndRender)(thread_context *Thread, game_memory *, + game_input *, game_offscreen_buffer *, game_sound_output_buffer *); B32 IsValid; @@ -582,9 +608,9 @@ static sdl_game_code SDLLoadGameCode(char *DLLPath) Result.DLLLastWriteTime = GetLastWriteTime(DLLPath); Result.UpdateAndRender = - (void(*)(game_memory *, game_input *, game_offscreen_buffer *, - game_sound_output_buffer *))dlsym(Result.GameCodeDLL, - "UpdateAndRender"); + (void(*)(thread_context *, game_memory *, game_input *, + game_offscreen_buffer *, game_sound_output_buffer *)) + dlsym(Result.GameCodeDLL, "UpdateAndRender"); if(!Result.UpdateAndRender) { /* TODO: Diagnostic. dlerror() */ } @@ -696,6 +722,7 @@ S32 main(S32 argc, char *argv[]) sdl_window_dimension Dimension; sdl_sound_output SoundOutput; game_memory GameMemory; + S32 ReplayIndex; #if BUILD_DEBUG 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 * memory as a side-effect of security. */ SDLState.GameMmemoryBlock = - mmap(BaseAddress, SDLState.TotalSize, PROT_READ | + mmap(BaseAddress, (size_t)SDLState.TotalSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GameMemory.PermanentStorage = SDLState.GameMmemoryBlock; GameMemory.TransientStorage = (U8 *)(GameMemory.PermanentStorage) + 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 && GameMemory.PermanentStorage && GameMemory.TransientStorage) @@ -775,9 +819,11 @@ S32 main(S32 argc, char *argv[]) Game = SDLLoadGameCode(SDLState.DLLPath); while(GlobalRunning) { + thread_context Context; S32 MonitorRefreshHz, GameUpdateHz; F32 TargetSecondsPerFrame; - U32 NewDLLWriteTime, ButtonIndex, ControllerIndex; + U32 NewDLLWriteTime, ButtonIndex, ControllerIndex, + SDLMouseButtons; game_controller_input *OldKeyboardController, *NewKeyboardController; game_controller_input ZeroController; @@ -813,6 +859,23 @@ S32 main(S32 argc, char *argv[]) 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); NewKeyboardController = GetController(NewInput, 0); memset(&ZeroController, 0, sizeof(ZeroController)); @@ -997,6 +1060,8 @@ S32 main(S32 argc, char *argv[]) BytesToWrite / SoundOutput.BytesPerSample; SoundBuffer.Samples = (short *)SoundOutput.Samples; + memset(&Context, 0, sizeof(Context)); + Buffer.Memory = GlobalBackbuffer.Memory; Buffer.Width = GlobalBackbuffer.Width; Buffer.Height = GlobalBackbuffer.Height; @@ -1010,7 +1075,8 @@ S32 main(S32 argc, char *argv[]) } if(Game.UpdateAndRender) - Game.UpdateAndRender(&GameMemory, NewInput, &Buffer, + Game.UpdateAndRender(&Context, &GameMemory, + NewInput, &Buffer, &SoundBuffer); SDLFillSoundBuffer(&SoundOutput, BytesToWrite); @@ -1044,6 +1110,7 @@ S32 main(S32 argc, char *argv[]) LastCounter = EndCounter; +#if 0 #if __x86_64__ || __i386__ EndCycleCount = __rdtsc(); CyclesElapsed = EndCycleCount - LastCycleCount; @@ -1054,6 +1121,7 @@ S32 main(S32 argc, char *argv[]) #else fprintf(stderr, "%.02f ms/f, %.02f/s\n", MSPerFrame, FPS); +#endif #endif SWAP(game_input *, NewInput, OldInput); diff --git a/sdl_handmade.h b/sdl_handmade.h index d27a903..58b1207 100644 --- a/sdl_handmade.h +++ b/sdl_handmade.h @@ -33,9 +33,16 @@ typedef struct sdl_sound_output { /* NOTE: We choose 1024 only because MacOS's MAXPATHLEN says such a value. * For example, linux/limits.h PATH_MAX says 4096. */ #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 { U64 TotalSize; void *GameMmemoryBlock; + sdl_replay_buffer ReplayBuffers[4]; S32 RecordingHandle; S32 InputRecordingIndex;