diff --git a/handmade.c b/handmade.c index cacdede..f0faca4 100644 --- a/handmade.c +++ b/handmade.c @@ -3,6 +3,7 @@ #include "sdl_handmade.h" #include +#include /* memset */ static void GameOutputSound(game_state *GameState, game_sound_output_buffer *SoundBuffer, @@ -121,35 +122,176 @@ static void RenderRectangle(game_offscreen_buffer *Buffer, S32 MouseX, } } +static tile_map *GetTileMap(world *World, S32 TileMapX, S32 TileMapY) +{ + tile_map *TileMap = NULL; + + if((TileMapX >= 0) && (TileMapX < World->TileMapCountX) && + (TileMapY >= 0) && (TileMapY < World->TileMapCountY)) + { + TileMap = + &World->TileMaps[TileMapY*World->TileMapCountX + TileMapX]; + } + + return TileMap; +} + +static U32 GetTileValueUnchecked(tile_map *TileMap, S32 TileX, S32 TileY) +{ + U32 TileMapValue = TileMap->Tiles[TileY*TileMap->CountX + TileX]; + return TileMapValue; +} + +static B32 IsTileMapPointEmpty(tile_map *TileMap, F32 TestX, F32 TestY) +{ + B32 Empty = FALSE; + + S32 PlayerTileX = + (S32)((TestX - TileMap->UpperLeftX) / TileMap->TileWidth); + S32 PlayerTileY = + (S32)((TestY - TileMap->UpperLeftY) / TileMap->TileHeight); + + if((PlayerTileX >= 0) && (PlayerTileX < TileMap->CountX) && + (PlayerTileY >= 0) && (PlayerTileY < TileMap->CountY)) + { + U32 TileMapValue = + GetTileValueUnchecked(TileMap, PlayerTileX, PlayerTileY); + Empty = (TileMapValue == 0); + } + + return Empty; +} + +static B32 IsWorldPointEmpty(world *World, + S32 TileMapX, S32 TileMapY, + F32 TestX, F32 TestY) +{ + B32 Empty = FALSE; + + tile_map *TileMap = GetTileMap(World, TileMapX, TileMapY); + + S32 PlayerTileX, PlayerTileY; + + TileMap = GetTileMap(World, TileMapX, TileMapY); + if(TileMap) { + S32 PlayerTileX = + (S32)((TestX - TileMap->UpperLeftX) / TileMap->TileWidth); + S32 PlayerTileY = + (S32)((TestY - TileMap->UpperLeftY) / TileMap->TileHeight); + + if((PlayerTileX >= 0) && (PlayerTileX < TileMap->CountX) && + (PlayerTileY >= 0) && (PlayerTileY < TileMap->CountY)) + { + U32 TileMapValue = + GetTileValueUnchecked(TileMap, PlayerTileX, PlayerTileY); + Empty = (TileMapValue == 0); + } + } + + return Empty; +} + void UpdateAndRender(thread_context *Thread, game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer, game_sound_output_buffer *SoundBuffer) { +#define TILEMAP_COUNT_X 17 +#define TILEMAP_COUNT_Y 9 + game_state *GameState; U32 ControllerIndex; S32 Row, Column; - U32 TileMap[9][17] = { - {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1}, + + U32 Tiles00[TILEMAP_COUNT_Y][TILEMAP_COUNT_X] = { + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}, {1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, - {0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0}, + {1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0}, {1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1}, {1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1}, {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}, - {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, }; - F32 UpperLeftX, UpperLeftY, TileWidth, TileHeight; + U32 Tiles01[TILEMAP_COUNT_Y][TILEMAP_COUNT_X] = { + {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + }; + U32 Tiles10[TILEMAP_COUNT_Y][TILEMAP_COUNT_X] = { + {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, + }; + U32 Tiles11[TILEMAP_COUNT_Y][TILEMAP_COUNT_X] = { + {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + }; + F32 PlayerR, PlayerG, PlayerB, PlayerWidth, PlayerHeight, PlayerLeft, PlayerTop; + tile_map TileMaps[2][2]; + tile_map *TileMap; + world World; + 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); + memset(&World, 0, sizeof(World)); + + TileMaps[0][0].CountX = TILEMAP_COUNT_X; + TileMaps[0][0].CountY = TILEMAP_COUNT_Y; + + TileMaps[0][0].UpperLeftX = 0.0f; + TileMaps[0][0].UpperLeftY = 0.0f; + TileMaps[0][0].TileWidth = 57.0f; + TileMaps[0][0].TileHeight = 57.0f; + + TileMaps[0][0].Tiles = (U32 *)Tiles00; + + TileMaps[0][1] = TileMaps[0][0]; + TileMaps[0][1].Tiles = (U32 *)Tiles01; + + TileMaps[1][0] = TileMaps[0][0]; + TileMaps[1][0].Tiles = (U32 *)Tiles10; + + TileMaps[1][1] = TileMaps[0][0]; + TileMaps[1][1].Tiles = (U32 *)Tiles11; + + TileMap = &TileMaps[0][0]; + + World.TileMaps = (tile_map *)TileMaps; + + PlayerWidth = 0.75f * TileMap->TileWidth; + PlayerHeight = TileMap->TileHeight; + GameState = (game_state *)Memory->PermanentStorage; if(!Memory->IsInitialized) { + GameState->PlayerX = 200.0f; + GameState->PlayerY = 200.0f; + Memory->IsInitialized = TRUE; } @@ -164,6 +306,8 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, F32 dPlayerX = 0.0f; F32 dPlayerY = 0.0f; + F32 NewPlayerX, NewPlayerY; + if(Controller->u.buttons.MoveUp.EndedDown) { dPlayerY = -1.0f; } @@ -177,14 +321,23 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, dPlayerX = 1.0f; } - dPlayerX *= 64.0f; - dPlayerY *= 64.0f; + dPlayerX *= 100.0f; + dPlayerY *= 100.0f; - GameState->PlayerX += Input->dtForFrame * dPlayerX; - GameState->PlayerY += Input->dtForFrame * dPlayerY; + NewPlayerX = RoundF32toS32(GameState->PlayerX + + Input->dtForFrame*dPlayerX); + NewPlayerY = RoundF32toS32(GameState->PlayerY + + Input->dtForFrame*dPlayerY); - GameState->PlayerX = RoundF32toS32(GameState->PlayerX); - GameState->PlayerY = RoundF32toS32(GameState->PlayerY); + if(IsTileMapPointEmpty(TileMap, NewPlayerX - 0.5f*PlayerWidth, + NewPlayerY) && + IsTileMapPointEmpty(TileMap, NewPlayerX + 0.5f*PlayerWidth, + NewPlayerY) && + IsTileMapPointEmpty(TileMap, NewPlayerX, NewPlayerY)) + { + GameState->PlayerX = NewPlayerX; + GameState->PlayerY = NewPlayerY; + } } } @@ -192,23 +345,18 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, (F32)(Buffer->Width), (F32)(Buffer->Height), 0.0f, 1.0f, 0.0f); - UpperLeftX = 0.0f; - UpperLeftY = 0.0f; - TileWidth = 57.0f; - TileHeight = 57.0f; - - for(Row = 0; Row < 9; Row++) { - for(Column = 0; Column < 17; Column++) { + for(Row = 0; Row < TILEMAP_COUNT_Y; Row++) { + for(Column = 0; Column < TILEMAP_COUNT_X; Column++) { F32 MinX, MinY, MaxX, MaxY; - U32 TileID = TileMap[Row][Column]; + U32 TileID = GetTileValueUnchecked(TileMap, Column, Row); F32 Gray = 0.5f; if(TileID) { Gray = 1.0f; } - MinX = UpperLeftX + (F32)(Column) * TileWidth; - MinY = UpperLeftY + (F32)(Row) * TileHeight; - MaxX = MinX + TileWidth; - MaxY = MinY + TileHeight; + MinX = TileMap->UpperLeftX + (F32)(Column) * TileMap->TileWidth; + MinY = TileMap->UpperLeftY + (F32)(Row) * TileMap->TileHeight; + MaxX = MinX + TileMap->TileWidth; + MaxY = MinY + TileMap->TileHeight; DrawRectangle(Buffer, MinX, MinY, MaxX, MaxY, Gray, Gray, Gray); } } @@ -216,8 +364,6 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, PlayerR = 1.0f; PlayerG = 0.0f; PlayerB = 0.0f; - PlayerWidth = 0.75f * TileWidth; - PlayerHeight = TileHeight; PlayerLeft = GameState->PlayerX - 0.5f*PlayerWidth; PlayerTop = GameState->PlayerY - PlayerHeight; DrawRectangle(Buffer, diff --git a/handmade.h b/handmade.h index 3b01c61..8e0175f 100644 --- a/handmade.h +++ b/handmade.h @@ -1,5 +1,5 @@ #ifndef HANDMADE_H_SENTRY -#define HANDMADE_H_SENTRY +#define HANDMADE_H_SENTRY #include "core.h" @@ -106,8 +106,8 @@ typedef struct game_memory { U64 PermanentStorageSize; void *PermanentStorage; /* WARNING: This memory is REQUIRED to be zero - initialized!!! (Done by the OS - layer.) */ + initialized!!! (Done by the OS + layer.) */ U64 TransientStorageSize; void *TransientStorage; /* WARNING: This memory is REQUIRED to be zero @@ -136,6 +136,25 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, * */ +typedef struct tile_map { + S32 CountX; + S32 CountY; + + F32 UpperLeftX; + F32 UpperLeftY; + F32 TileWidth; + F32 TileHeight; + + U32 *Tiles; +} tile_map; + +typedef struct world { + S32 TileMapCountX; + S32 TileMapCountY; + + tile_map *TileMaps; +} world; + typedef struct game_state { F32 PlayerX; F32 PlayerY; diff --git a/sdl_handmade.c b/sdl_handmade.c index 9251cc7..e7eae1c 100644 --- a/sdl_handmade.c +++ b/sdl_handmade.c @@ -178,6 +178,11 @@ static void SDLDisplayBufferInWindow(offscreen_buffer Buffer, SDL_Renderer *Renderer) { SDL_Rect dest_rect; + S32 OffsetX = 10; + S32 OffsetY = 10; + + SDL_SetRenderDrawColor(Renderer, 0, 0, 0, 255); + SDL_RenderClear(Renderer); if(SDL_UpdateTexture(Buffer.Texture, 0, Buffer.Memory, Buffer.Pitch)) { /* TODO: Do something about this error! */ @@ -186,8 +191,8 @@ 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 = 0; - dest_rect.y = 0; + dest_rect.x = OffsetX; + dest_rect.y = OffsetY; dest_rect.w = RESOLUTION_WIDTH; dest_rect.h = RESOLUTION_HEIGHT; SDL_RenderCopy(Renderer, Buffer.Texture, 0, (const SDL_Rect *)(&dest_rect)); @@ -646,7 +651,7 @@ void GetExecutablePath(char *path, size_t path_size) #endif if(path_size > 0) { - path[0] = '\0'; + path[0] = '\0'; #if __APPLE__ && __MACH__ size = path_size; @@ -684,6 +689,13 @@ static void SDLGetDLLPath(char *path, size_t path_size, char *exe_path) snprintf(path, path_size, "%s%s", exe_path, GAME_DLL_NAME); } +#if !(__x86_64__ || __i386__) +U64 __rdtsc() +{ + return 0; +} +#endif + S32 main(S32 argc, char *argv[]) { sdl_state SDLState; @@ -818,9 +830,7 @@ S32 main(S32 argc, char *argv[]) S32 MonitorRefreshHz, GameUpdateHz; U64 LastCounter; -#if __x86_64__ || __i386__ U64 LastCycleCount; -#endif MonitorRefreshHz = SDLGetWindowRefreshRate(Window); /*GameUpdateHz = MonitorRefreshHz;*/ @@ -848,23 +858,19 @@ S32 main(S32 argc, char *argv[]) U64 WorkCounter, EndCounter; F32 WorkSecondsElapsed, SecondsElapsedForFrame; F64 MSPerFrame, FPS; -#if __x86_64__ || __i386__ U64 EndCycleCount, CyclesElapsed; F64 MCPF; -#endif NewInput->dtForFrame = TargetSecondsPerFrame; LastCounter = SDLGetWallClock(); -#if __x86_64__ || __i386__ /* NOTE: rdtsc reports clock cylces, however it is not * meant for really precise profiler work as the * value returned is varied. */ /* Also, __rdtsc is not available on MacOS ARM; I * have not checked MacOS x64. */ - LastCycleCount = __rdtsc(); -#endif + LastCycleCount = __rdtsc(); NewDLLWriteTime = GetLastWriteTime(SDLState.DLLPath); if(NewDLLWriteTime > Game.DLLLastWriteTime) { @@ -1126,17 +1132,12 @@ S32 main(S32 argc, char *argv[]) LastCounter = EndCounter; #if 0 -#if __x86_64__ || __i386__ EndCycleCount = __rdtsc(); CyclesElapsed = EndCycleCount - LastCycleCount; MCPF = ((double)CyclesElapsed / (1000.0 * 1000.0)); fprintf(stderr, "%.02f ms/f, %.02f/s, %.02f mc/f\n", MSPerFrame, FPS, MCPF); LastCycleCount = EndCycleCount; -#else - fprintf(stderr, "%.02f ms/f, %.02f/s\n", - MSPerFrame, FPS); -#endif #endif SWAP(game_input *, NewInput, OldInput);