diff --git a/handmade.c b/handmade.c index 7fa6192..ba58126 100644 --- a/handmade.c +++ b/handmade.c @@ -5,6 +5,9 @@ #include "handmade_intrinsics.h" #include /* memset */ +#include "handmade_tile.h" +#include "handmade_tile.cpp" + static void GameOutputSound(game_state *GameState, game_sound_output_buffer *SoundBuffer, S32 ToneHz) @@ -94,111 +97,26 @@ static void DrawRectangle(game_offscreen_buffer *Buffer, } } -static tile_chunk *GetTileChunk(world *World, - S32 TileChunkX, S32 TileChunkY) +static void InitializeArena(memory_arena *Arena, U64 Size, U8 *Base) { - tile_chunk *TileChunk = NULL; - - if((TileChunkX >= 0) && (TileChunkX < World->TileChunkCountX) && - (TileChunkY >= 0) && (TileChunkY < World->TileChunkCountY)) - { - TileChunk = &World->TileChunks[TileChunkY * - World->TileChunkCountX + - TileChunkX]; - } - - return TileChunk; + Arena->Size = Size; + Arena->Base = Base; + Arena->Used = 0; } -static U32 GetTileValueUnchecked(world *World, tile_chunk *TileChunk, - U32 TileX, U32 TileY) +#define PUSH_STRUCT(Arena, type) (type *)PushSize_(Arena, sizeof(type)) +#define PUSH_ARRAY(Arena, Count, type) (type *)PushSize_(Arena, (Count)*sizeof(type)) +static void *PushSize_(memory_arena *Arena, U64 Size) { - U32 TileChunkValue; + void *Result; - ASSERT(TileChunk); - ASSERT(TileX < World->ChunkDim); - ASSERT(TileY < World->ChunkDim); - - TileChunkValue = TileChunk->Tiles[TileY * World->ChunkDim + TileX]; - return TileChunkValue; -} - -static U32 GetTileChunkValue(world *World, tile_chunk *TileChunk, - U32 TestTileX, U32 TestTileY) -{ - U32 TileChunkValue = 0; - - if(TileChunk) { - TileChunkValue = GetTileValueUnchecked(World, - TileChunk, - TestTileX, TestTileY); - } - - return TileChunkValue; -} - -static void CannonicalizeCoord(world *World, 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 = FloorF32toS32(*TileRel / World->TileSideInMeters); - *Tile += Offset; - *TileRel -= (F32)Offset * World->TileSideInMeters; - - ASSERT(*TileRel >= 0); - ASSERT(*TileRel < World->TileSideInMeters); -} - -static cannonical_position RecannonicalizePosition(world *World, - cannonical_position Pos) -{ - cannonical_position Result = Pos; - - CannonicalizeCoord(World, &Result.AbsTileX, &Result.TileRelX); - CannonicalizeCoord(World, &Result.AbsTileY, &Result.TileRelY); + ASSERT((Arena->Used + Size) <= Arena->Size); + Result = (void *)(Arena->Base + Arena->Used); + Arena->Used += Size; return Result; } -static tile_chunk_position GetChunkPositionFor(world *World, - U32 AbsTileX, U32 AbsTileY) -{ - tile_chunk_position Result; - - Result.TileChunkX = AbsTileX >> World->ChunkShift; - Result.TileChunkY = AbsTileY >> World->ChunkShift; - Result.RelTileX = AbsTileX & World->ChunkMask; - Result.RelTileY = AbsTileY & World->ChunkMask; - - return Result; -} - -static U32 GetTileValue(world *World, U32 AbsTileX, U32 AbsTileY) -{ - tile_chunk_position ChunkPos = GetChunkPositionFor(World, - AbsTileX, - AbsTileY); - tile_chunk *TileMap = GetTileChunk(World, - ChunkPos.TileChunkX, - ChunkPos.TileChunkY); - U32 TileChunkValue = GetTileChunkValue(World, TileMap, - ChunkPos.RelTileX, - ChunkPos.RelTileY); - return TileChunkValue; -} - -static B32 IsWorldPointEmpty(world *World, cannonical_position CanPos) -{ - B32 Empty; - - U32 TileChunkValue = GetTileValue(World, - CanPos.AbsTileX, - CanPos.AbsTileY); - Empty = (TileChunkValue == 0); - - return Empty; -} - void UpdateAndRender(thread_context *Thread, game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer, game_sound_output_buffer *SoundBuffer) @@ -209,73 +127,98 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, game_state *GameState; U32 ControllerIndex; - U32 TempTiles[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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 1}, - {1, 0, 0, 0, 0, 0, 0, 0, 1, 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, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, - {1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 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, 1, 0, 0, 1, 0, 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 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, 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, 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, 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, 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; - F32 CenterX, CenterY; + F32 ScreenCenterX, ScreenCenterY; - tile_chunk TileChunk; - world World; + world *World; + tile_map *TileMap; 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)); - /* NOTE: This is set to using 256x256 tile chunks. */ - World.ChunkShift = 8; - World.ChunkMask = 0xFF; - World.ChunkDim = 256; - - World.TileChunkCountX = 1; - World.TileChunkCountY = 1; - - TileChunk.Tiles = (U32 *)TempTiles; - World.TileChunks = &TileChunk; - - World.TileSideInMeters = 1.4f; - World.TileSideInPixels = 60; - World.MetersToPixels = - (F32)World.TileSideInPixels / World.TileSideInMeters; - PlayerHeight = 1.4f; PlayerWidth = 0.75f * PlayerHeight; - CenterX = 0.5f * (F32)Buffer->Width; - CenterY = 0.5f * (F32)Buffer->Height; - GameState = (game_state *)Memory->PermanentStorage; if(!Memory->IsInitialized) { - GameState->PlayerP.AbsTileX = 3; + U32 TilesPerWidth, TilesPerHeight; + U32 ScreenX, ScreenY; + tile_map *TileMap; + world *World; + + GameState->PlayerP.AbsTileX = 2; GameState->PlayerP.AbsTileY = 3; GameState->PlayerP.TileRelX = 5.0f; GameState->PlayerP.TileRelY = 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->TileMap = PUSH_STRUCT(&GameState->WorldArena, tile_map); + + TileMap = World->TileMap; + + TileMap->ChunkShift = 8; + TileMap->ChunkMask = (1 << TileMap->ChunkShift) - 1; + TileMap->ChunkDim = 256; + + TileMap->TileChunkCountX = 4; + TileMap->TileChunkCountY = 4; + + TileMap->TileChunks = + PUSH_ARRAY(&GameState->WorldArena, + TileMap->TileChunkCountX*TileMap->TileChunkCountX, + tile_chunk); + + { + U32 X, Y; + for(Y = 0; Y < TileMap->TileChunkCountY; Y++) { + for(X = 0; X < TileMap->TileChunkCountX; X++) { + TileMap->TileChunks[Y*TileMap->TileChunkCountX + X].Tiles = + PUSH_ARRAY(&GameState->WorldArena, + TileMap->ChunkDim*TileMap->ChunkDim, + U32); + } + } + } + + TileMap->TileSideInMeters = 1.4f; + TileMap->TileSideInPixels = 60; + TileMap->MetersToPixels = + (F32)TileMap->TileSideInPixels / TileMap->TileSideInMeters; + + TilesPerWidth = 17; + TilesPerHeight = 9; + for(ScreenY = 0; ScreenY < 32; ScreenY++) { + for(ScreenX = 0; ScreenX < 32; ScreenX++) { + U32 TileX, TileY; + for(TileY = 0; TileY < TilesPerWidth; TileY++) { + for(TileX = 0; TileX < TilesPerWidth; TileX++) { + U32 AbsTileX = ScreenX * TilesPerWidth + TileX; + U32 AbsTileY = ScreenY * TilesPerHeight + TileY; + + SetTileValue(&GameState->WorldArena, + World->TileMap, + AbsTileX, AbsTileY, + (TileX == TileY) && (TileY % 2) ? 1 : 0); + } + } + } + } + Memory->IsInitialized = TRUE; } + World = GameState->World; + TileMap = World->TileMap; + for(ControllerIndex = 0; ControllerIndex < ARRAY_SIZE(Input->Controllers); ControllerIndex++) @@ -287,7 +230,7 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, F32 dPlayerX = 0.0f; F32 dPlayerY = 0.0f; - cannonical_position NewPlayerP, PlayerLeft, PlayerRight; + tile_map_position NewPlayerP, PlayerLeft, PlayerRight; if(Controller->u.buttons.MoveUp.EndedDown) { dPlayerY = 1.0f; @@ -302,31 +245,41 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, dPlayerX = 1.0f; } - dPlayerX *= 5.0f; - dPlayerY *= 5.0f; + { + F32 PlayerSpeed = 2.0f; + + if(Controller->u.buttons.ActionUp.EndedDown) + PlayerSpeed = 10.0f; + + dPlayerX *= PlayerSpeed; + dPlayerY *= PlayerSpeed; + } NewPlayerP = GameState->PlayerP; NewPlayerP.TileRelX += Input->dtForFrame*dPlayerX; NewPlayerP.TileRelY += Input->dtForFrame*dPlayerY; - NewPlayerP = RecannonicalizePosition(&World, NewPlayerP); + NewPlayerP = RecannonicalizePosition(TileMap, NewPlayerP); PlayerLeft = NewPlayerP; PlayerLeft.TileRelX -= 0.5f*PlayerWidth; - PlayerLeft = RecannonicalizePosition(&World, PlayerLeft); + PlayerLeft = RecannonicalizePosition(TileMap, PlayerLeft); PlayerRight = NewPlayerP; PlayerRight.TileRelX += 0.5f*PlayerWidth; - PlayerRight = RecannonicalizePosition(&World, PlayerRight); + PlayerRight = RecannonicalizePosition(TileMap, PlayerRight); - if(IsWorldPointEmpty(&World, NewPlayerP) && - IsWorldPointEmpty(&World, PlayerLeft) && - IsWorldPointEmpty(&World, PlayerRight)) + if(IsTileMapPointEmpty(TileMap, NewPlayerP) && + IsTileMapPointEmpty(TileMap, PlayerLeft) && + IsTileMapPointEmpty(TileMap, PlayerRight)) { GameState->PlayerP = NewPlayerP; } } } + ScreenCenterX = 0.5f * (F32)Buffer->Width; + ScreenCenterY = 0.5f * (F32)Buffer->Height; + DrawRectangle(Buffer, 0.0f, 0.0f, (F32)Buffer->Width, (F32)Buffer->Height, 0.0f, 1.0f, 0.0f); @@ -337,7 +290,7 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, U32 Column = GameState->PlayerP.AbsTileX + RelColumn; U32 Row = GameState->PlayerP.AbsTileY + RelRow; - U32 TileID = GetTileValue(&World, Column, Row); + U32 TileID = GetTileValue(TileMap, Column, Row); F32 Gray = 0.5f; if(TileID) { @@ -351,15 +304,20 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, } { - F32 MinX, MinY, MaxX, MaxY; - MinX = CenterX + - (F32)RelColumn * (F32)World.TileSideInPixels; - MinY = CenterY - - (F32)RelRow * (F32)World.TileSideInPixels; - MaxX = MinX + (F32)World.TileSideInPixels; - MaxY = MinY - (F32)World.TileSideInPixels; + F32 CenterX, CenterY, MinX, MinY, MaxX, MaxY; + + CenterX = ScreenCenterX - + TileMap->MetersToPixels*GameState->PlayerP.TileRelX + + (F32)RelColumn * (F32)TileMap->TileSideInPixels; + CenterY = ScreenCenterY + + TileMap->MetersToPixels*GameState->PlayerP.TileRelY - + (F32)RelRow * (F32)TileMap->TileSideInPixels; + MinX = CenterX - 0.5f*(F32)TileMap->TileSideInPixels; + MinY = CenterY - 0.5f*(F32)TileMap->TileSideInPixels; + MaxX = CenterX + 0.5f*(F32)TileMap->TileSideInPixels; + MaxY = CenterY + 0.5f*(F32)TileMap->TileSideInPixels; DrawRectangle(Buffer, - MinX, MaxY, MaxX, MinY, + MinX, MinY, MaxX, MaxY, Gray, Gray, Gray); } } @@ -369,14 +327,12 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, PlayerR = 1.0f; PlayerG = 0.0f; PlayerB = 0.0f; - PlayerLeft = CenterX + World.MetersToPixels*GameState->PlayerP.TileRelX - - 0.5f*World.MetersToPixels*PlayerWidth; - PlayerTop = CenterY - World.MetersToPixels*GameState->PlayerP.TileRelY - - World.MetersToPixels*PlayerHeight; + PlayerLeft = ScreenCenterX - 0.5f* TileMap->MetersToPixels*PlayerWidth; + PlayerTop = ScreenCenterY - TileMap->MetersToPixels*PlayerHeight; DrawRectangle(Buffer, PlayerLeft, PlayerTop, - PlayerLeft + World.MetersToPixels*PlayerWidth, - PlayerTop + World.MetersToPixels*PlayerHeight, + PlayerLeft + TileMap->MetersToPixels*PlayerWidth, + PlayerTop + TileMap->MetersToPixels*PlayerHeight, PlayerR, PlayerG, PlayerB); GameOutputSound(GameState, SoundBuffer, 400); diff --git a/handmade.h b/handmade.h index c402053..a5ce0eb 100644 --- a/handmade.h +++ b/handmade.h @@ -2,6 +2,7 @@ #define HANDMADE_H_SENTRY #include "core.h" +#include "handmade_tile.h" /* --------------------------------------------------------------------- */ /* NOTE: Servcies that the platform layer provides to the game. */ @@ -136,44 +137,20 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, * */ -typedef struct tile_chunk_position { - U32 TileChunkX; - U32 TileChunkY; - - U32 RelTileX; - U32 RelTileY; -} tile_chunk_position; - -typedef struct cannonical_position { - U32 AbsTileX; - U32 AbsTileY; - - /* NOTE: Tile-relative X and Y. */ - F32 TileRelX; - F32 TileRelY; -} cannonical_position; - -typedef struct tile_chunk { - U32 *Tiles; -} tile_chunk; +typedef struct memory_arena { + U64 Size; + U8 *Base; + U64 Used; +} memory_arena; typedef struct world { - U32 ChunkShift; - U32 ChunkMask; - U32 ChunkDim; - - F32 TileSideInMeters; - S32 TileSideInPixels; - F32 MetersToPixels; - - S32 TileChunkCountX; - S32 TileChunkCountY; - - tile_chunk *TileChunks; + tile_map *TileMap; } world; typedef struct game_state { - cannonical_position PlayerP; + memory_arena WorldArena; + world *World; + tile_map_position PlayerP; } game_state; #endif diff --git a/handmade_intrinsics.h b/handmade_intrinsics.h index 1c9fd46..a26ff48 100644 --- a/handmade_intrinsics.h +++ b/handmade_intrinsics.h @@ -8,7 +8,7 @@ S32 RoundF32toS32(F32 Real32) { - S32 Result = (S32)(Real32 + 0.5f); + S32 Result = (S32)roundf(Real32); return Result; } diff --git a/handmade_tile.cpp b/handmade_tile.cpp new file mode 100644 index 0000000..6625e62 --- /dev/null +++ b/handmade_tile.cpp @@ -0,0 +1,144 @@ +#include "handmade_tile.h" + +static tile_chunk *GetTileChunk(tile_map *TileMap, + U32 TileChunkX, U32 TileChunkY) +{ + tile_chunk *TileChunk = NULL; + + if((TileChunkX >= 0) && (TileChunkX < TileMap->TileChunkCountX) && + (TileChunkY >= 0) && (TileChunkY < TileMap->TileChunkCountY)) + { + TileChunk = &TileMap->TileChunks[TileChunkY * + TileMap->TileChunkCountX + + TileChunkX]; + } + + 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) +{ + tile_chunk_position Result; + + Result.TileChunkX = AbsTileX >> TileMap->ChunkShift; + Result.TileChunkY = AbsTileY >> TileMap->ChunkShift; + Result.RelTileX = AbsTileX & TileMap->ChunkMask; + Result.RelTileY = AbsTileY & TileMap->ChunkMask; + + return Result; +} + +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]; + return TileChunkValue; +} + +static U32 GetTileChunkValue(tile_map *TileMap, tile_chunk *TileChunk, + U32 TestTileX, U32 TestTileY) +{ + U32 TileChunkValue = 0; + + if(TileChunk) { + TileChunkValue = GetTileValueUnchecked(TileMap, + TileChunk, + TestTileX, TestTileY); + } + + 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) +{ + SetTileValueUnchecked(TileMap, + TileChunk, + TestTileX, TestTileY, + TileValue); +} + +static U32 GetTileValue(tile_map *TileMap, U32 AbsTileX, U32 AbsTileY) +{ + tile_chunk_position ChunkPos = GetChunkPositionFor(TileMap, + AbsTileX, + AbsTileY); + tile_chunk *TileChunk = GetTileChunk(TileMap, + ChunkPos.TileChunkX, + ChunkPos.TileChunkY); + U32 TileChunkValue = GetTileChunkValue(TileMap, TileChunk, + ChunkPos.RelTileX, + ChunkPos.RelTileY); + return TileChunkValue; +} + +static B32 IsTileMapPointEmpty(tile_map *TileMap, tile_map_position CanPos) +{ + B32 Empty; + + U32 TileChunkValue = GetTileValue(TileMap, + CanPos.AbsTileX, + CanPos.AbsTileY); + Empty = (TileChunkValue == 0); + return Empty; +} + +static void SetTileValue(memory_arena *Arena, + tile_map *TileMap, + U32 AbsTileX, U32 AbsTileY, + U32 TileValue) +{ + tile_chunk_position ChunkPos; + tile_chunk *TileChunk; + + ChunkPos = GetChunkPositionFor(TileMap, AbsTileX, AbsTileY); + TileChunk = GetTileChunk(TileMap, + ChunkPos.TileChunkX, + ChunkPos.TileChunkY); + ASSERT(TileChunk); /* TODO: On-deman tile chunk creation. */ + + SetTileChunkValue(TileMap, TileChunk, + ChunkPos.RelTileX, + ChunkPos.RelTileY, + TileValue); +} diff --git a/handmade_tile.h b/handmade_tile.h new file mode 100644 index 0000000..6a234c7 --- /dev/null +++ b/handmade_tile.h @@ -0,0 +1,40 @@ +#ifndef HANDMADE_TILE_H_SENTRY +#define HANDMADE_TILE_H_SENTRY + +typedef struct tile_map_position { + U32 AbsTileX; + U32 AbsTileY; + + /* NOTE: Tile-relative X and Y. */ + F32 TileRelX; + F32 TileRelY; +} tile_map_position; + +typedef struct tile_chunk_position { + U32 TileChunkX; + U32 TileChunkY; + + U32 RelTileX; + U32 RelTileY; +} tile_chunk_position; + +typedef struct tile_chunk { + U32 *Tiles; +} tile_chunk; + +typedef struct tile_map { + U32 ChunkShift; + U32 ChunkMask; + U32 ChunkDim; + + F32 TileSideInMeters; + S32 TileSideInPixels; + F32 MetersToPixels; + + U32 TileChunkCountX; + U32 TileChunkCountY; + + tile_chunk *TileChunks; +} tile_map; + +#endif \ No newline at end of file