diff --git a/Makefile b/Makefile index 00a098e..db13fdf 100644 --- a/Makefile +++ b/Makefile @@ -15,18 +15,19 @@ endif CC = clang UFLAGS = -# NOTE: We comply with C89 (plain C), however the standard has no 64-bit -# support. But, every compiler at that time supported long long, -# hence we ignore the incompliance in our code. -# NOTE: We allow function declrations with specifying void -# (ex, void test() is allowed). -FLAGS = -ansi -pedantic -pedantic-errors -Wno-long-long \ - -Wno-overlength-strings -Wincompatible-pointer-types \ - -Wint-conversion -Wimplicit-int-float-conversion -Wformat \ - -Wno-strict-prototypes -Wall -Wextra -fno-caret-diagnostics \ - -fno-show-column -Wno-missing-field-initializers \ +# NOTE: This project's code bases itself on C89 (plain C) standard, however +# allowing a few convenient features of newer standards. Mid-scope +# variable declarations, comments that begin with '//', long long, +# designated initializers, compound literals, and anonymous structures +# are allowed as they are convenient. Everything else that has come out +# of modern standards is pretty much destructive and should not be used. +FLAGS = -Wall -Wextra \ + -Wincompatible-pointer-types \ + -Wint-conversion -Wimplicit-int-float-conversion -Wformat \ + -Wno-strict-prototypes -Wno-missing-field-initializers \ -Wno-unused-function -Wno-unused-parameter -Wno-unused-variable \ - -Wno-unused-but-set-variable + -Wno-unused-but-set-variable \ + -fno-caret-diagnostics -fno-show-column ifeq ($(DETECTED_OS),macos) UFLAGS = -glldb diff --git a/handmade.c b/handmade.c index 5d362e2..407252f 100644 --- a/handmade.c +++ b/handmade.c @@ -5,7 +5,7 @@ #include "handmade_intrinsics.h" #include "handmade_random.h" #include "handmade_tile.h" -#include "handmade_tile.cpp" +#include "handmade_tile.c" #include /* memset */ @@ -44,12 +44,10 @@ static void GameOutputSound(game_state *GameState, static void ClearBackground(game_offscreen_buffer *Buffer) { - S32 Width, Height, X; + S32 Width = Buffer->Width; + S32 Height = Buffer->Height; - Width = Buffer->Width; - Height = Buffer->Height; - - for(X = 0; X < Width * Height; X++) { + for(S32 X = 0; X < Width * Height; X++) { U32 *Pixel = &((U32 *)Buffer->Memory)[X]; *Pixel = 0xFFFFFF; } @@ -68,10 +66,6 @@ static void DrawRectangle(game_offscreen_buffer *Buffer, S32 Width = Buffer->Width; S32 Height = Buffer->Height; - U8 *Row; - S32 Y, X; - U32 Color; - if(MinX < 0) MinX = 0; if(MinY < 0) @@ -82,15 +76,15 @@ static void DrawRectangle(game_offscreen_buffer *Buffer, if(MaxY > Height) MaxY = Height; - Color = (U32)((RoundF32toS32(R * 255.0f) << 16) | - (RoundF32toS32(G * 255.0f) << 8) | - (RoundF32toS32(B * 255.0f) << 0)); + U32 Color = (U32)((RoundF32toS32(R * 255.0f) << 16) | + (RoundF32toS32(G * 255.0f) << 8) | + (RoundF32toS32(B * 255.0f) << 0)); - Row = ((U8 *)Buffer->Memory + MinX*Buffer->BytesPerPixel + - MinY*Buffer->Pitch); - for(Y = MinY; Y < MaxY; Y++) { + U8 *Row = ((U8 *)Buffer->Memory + MinX*Buffer->BytesPerPixel + + MinY*Buffer->Pitch); + for(S32 Y = MinY; Y < MaxY; Y++) { U32 *Pixel = (U32 *)Row; - for(X = MinX; X < MaxX; X++) { + for(S32 X = MinX; X < MaxX; X++) { *(U32 *)Pixel = Color; Pixel++; } @@ -102,60 +96,36 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer, game_sound_output_buffer *SoundBuffer) { -#define TILEMAP_COUNT_X 256 -#define TILEMAP_COUNT_Y 256 - - game_state *GameState; - U32 ControllerIndex; - - F32 PlayerR, PlayerG, PlayerB, - PlayerWidth, PlayerHeight, - PlayerLeft, PlayerTop; - F32 ScreenCenterX, ScreenCenterY; - - world *World; - tile_map *TileMap; - - S32 TileSideInPixels; - F32 MetersToPixels; 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); - PlayerHeight = 1.4f; - PlayerWidth = 0.75f * PlayerHeight; +#define TILEMAP_COUNT_X 256 +#define TILEMAP_COUNT_Y 256 + + game_state *GameState; + + F32 PlayerHeight = 1.4f; + F32 PlayerWidth = 0.75f * PlayerHeight; GameState = (game_state *)Memory->PermanentStorage; if(!Memory->IsInitialized) { - U32 TilesPerWidth, TilesPerHeight; - - U32 ScreenX, ScreenY; - U32 ScreenIndex; - - tile_map *TileMap; - world *World; - - U32 AbsTileZ; - B32 DoorTop, DoorBottom, DoorLeft, DoorRight, DoorUp, DoorDown; - - U32 RandomNumberIndex; - GameState->PlayerP.AbsTileX = 2; GameState->PlayerP.AbsTileY = 3; - GameState->PlayerP.TileRelX = 5.0f; - GameState->PlayerP.TileRelY = 5.0f; + GameState->PlayerP.OffsetX = 5.0f; + GameState->PlayerP.OffsetY = 5.0f; InitializeArena(&GameState->WorldArena, Memory->PermanentStorageSize - sizeof(game_state), (U8 *)Memory->PermanentStorage + sizeof(game_state)); GameState->World = PUSH_STRUCT(&GameState->WorldArena, world); - World = GameState->World; + world *World = GameState->World; World->TileMap = PUSH_STRUCT(&GameState->WorldArena, tile_map); - TileMap = World->TileMap; + tile_map *TileMap = World->TileMap; TileMap->ChunkShift = 4; TileMap->ChunkMask = (1 << TileMap->ChunkShift) - 1; @@ -174,34 +144,37 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, TileMap->TileSideInMeters = 1.4f; - RandomNumberIndex = 0; + U32 RandomNumberIndex = 0; - TilesPerWidth = 17; - TilesPerHeight = 9; - ScreenX = 0; - ScreenY = 0; + U32 TilesPerWidth = 17; + U32 TilesPerHeight = 9; + U32 ScreenX = 0; + U32 ScreenY = 0; - AbsTileZ = 0; - - DoorTop = FALSE; - DoorBottom = FALSE; - DoorLeft = FALSE; - DoorRight = FALSE; - DoorUp = FALSE; - DoorDown = FALSE; - for(ScreenIndex = 0; ScreenIndex < 100; ScreenIndex++) { - /* TODO: Random number generator. */ - U32 TileX, TileY; - U32 RandomChoice; + U32 AbsTileZ = 0; + B32 DoorTop = FALSE; + B32 DoorBottom = FALSE; + B32 DoorLeft = FALSE; + B32 DoorRight = FALSE; + B32 DoorUp = FALSE; + B32 DoorDown = FALSE; + for(U32 ScreenIndex = 0; ScreenIndex < 100; ScreenIndex++) { ASSERT(RandomNumberIndex < ARRAY_SIZE(RandomNumberTable)); + + /* TODO: Random number generator. */ + U32 RandomChoice; if(DoorUp || DoorDown) { RandomChoice = RandomNumberTable[RandomNumberIndex++] % 2; } else { RandomChoice = RandomNumberTable[RandomNumberIndex++] % 3; } + B32 CreatedZDoor = FALSE; + if(RandomChoice == 2) { + CreatedZDoor = TRUE; + if(AbsTileZ == 0) { DoorUp = TRUE; } else { @@ -213,8 +186,8 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, DoorTop = TRUE; } - for(TileY = 0; TileY < TilesPerHeight; TileY++) { - for(TileX = 0; TileX < TilesPerWidth; TileX++) { + for(U32 TileY = 0; TileY < TilesPerHeight; TileY++) { + for(U32 TileX = 0; TileX < TilesPerWidth; TileX++) { U32 AbsTileX = ScreenX * TilesPerWidth + TileX; U32 AbsTileY = ScreenY * TilesPerHeight + TileY; @@ -259,16 +232,12 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, } } - DoorLeft = DoorRight; DoorBottom = DoorTop; - if(DoorUp) { - DoorDown = TRUE; - DoorUp = FALSE; - } else if (DoorDown) { - DoorUp = TRUE; - DoorDown = FALSE; + if(CreatedZDoor) { + DoorDown = !DoorDown; + DoorUp = !DoorUp; } else { DoorUp = FALSE; DoorDown = FALSE; @@ -293,13 +262,13 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, Memory->IsInitialized = TRUE; } - World = GameState->World; - TileMap = World->TileMap; + world *World = GameState->World; + tile_map *TileMap = World->TileMap; - TileSideInPixels = 60; - MetersToPixels = (F32)TileSideInPixels / TileMap->TileSideInMeters; + S32 TileSideInPixels = 60; + F32 MetersToPixels = (F32)TileSideInPixels / TileMap->TileSideInMeters; - for(ControllerIndex = 0; + for(U32 ControllerIndex = 0; ControllerIndex < ARRAY_SIZE(Input->Controllers); ControllerIndex++) { @@ -310,8 +279,6 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, F32 dPlayerX = 0.0f; F32 dPlayerY = 0.0f; - tile_map_position NewPlayerP, PlayerLeft, PlayerRight; - if(Controller->u.buttons.MoveUp.EndedDown) { dPlayerY = 1.0f; } @@ -325,48 +292,58 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, dPlayerX = 1.0f; } - { - F32 PlayerSpeed = 2.0f; + F32 PlayerSpeed = 2.0f; - if(Controller->u.buttons.ActionUp.EndedDown) - PlayerSpeed = 10.0f; + if(Controller->u.buttons.ActionUp.EndedDown) + PlayerSpeed = 10.0f; - dPlayerX *= PlayerSpeed; - dPlayerY *= PlayerSpeed; - } + dPlayerX *= PlayerSpeed; + dPlayerY *= PlayerSpeed; + tile_map_position NewPlayerP; NewPlayerP = GameState->PlayerP; - NewPlayerP.TileRelX += Input->dtForFrame*dPlayerX; - NewPlayerP.TileRelY += Input->dtForFrame*dPlayerY; + NewPlayerP.OffsetX += Input->dtForFrame*dPlayerX; + NewPlayerP.OffsetY += Input->dtForFrame*dPlayerY; NewPlayerP = RecannonicalizePosition(TileMap, NewPlayerP); + tile_map_position PlayerLeft; PlayerLeft = NewPlayerP; - PlayerLeft.TileRelX -= 0.5f*PlayerWidth; + PlayerLeft.OffsetX -= 0.5f*PlayerWidth; PlayerLeft = RecannonicalizePosition(TileMap, PlayerLeft); + tile_map_position PlayerRight; PlayerRight = NewPlayerP; - PlayerRight.TileRelX += 0.5f*PlayerWidth; + PlayerRight.OffsetX += 0.5f*PlayerWidth; PlayerRight = RecannonicalizePosition(TileMap, PlayerRight); if(IsTileMapPointEmpty(TileMap, NewPlayerP) && IsTileMapPointEmpty(TileMap, PlayerLeft) && IsTileMapPointEmpty(TileMap, PlayerRight)) { + if(!AreOnSameTile(&GameState->PlayerP, &NewPlayerP)) { + U32 NewTileValue = + GetTileValueByPos(TileMap, NewPlayerP); + + if(NewTileValue == 3) { + NewPlayerP.AbsTileZ++; + } else if(NewTileValue == 4) { + NewPlayerP.AbsTileZ--; + } + } GameState->PlayerP = NewPlayerP; } } } - ScreenCenterX = 0.5f * (F32)Buffer->Width; - ScreenCenterY = 0.5f * (F32)Buffer->Height; + F32 ScreenCenterX = 0.5f * (F32)Buffer->Width; + F32 ScreenCenterY = 0.5f * (F32)Buffer->Height; DrawRectangle(Buffer, 0.0f, 0.0f, (F32)Buffer->Width, (F32)Buffer->Height, 0.0f, 1.0f, 0.0f); { - S32 RelRow, RelColumn; - for(RelRow = -10; RelRow < 10; RelRow++) { - for(RelColumn = -20; RelColumn < 20; RelColumn++) { + for(S32 RelRow = -10; RelRow < 10; RelRow++) { + for(S32 RelColumn = -20; RelColumn < 20; RelColumn++) { U32 Column = GameState->PlayerP.AbsTileX + RelColumn; U32 Row = GameState->PlayerP.AbsTileY + RelRow; @@ -376,8 +353,6 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, GameState->PlayerP.AbsTileZ); if(TileID > 0) { - F32 CenterX, CenterY, MinX, MinY, MaxX, MaxY; - F32 Gray = 0.5f; if(TileID == 2) { Gray = 1.0f; @@ -394,16 +369,16 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, } - CenterX = ScreenCenterX - - MetersToPixels*GameState->PlayerP.TileRelX + - (F32)RelColumn*(F32)TileSideInPixels; - CenterY = ScreenCenterY + - MetersToPixels*GameState->PlayerP.TileRelY - - (F32)RelRow*(F32)TileSideInPixels; - MinX = CenterX - 0.5f*(F32)TileSideInPixels; - MinY = CenterY - 0.5f*(F32)TileSideInPixels; - MaxX = CenterX + 0.5f*(F32)TileSideInPixels; - MaxY = CenterY + 0.5f*(F32)TileSideInPixels; + F32 CenterX = ScreenCenterX - + MetersToPixels*GameState->PlayerP.OffsetX + + (F32)RelColumn*(F32)TileSideInPixels; + F32 CenterY = ScreenCenterY + + MetersToPixels*GameState->PlayerP.OffsetY - + (F32)RelRow*(F32)TileSideInPixels; + F32 MinX = CenterX - 0.5f*(F32)TileSideInPixels; + F32 MinY = CenterY - 0.5f*(F32)TileSideInPixels; + F32 MaxX = CenterX + 0.5f*(F32)TileSideInPixels; + F32 MaxY = CenterY + 0.5f*(F32)TileSideInPixels; DrawRectangle(Buffer, MinX, MinY, MaxX, MaxY, Gray, Gray, Gray); @@ -412,11 +387,11 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, } } - PlayerR = 1.0f; - PlayerG = 0.0f; - PlayerB = 0.0f; - PlayerLeft = ScreenCenterX - 0.5f * MetersToPixels*PlayerWidth; - PlayerTop = ScreenCenterY - MetersToPixels*PlayerHeight; + F32 PlayerR = 1.0f; + F32 PlayerG = 0.0f; + F32 PlayerB = 0.0f; + F32 PlayerLeft = ScreenCenterX - 0.5f * MetersToPixels*PlayerWidth; + F32 PlayerTop = ScreenCenterY - MetersToPixels*PlayerHeight; DrawRectangle(Buffer, PlayerLeft, PlayerTop, PlayerLeft + MetersToPixels*PlayerWidth, diff --git a/handmade_tile.cpp b/handmade_tile.c similarity index 74% rename from handmade_tile.cpp rename to handmade_tile.c index b04a12b..525c71b 100644 --- a/handmade_tile.cpp +++ b/handmade_tile.c @@ -21,29 +21,6 @@ static tile_chunk *GetTileChunk(tile_map *TileMap, return TileChunk; } -static void CannonicalizeCoord(tile_map *TileMap, U32 *Tile, F32 *TileRel) -{ - /* NOTE: The world is assumed to be toroidal topology. If you step off - one end, you come back on the other. */ - S32 Offset = RoundF32toS32(*TileRel / TileMap->TileSideInMeters); - *Tile += Offset; - *TileRel -= (F32)Offset * TileMap->TileSideInMeters; - - ASSERT(*TileRel >= -0.5f*TileMap->TileSideInMeters); - ASSERT(*TileRel <= 0.5f*TileMap->TileSideInMeters); -} - -static tile_map_position RecannonicalizePosition(tile_map *TileMap, - tile_map_position Pos) -{ - tile_map_position Result = Pos; - - CannonicalizeCoord(TileMap, &Result.AbsTileX, &Result.TileRelX); - CannonicalizeCoord(TileMap, &Result.AbsTileY, &Result.TileRelY); - - return Result; -} - static tile_chunk_position GetChunkPositionFor(tile_map *TileMap, U32 AbsTileX, U32 AbsTileY, @@ -63,26 +40,14 @@ static tile_chunk_position GetChunkPositionFor(tile_map *TileMap, static U32 GetTileValueUnchecked(tile_map *TileMap, tile_chunk *TileChunk, U32 TileX, U32 TileY) { - U32 TileChunkValue; - ASSERT(TileChunk); ASSERT(TileX < TileMap->ChunkDim); ASSERT(TileY < TileMap->ChunkDim); - TileChunkValue = TileChunk->Tiles[TileY * TileMap->ChunkDim + TileX]; + U32 TileChunkValue = TileChunk->Tiles[TileY * TileMap->ChunkDim + TileX]; return TileChunkValue; } -static void SetTileValueUnchecked(tile_map *TileMap, tile_chunk *TileChunk, - U32 TileX, U32 TileY, U32 TileValue) -{ - ASSERT(TileChunk); - ASSERT(TileX < TileMap->ChunkDim); - ASSERT(TileY < TileMap->ChunkDim); - - TileChunk->Tiles[TileY * TileMap->ChunkDim + TileX] = TileValue; -} - static U32 GetTileChunkValue(tile_map *TileMap, tile_chunk *TileChunk, U32 TestTileX, U32 TestTileY) { @@ -98,18 +63,6 @@ static U32 GetTileChunkValue(tile_map *TileMap, tile_chunk *TileChunk, return TileChunkValue; } -static void SetTileChunkValue(tile_map *TileMap, tile_chunk *TileChunk, - U32 TestTileX, U32 TestTileY, - U32 TileValue) -{ - if(TileChunk && TileChunk->Tiles) { - SetTileValueUnchecked(TileMap, - TileChunk, - TestTileX, TestTileY, - TileValue); - } -} - static U32 GetTileValue(tile_map *TileMap, U32 AbsTileX, U32 AbsTileY, U32 AbsTileZ) { @@ -127,15 +80,43 @@ static U32 GetTileValue(tile_map *TileMap, return TileChunkValue; } -static B32 IsTileMapPointEmpty(tile_map *TileMap, tile_map_position CanPos) +static U32 GetTileValueByPos(tile_map *TileMap, tile_map_position Pos) { - B32 Empty; - U32 TileChunkValue = GetTileValue(TileMap, - CanPos.AbsTileX, - CanPos.AbsTileY, - CanPos.AbsTileZ); - Empty = (TileChunkValue == 1); + Pos.AbsTileX, + Pos.AbsTileY, + Pos.AbsTileZ); + return TileChunkValue; +} + +static void SetTileValueUnchecked(tile_map *TileMap, tile_chunk *TileChunk, + U32 TileX, U32 TileY, U32 TileValue) +{ + ASSERT(TileChunk); + ASSERT(TileX < TileMap->ChunkDim); + ASSERT(TileY < TileMap->ChunkDim); + + TileChunk->Tiles[TileY * TileMap->ChunkDim + TileX] = TileValue; +} + +static void SetTileChunkValue(tile_map *TileMap, tile_chunk *TileChunk, + U32 TestTileX, U32 TestTileY, + U32 TileValue) +{ + if(TileChunk && TileChunk->Tiles) { + SetTileValueUnchecked(TileMap, + TileChunk, + TestTileX, TestTileY, + TileValue); + } +} + +static B32 IsTileMapPointEmpty(tile_map *TileMap, tile_map_position Pos) +{ + U32 TileChunkValue = GetTileValueByPos(TileMap, Pos); + B32 Empty = ((TileChunkValue == 1) || + (TileChunkValue == 3) || + (TileChunkValue == 4)); return Empty; } @@ -144,22 +125,22 @@ static void SetTileValue(memory_arena *Arena, U32 AbsTileX, U32 AbsTileY, U32 AbsTileZ, U32 TileValue) { - tile_chunk_position ChunkPos; - tile_chunk *TileChunk; - ChunkPos = GetChunkPositionFor(TileMap, AbsTileX, AbsTileY, AbsTileZ); - TileChunk = GetTileChunk(TileMap, - ChunkPos.TileChunkX, - ChunkPos.TileChunkY, - ChunkPos.TileChunkZ); + tile_chunk_position ChunkPos = GetChunkPositionFor(TileMap, + AbsTileX, + AbsTileY, + AbsTileZ); + tile_chunk *TileChunk = GetTileChunk(TileMap, + ChunkPos.TileChunkX, + ChunkPos.TileChunkY, + ChunkPos.TileChunkZ); ASSERT(TileChunk); if(!TileChunk->Tiles) { U32 TileCount = TileMap->ChunkDim*TileMap->ChunkDim; - U32 TileIndex; TileChunk->Tiles = PUSH_ARRAY(Arena, TileCount, U32); - for(TileIndex = 0; TileIndex < TileCount; TileIndex++) { + for(U32 TileIndex = 0; TileIndex < TileCount; TileIndex++) { TileChunk->Tiles[TileIndex] = 1; } @@ -170,3 +151,38 @@ static void SetTileValue(memory_arena *Arena, ChunkPos.RelTileY, TileValue); } + +// +// TODO: Do these belong more in a "positioning" or "geometry" file? +// + +static void CannonicalizeCoord(tile_map *TileMap, U32 *Tile, F32 *TileRel) +{ + // NOTE: The world is assumed to be toroidal topology. If you step off + // one end, you come back on the other. + S32 Offset = RoundF32toS32(*TileRel / TileMap->TileSideInMeters); + *Tile += Offset; + *TileRel -= (F32)Offset * TileMap->TileSideInMeters; + + ASSERT(*TileRel >= -0.5f*TileMap->TileSideInMeters); + ASSERT(*TileRel <= 0.5f*TileMap->TileSideInMeters); +} + +static tile_map_position RecannonicalizePosition(tile_map *TileMap, + tile_map_position Pos) +{ + tile_map_position Result = Pos; + + CannonicalizeCoord(TileMap, &Result.AbsTileX, &Result.OffsetX); + CannonicalizeCoord(TileMap, &Result.AbsTileY, &Result.OffsetY); + + return Result; +} + +static B32 AreOnSameTile(tile_map_position *A, tile_map_position *B) +{ + B32 Result = ((A->AbsTileX == B->AbsTileX) && + (A->AbsTileY == B->AbsTileY) && + (A->AbsTileZ == B->AbsTileZ)); + return Result; +} diff --git a/handmade_tile.h b/handmade_tile.h index e2107f8..0d0d345 100644 --- a/handmade_tile.h +++ b/handmade_tile.h @@ -6,9 +6,9 @@ typedef struct tile_map_position { U32 AbsTileY; U32 AbsTileZ; - /* NOTE: Tile-relative X and Y. */ - F32 TileRelX; - F32 TileRelY; + /* NOTE: X and Y relative to tile center. */ + F32 OffsetX; + F32 OffsetY; } tile_map_position; typedef struct tile_chunk_position { diff --git a/sdl_handmade.c b/sdl_handmade.c index 4f80b90..839ca3f 100644 --- a/sdl_handmade.c +++ b/sdl_handmade.c @@ -50,10 +50,8 @@ static S32 str_len(char *str) static U32 SafeTruncateUInt64(U64 Value) { - U32 Result; - ASSERT(Value <= 0xFFFFFFFF); - Result = (U32)Value; + U32 Result = (U32)Value; return Result; } @@ -61,17 +59,14 @@ debug_read_file_result DEBUGPlatformReadEntireFile(thread_context *Thread, const char *Filename) { debug_read_file_result Result; - S32 FileHandle; - struct stat FileStatus; - U32 BytesToRead; - U8 *NextByteLocation; - memset(&Result, 0, sizeof(Result)); - FileHandle = open(Filename, O_RDONLY); + + S32 FileHandle = open(Filename, O_RDONLY); if(FileHandle == -1) { return Result; } + struct stat FileStatus; if(fstat(FileHandle, &FileStatus) == -1) { close(FileHandle); return Result; @@ -85,12 +80,10 @@ debug_read_file_result DEBUGPlatformReadEntireFile(thread_context *Thread, return Result; } - BytesToRead = Result.ContentsSize; - NextByteLocation = (U8 *)Result.Contents; + U32 BytesToRead = Result.ContentsSize; + U8 *NextByteLocation = (U8 *)Result.Contents; while(BytesToRead) { - U32 BytesRead; - - BytesRead = read(FileHandle, NextByteLocation, BytesToRead); + U32 BytesRead = read(FileHandle, NextByteLocation, BytesToRead); if(BytesRead == (U32)-1) { free(Result.Contents); Result.Contents = 0; @@ -111,17 +104,13 @@ B32 DEBUGPlatformWriteEntireFile(thread_context *Thread, const char *Filename, U32 MemorySize, void *Memory) { - S32 FileHandle; - U32 BytesToWrite; - U8 *NextByteLocation; - - FileHandle = open(Filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | - S_IRGRP | S_IROTH); + S32 FileHandle = open(Filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | + S_IRGRP | S_IROTH); if(FileHandle == -1) return FALSE; - BytesToWrite = MemorySize; - NextByteLocation = (U8*)Memory; + U32 BytesToWrite = MemorySize; + U8 *NextByteLocation = (U8*)Memory; while(BytesToWrite) { U32 BytesWritten; @@ -155,15 +144,13 @@ static sdl_window_dimension SDLGetWindowDimension(SDL_Window *Window) static void SDLResizeTexture(offscreen_buffer *Buffer, SDL_Renderer *Renderer, int Width, int Height) { - S32 BytesPerPixel; - if(Buffer->Texture) SDL_DestroyTexture(Buffer->Texture); if(Buffer->Memory) free(Buffer->Memory); - BytesPerPixel = 4; + S32 BytesPerPixel = 4; Buffer->Texture = SDL_CreateTexture(Renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, @@ -179,7 +166,6 @@ static void SDLDisplayBufferInWindow(offscreen_buffer Buffer, SDL_Window *Window, SDL_Renderer *Renderer) { - SDL_Rect dest_rect; S32 OffsetX = 10; S32 OffsetY = 10; @@ -193,21 +179,17 @@ static void SDLDisplayBufferInWindow(offscreen_buffer Buffer, /* TODO: We temporarily introduce the target rectangle to avoid * stretching the canvas. */ /* SDL_RenderCopy(Renderer, Buffer.Texture, 0, 0); */ - dest_rect.x = OffsetX; - dest_rect.y = OffsetY; - dest_rect.w = RESOLUTION_WIDTH; - dest_rect.h = RESOLUTION_HEIGHT; + SDL_Rect dest_rect = { OffsetX, OffsetY, + RESOLUTION_WIDTH, RESOLUTION_HEIGHT }; SDL_RenderCopy(Renderer, Buffer.Texture, 0, (const SDL_Rect *)(&dest_rect)); SDL_RenderPresent(Renderer); } static void SDLInitControllers() { - S32 MaxJoysticks, ControllerIndex, JoystickIndex; - - MaxJoysticks = SDL_NumJoysticks(); - ControllerIndex = 0; - for(JoystickIndex = 0; JoystickIndex < MaxJoysticks; JoystickIndex++) { + S32 MaxJoysticks = SDL_NumJoysticks(); + S32 ControllerIndex = 0; + for(S32 JoystickIndex = 0; JoystickIndex < MaxJoysticks; JoystickIndex++) { if(!SDL_IsGameController(JoystickIndex)) continue; if(ControllerIndex >= MAX_CONTROLLERS) @@ -221,9 +203,7 @@ static void SDLInitControllers() /* static void SDLDeinitControllers() { - S32 ControllerIndex; - - for(ControllerIndex = 0; + for(S32 ControllerIndex = 0; ControllerIndex < MAX_CONTROLLERS; ControllerIndex++) { @@ -236,7 +216,6 @@ static void SDLDeinitControllers() static void SDLInitSound(S32 SamplesPerSecond, S32 BufferSize) { SDL_AudioSpec AudioSettings; - memset(&AudioSettings, 0, sizeof(AudioSettings)); AudioSettings.freq = SamplesPerSecond; @@ -283,12 +262,8 @@ static void SDLProcessInputDigitalButton(SDL_GameController *Controller, static void HandleEvent(SDL_Event *Event) { - /* TODO: Should this be below scopes? */ - SDL_Window *Window; - SDL_Renderer *Renderer; - - Window = SDL_GetWindowFromID(Event->window.windowID); - Renderer = SDL_GetRenderer(Window); + SDL_Window *Window = SDL_GetWindowFromID(Event->window.windowID); + SDL_Renderer *Renderer = SDL_GetRenderer(Window); switch(Event->type) { case SDL_QUIT: { @@ -404,13 +379,11 @@ static void SDLProcessMessages(sdl_state *SDLState, } if(WasDown) { - B32 AltKeyWasDown; - /* 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. */ - AltKeyWasDown = (Event.key.keysym.mod & KMOD_ALT); + B32 AltKeyWasDown = (Event.key.keysym.mod & KMOD_ALT); if(KeyCode == SDLK_F4 && AltKeyWasDown) GlobalRunning = FALSE; #if BUILD_INTERNAL @@ -429,9 +402,7 @@ static void SDLProcessMessages(sdl_state *SDLState, static F32 SDLProcessInputStickValue(F32 Value, S32 DeadZoneThreshold) { - F32 Result; - - Result = 0.0f; + F32 Result = 0.0f; if(Value < -(F32)DeadZoneThreshold) Result = ((Value + (F32)DeadZoneThreshold) / (32768.0f - (F32)DeadZoneThreshold)); @@ -445,11 +416,9 @@ static F32 SDLProcessInputStickValue(F32 Value, S32 DeadZoneThreshold) #define DEFAULT_REFRESH_RATE 60 static S32 SDLGetWindowRefreshRate(SDL_Window *Window) { - S32 DisplayIndex; + S32 DisplayIndex = SDL_GetWindowDisplayIndex(Window); + SDL_DisplayMode Mode; - - DisplayIndex = SDL_GetWindowDisplayIndex(Window); - if(SDL_GetDesktopDisplayMode(DisplayIndex, &Mode) != 0) return DEFAULT_REFRESH_RATE; if(Mode.refresh_rate == 0) @@ -482,7 +451,6 @@ typedef struct sdl_game_code { static U32 GetLastWriteTime(const char *FileName) { struct stat file_info; - memset(&file_info, 0, sizeof(file_info)); if(stat(FileName, &file_info) != 0) { /* TODO: Diagnostic. perror("stat failed"); */ @@ -561,11 +529,9 @@ void GetExecutablePath(char *path, size_t path_size) static void SDLGetEXEDirPath(char *path, size_t path_size) { - U32 len, i; - GetExecutablePath(path, path_size); - len = str_len(path); - i = len; + U32 len = str_len(path); + U32 i = len; while(path[i] != '/' || i == 0) { i--; } @@ -590,8 +556,6 @@ U64 __rdtsc() * drawing into a bitmap. */ void SDLSetProgramIcon(SDL_Window *Window) { - SDL_Surface *icon; - U32 Rmask, Gmask, Bmask, Amask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN S32 shift_by = (program_icon.bytes_per_pixel == 3) ? 8 : 0; @@ -606,12 +570,12 @@ void SDLSetProgramIcon(SDL_Window *Window) Amask = (program_icon.bytes_per_pixel == 3) ? 0 : 0xff000000; #endif - icon = SDL_CreateRGBSurfaceFrom( - (void *)program_icon.pixel_data, - program_icon.width, program_icon.height, - program_icon.bytes_per_pixel * 8, - program_icon.bytes_per_pixel * program_icon.width, - Rmask, Gmask, Bmask, Amask); + SDL_Surface * icon = SDL_CreateRGBSurfaceFrom( + (void *)program_icon.pixel_data, + program_icon.width, program_icon.height, + program_icon.bytes_per_pixel * 8, + program_icon.bytes_per_pixel * program_icon.width, + Rmask, Gmask, Bmask, Amask); if(icon) { SDL_SetWindowIcon(Window, icon); SDL_FreeSurface(icon); @@ -623,8 +587,6 @@ void SDLSetProgramIcon(SDL_Window *Window) S32 main(S32 argc, char *argv[]) { sdl_state SDLState; - SDL_Window *Window; - memset(&SDLState, 0, sizeof(SDLState)); SDLGetEXEDirPath(SDLState.EXEDirPath, sizeof(SDLState.EXEDirPath)); @@ -642,20 +604,20 @@ S32 main(S32 argc, char *argv[]) /* NOTE: Floating windows are not supported oficially by Wayland * protocol. However, SDL_WINDOW_ALWAYS_ON_TOP does work on KDE * under Wayland. I have not tested GNOME. */ - Window = SDL_CreateWindow("Handmade Hero", SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - RESOLUTION_WIDTH, RESOLUTION_HEIGHT, - SDL_WINDOW_RESIZABLE); + SDL_Window *Window = SDL_CreateWindow("Handmade Hero", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + RESOLUTION_WIDTH, RESOLUTION_HEIGHT, + SDL_WINDOW_RESIZABLE); /*SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALWAYS_ON_TOP);*/ if(Window) { - SDL_Renderer *Renderer; - SDL_DisplayMode display_mode; SDL_GetCurrentDisplayMode(0, &display_mode); - Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_PRESENTVSYNC); + SDL_Renderer *Renderer = + SDL_CreateRenderer(Window, -1, SDL_RENDERER_PRESENTVSYNC); SDL_SetWindowPosition(Window, (display_mode.w - RESOLUTION_WIDTH), (display_mode.h - RESOLUTION_HEIGHT)); @@ -666,11 +628,6 @@ S32 main(S32 argc, char *argv[]) * its actual size. */ /* SDL_RenderPresent(Renderer) is enough to display the window. */ if(Renderer) { - sdl_window_dimension Dimension; - sdl_sound_output SoundOutput; - game_memory GameMemory; - S32 ReplayIndex; - #if BUILD_DEBUG void *BaseAddress = (void *)TB(2); #else @@ -686,10 +643,11 @@ S32 main(S32 argc, char *argv[]) GlobalRunning = TRUE; - Dimension = SDLGetWindowDimension(Window); + sdl_window_dimension Dimension = SDLGetWindowDimension(Window); SDLResizeTexture(&GlobalBackbuffer, Renderer, Dimension.Width, Dimension.Height); + sdl_sound_output SoundOutput; memset(&SoundOutput, 0, sizeof(SoundOutput)); SoundOutput.SamplesPerSecond = 48000; SoundOutput.BytesPerSample = sizeof(S16) * 2; @@ -712,6 +670,7 @@ S32 main(S32 argc, char *argv[]) /* NOTE: calloc auto clears to zero */ /* SDLClearSoundBuffer(&SoundOutput); */ + game_memory GameMemory; memset(&GameMemory, 0, sizeof(GameMemory)); GameMemory.PermanentStorageSize = MB(64); GameMemory.TransientStorageSize = GB(1); @@ -735,65 +694,29 @@ S32 main(S32 argc, char *argv[]) (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) { game_input Input[2]; - game_input *NewInput, *OldInput; - sdl_game_code Game; - F32 TargetSecondsPerFrame; - S32 MonitorRefreshHz, GameUpdateHz; U64 LastCounter; U64 LastCycleCount; - MonitorRefreshHz = SDLGetWindowRefreshRate(Window); + S32 MonitorRefreshHz = SDLGetWindowRefreshRate(Window); /*GameUpdateHz = MonitorRefreshHz;*/ - GameUpdateHz = 30; /* NOTE: Temporarily target 30 FPS. */ - TargetSecondsPerFrame = 1.0f / (F32)GameUpdateHz; + S32 GameUpdateHz = 30; /* NOTE: Temporarily target 30 FPS. */ + F32 TargetSecondsPerFrame = 1.0f / (F32)GameUpdateHz; - NewInput = &Input[0]; - OldInput = &Input[1]; + game_input *NewInput = &Input[0]; + game_input *OldInput = &Input[1]; memset(&Input, 0, sizeof(Input)); GlobalPerfCountFrequency = SDL_GetPerformanceFrequency(); - Game = SDLLoadGameCode(SDLState.DLLPath); + sdl_game_code Game = SDLLoadGameCode(SDLState.DLLPath); while(GlobalRunning) { - thread_context Context; - U32 NewDLLWriteTime, ButtonIndex, ControllerIndex, - SDLMouseButtons; - game_controller_input *OldKeyboardController, - *NewKeyboardController; - game_controller_input ZeroController; - S32 TargetQueueBytes, BytesToWrite; - game_sound_output_buffer SoundBuffer; - game_offscreen_buffer Buffer; - U64 WorkCounter, EndCounter; - F32 WorkSecondsElapsed, SecondsElapsedForFrame; - F64 MSPerFrame, FPS; - U64 EndCycleCount, CyclesElapsed; - F64 MCPF; - NewInput->dtForFrame = TargetSecondsPerFrame; LastCounter = SDLGetWallClock(); @@ -805,14 +728,15 @@ S32 main(S32 argc, char *argv[]) * have not checked MacOS x64. */ LastCycleCount = __rdtsc(); - NewDLLWriteTime = GetLastWriteTime(SDLState.DLLPath); + U32 NewDLLWriteTime = GetLastWriteTime(SDLState.DLLPath); if(NewDLLWriteTime > Game.DLLLastWriteTime) { SDLUnloadGameCode(&Game); Game = SDLLoadGameCode(SDLState.DLLPath); } - SDLMouseButtons = SDL_GetMouseState(&(NewInput->MouseX), - &(NewInput->MouseY)); + U32 SDLMouseButtons = + SDL_GetMouseState(&(NewInput->MouseX), + &(NewInput->MouseY)); NewInput->MouseZ = 0; /* TODO: Support mouse wheel? */ SDLProcessKeyboardMessage(&(NewInput->MouseButtons[0]), SDL_BUTTON_LMASK & SDLMouseButtons); @@ -828,13 +752,16 @@ S32 main(S32 argc, char *argv[]) SDLProcessKeyboardMessage(&(NewInput->MouseButtons[4]), SDL_BUTTON_X2MASK & SDLMouseButtons); - OldKeyboardController = GetController(OldInput, 0); - NewKeyboardController = GetController(NewInput, 0); + game_controller_input *OldKeyboardController = + GetController(OldInput, 0); + game_controller_input *NewKeyboardController = + GetController(NewInput, 0); + game_controller_input ZeroController; memset(&ZeroController, 0, sizeof(ZeroController)); *NewKeyboardController = ZeroController; NewKeyboardController->IsConnected = TRUE; - for(ButtonIndex = 0; + for(U32 ButtonIndex = 0; ButtonIndex < ARRAY_SIZE( NewKeyboardController->u.Buttons); ButtonIndex++) @@ -848,11 +775,12 @@ S32 main(S32 argc, char *argv[]) SDLProcessMessages(&SDLState, NewKeyboardController); - for(ControllerIndex = 0; + for(U32 ControllerIndex = 0; ControllerIndex < MAX_CONTROLLERS; ControllerIndex++) { - game_controller_input *OldController, *NewController; + game_controller_input *OldController, + *NewController; OldController = GetController(OldInput, ControllerIndex+1); @@ -863,18 +791,15 @@ S32 main(S32 argc, char *argv[]) SDL_GameControllerGetAttached( ControllerHandles[ControllerIndex])) { - S16 StickX, StickY; - float Threshold; - NewController->IsAnalog = OldController->IsAnalog; NewController->IsConnected = TRUE; - StickX = + S16 StickX = SDL_GameControllerGetAxis( ControllerHandles[ControllerIndex], SDL_CONTROLLER_AXIS_LEFTX); - StickY = + S16 StickY = SDL_GameControllerGetAxis( ControllerHandles[ControllerIndex], SDL_CONTROLLER_AXIS_LEFTY); @@ -925,7 +850,7 @@ S32 main(S32 argc, char *argv[]) NewController->IsAnalog = FALSE; } - Threshold = 0.5f; + F32 Threshold = 0.5f; SDLProcessInputDigitalButton( ControllerHandles[ (NewController->StickAverageY < @@ -1002,18 +927,21 @@ S32 main(S32 argc, char *argv[]) } } - TargetQueueBytes = SoundOutput.LatencySampleCount * - SoundOutput.BytesPerSample; - BytesToWrite = + S32 TargetQueueBytes = SoundOutput.LatencySampleCount * + SoundOutput.BytesPerSample; + S32 BytesToWrite = TargetQueueBytes - SDL_GetQueuedAudioSize(1); + game_sound_output_buffer SoundBuffer; SoundBuffer.SamplesPerSecond = SoundOutput.SamplesPerSecond; SoundBuffer.SampleCount = BytesToWrite / SoundOutput.BytesPerSample; SoundBuffer.Samples = (short *)SoundOutput.Samples; + thread_context Context; memset(&Context, 0, sizeof(Context)); + game_offscreen_buffer Buffer; Buffer.Memory = GlobalBackbuffer.Memory; Buffer.Width = GlobalBackbuffer.Width; Buffer.Height = GlobalBackbuffer.Height; @@ -1028,11 +956,11 @@ S32 main(S32 argc, char *argv[]) SDLFillSoundBuffer(&SoundOutput, BytesToWrite); - WorkCounter = SDLGetWallClock(); - WorkSecondsElapsed = SDLGetSecondsElapsed(LastCounter, - WorkCounter); + U64 WorkCounter = SDLGetWallClock(); + F32 WorkSecondsElapsed = + SDLGetSecondsElapsed(LastCounter, WorkCounter); - SecondsElapsedForFrame = WorkSecondsElapsed; + F32 SecondsElapsedForFrame = WorkSecondsElapsed; if(SecondsElapsedForFrame < TargetSecondsPerFrame) { while(SecondsElapsedForFrame < TargetSecondsPerFrame) { SecondsElapsedForFrame = @@ -1046,21 +974,21 @@ S32 main(S32 argc, char *argv[]) /* TODO: Logging. */ } - EndCounter = SDLGetWallClock(); + U64 EndCounter = SDLGetWallClock(); SDLDisplayBufferInWindow(GlobalBackbuffer, Window, Renderer); - MSPerFrame = 1000.0 * SDLGetSecondsElapsed(LastCounter, - EndCounter); - FPS = 0.0; + F64 MSPerFrame = 1000.0 * + SDLGetSecondsElapsed(LastCounter, EndCounter); + F64 FPS = 0.0; LastCounter = EndCounter; #if 0 - EndCycleCount = __rdtsc(); - CyclesElapsed = EndCycleCount - LastCycleCount; - MCPF = ((double)CyclesElapsed / (1000.0 * 1000.0)); + U64 EndCycleCount = __rdtsc(); + U64 CyclesElapsed = EndCycleCount - LastCycleCount; + F64 MCPF = ((double)CyclesElapsed / (1000.0 * 1000.0)); fprintf(stderr, "%.02f ms/f, %.02f/s, %.02f mc/f\n", MSPerFrame, FPS, MCPF); LastCycleCount = EndCycleCount; diff --git a/sdl_handmade.h b/sdl_handmade.h index 58b1207..7ab2bbd 100644 --- a/sdl_handmade.h +++ b/sdl_handmade.h @@ -34,22 +34,9 @@ typedef struct sdl_sound_output { * 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; - - /* NOTE: These functions might be NULL. Check before calling them! */ - S32 PlaybackHandle; - S32 InputPlayingIndex; char EXEDirPath[SDL_STATE_PATH_SIZE]; char DLLPath[SDL_STATE_PATH_SIZE];