Day 34 complete.

This commit is contained in:
igor
2026-04-15 11:58:51 -07:00
parent 713738b9f3
commit cd0ed29b30
5 changed files with 316 additions and 199 deletions
+121 -165
View File
@@ -5,6 +5,9 @@
#include "handmade_intrinsics.h" #include "handmade_intrinsics.h"
#include <string.h> /* memset */ #include <string.h> /* memset */
#include "handmade_tile.h"
#include "handmade_tile.cpp"
static void GameOutputSound(game_state *GameState, static void GameOutputSound(game_state *GameState,
game_sound_output_buffer *SoundBuffer, game_sound_output_buffer *SoundBuffer,
S32 ToneHz) S32 ToneHz)
@@ -94,111 +97,26 @@ static void DrawRectangle(game_offscreen_buffer *Buffer,
} }
} }
static tile_chunk *GetTileChunk(world *World, static void InitializeArena(memory_arena *Arena, U64 Size, U8 *Base)
S32 TileChunkX, S32 TileChunkY)
{ {
tile_chunk *TileChunk = NULL; Arena->Size = Size;
Arena->Base = Base;
if((TileChunkX >= 0) && (TileChunkX < World->TileChunkCountX) && Arena->Used = 0;
(TileChunkY >= 0) && (TileChunkY < World->TileChunkCountY))
{
TileChunk = &World->TileChunks[TileChunkY *
World->TileChunkCountX +
TileChunkX];
} }
return TileChunk; #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)
static U32 GetTileValueUnchecked(world *World, tile_chunk *TileChunk,
U32 TileX, U32 TileY)
{ {
U32 TileChunkValue; void *Result;
ASSERT(TileChunk); ASSERT((Arena->Used + Size) <= Arena->Size);
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);
Result = (void *)(Arena->Base + Arena->Used);
Arena->Used += Size;
return Result; 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, void UpdateAndRender(thread_context *Thread, game_memory *Memory,
game_input *Input, game_offscreen_buffer *Buffer, game_input *Input, game_offscreen_buffer *Buffer,
game_sound_output_buffer *SoundBuffer) game_sound_output_buffer *SoundBuffer)
@@ -209,73 +127,98 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
game_state *GameState; game_state *GameState;
U32 ControllerIndex; 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, F32 PlayerR, PlayerG, PlayerB,
PlayerWidth, PlayerHeight, PlayerWidth, PlayerHeight,
PlayerLeft, PlayerTop; 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 - 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);
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; PlayerHeight = 1.4f;
PlayerWidth = 0.75f * PlayerHeight; PlayerWidth = 0.75f * PlayerHeight;
CenterX = 0.5f * (F32)Buffer->Width;
CenterY = 0.5f * (F32)Buffer->Height;
GameState = (game_state *)Memory->PermanentStorage; GameState = (game_state *)Memory->PermanentStorage;
if(!Memory->IsInitialized) { 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.AbsTileY = 3;
GameState->PlayerP.TileRelX = 5.0f; GameState->PlayerP.TileRelX = 5.0f;
GameState->PlayerP.TileRelY = 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; Memory->IsInitialized = TRUE;
} }
World = GameState->World;
TileMap = World->TileMap;
for(ControllerIndex = 0; for(ControllerIndex = 0;
ControllerIndex < ARRAY_SIZE(Input->Controllers); ControllerIndex < ARRAY_SIZE(Input->Controllers);
ControllerIndex++) ControllerIndex++)
@@ -287,7 +230,7 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
F32 dPlayerX = 0.0f; F32 dPlayerX = 0.0f;
F32 dPlayerY = 0.0f; F32 dPlayerY = 0.0f;
cannonical_position NewPlayerP, PlayerLeft, PlayerRight; tile_map_position NewPlayerP, PlayerLeft, PlayerRight;
if(Controller->u.buttons.MoveUp.EndedDown) { if(Controller->u.buttons.MoveUp.EndedDown) {
dPlayerY = 1.0f; dPlayerY = 1.0f;
@@ -302,31 +245,41 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
dPlayerX = 1.0f; 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 = GameState->PlayerP;
NewPlayerP.TileRelX += Input->dtForFrame*dPlayerX; NewPlayerP.TileRelX += Input->dtForFrame*dPlayerX;
NewPlayerP.TileRelY += Input->dtForFrame*dPlayerY; NewPlayerP.TileRelY += Input->dtForFrame*dPlayerY;
NewPlayerP = RecannonicalizePosition(&World, NewPlayerP); NewPlayerP = RecannonicalizePosition(TileMap, NewPlayerP);
PlayerLeft = NewPlayerP; PlayerLeft = NewPlayerP;
PlayerLeft.TileRelX -= 0.5f*PlayerWidth; PlayerLeft.TileRelX -= 0.5f*PlayerWidth;
PlayerLeft = RecannonicalizePosition(&World, PlayerLeft); PlayerLeft = RecannonicalizePosition(TileMap, PlayerLeft);
PlayerRight = NewPlayerP; PlayerRight = NewPlayerP;
PlayerRight.TileRelX += 0.5f*PlayerWidth; PlayerRight.TileRelX += 0.5f*PlayerWidth;
PlayerRight = RecannonicalizePosition(&World, PlayerRight); PlayerRight = RecannonicalizePosition(TileMap, PlayerRight);
if(IsWorldPointEmpty(&World, NewPlayerP) && if(IsTileMapPointEmpty(TileMap, NewPlayerP) &&
IsWorldPointEmpty(&World, PlayerLeft) && IsTileMapPointEmpty(TileMap, PlayerLeft) &&
IsWorldPointEmpty(&World, PlayerRight)) IsTileMapPointEmpty(TileMap, PlayerRight))
{ {
GameState->PlayerP = NewPlayerP; GameState->PlayerP = NewPlayerP;
} }
} }
} }
ScreenCenterX = 0.5f * (F32)Buffer->Width;
ScreenCenterY = 0.5f * (F32)Buffer->Height;
DrawRectangle(Buffer, 0.0f, 0.0f, DrawRectangle(Buffer, 0.0f, 0.0f,
(F32)Buffer->Width, (F32)Buffer->Height, (F32)Buffer->Width, (F32)Buffer->Height,
0.0f, 1.0f, 0.0f); 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 Column = GameState->PlayerP.AbsTileX + RelColumn;
U32 Row = GameState->PlayerP.AbsTileY + RelRow; U32 Row = GameState->PlayerP.AbsTileY + RelRow;
U32 TileID = GetTileValue(&World, Column, Row); U32 TileID = GetTileValue(TileMap, Column, Row);
F32 Gray = 0.5f; F32 Gray = 0.5f;
if(TileID) { if(TileID) {
@@ -351,15 +304,20 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
} }
{ {
F32 MinX, MinY, MaxX, MaxY; F32 CenterX, CenterY, MinX, MinY, MaxX, MaxY;
MinX = CenterX +
(F32)RelColumn * (F32)World.TileSideInPixels; CenterX = ScreenCenterX -
MinY = CenterY - TileMap->MetersToPixels*GameState->PlayerP.TileRelX +
(F32)RelRow * (F32)World.TileSideInPixels; (F32)RelColumn * (F32)TileMap->TileSideInPixels;
MaxX = MinX + (F32)World.TileSideInPixels; CenterY = ScreenCenterY +
MaxY = MinY - (F32)World.TileSideInPixels; 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, DrawRectangle(Buffer,
MinX, MaxY, MaxX, MinY, MinX, MinY, MaxX, MaxY,
Gray, Gray, Gray); Gray, Gray, Gray);
} }
} }
@@ -369,14 +327,12 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
PlayerR = 1.0f; PlayerR = 1.0f;
PlayerG = 0.0f; PlayerG = 0.0f;
PlayerB = 0.0f; PlayerB = 0.0f;
PlayerLeft = CenterX + World.MetersToPixels*GameState->PlayerP.TileRelX - PlayerLeft = ScreenCenterX - 0.5f* TileMap->MetersToPixels*PlayerWidth;
0.5f*World.MetersToPixels*PlayerWidth; PlayerTop = ScreenCenterY - TileMap->MetersToPixels*PlayerHeight;
PlayerTop = CenterY - World.MetersToPixels*GameState->PlayerP.TileRelY -
World.MetersToPixels*PlayerHeight;
DrawRectangle(Buffer, DrawRectangle(Buffer,
PlayerLeft, PlayerTop, PlayerLeft, PlayerTop,
PlayerLeft + World.MetersToPixels*PlayerWidth, PlayerLeft + TileMap->MetersToPixels*PlayerWidth,
PlayerTop + World.MetersToPixels*PlayerHeight, PlayerTop + TileMap->MetersToPixels*PlayerHeight,
PlayerR, PlayerG, PlayerB); PlayerR, PlayerG, PlayerB);
GameOutputSound(GameState, SoundBuffer, 400); GameOutputSound(GameState, SoundBuffer, 400);
+10 -33
View File
@@ -2,6 +2,7 @@
#define HANDMADE_H_SENTRY #define HANDMADE_H_SENTRY
#include "core.h" #include "core.h"
#include "handmade_tile.h"
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
/* NOTE: Servcies that the platform layer provides to the game. */ /* 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 { typedef struct memory_arena {
U32 TileChunkX; U64 Size;
U32 TileChunkY; U8 *Base;
U64 Used;
U32 RelTileX; } memory_arena;
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 world { typedef struct world {
U32 ChunkShift; tile_map *TileMap;
U32 ChunkMask;
U32 ChunkDim;
F32 TileSideInMeters;
S32 TileSideInPixels;
F32 MetersToPixels;
S32 TileChunkCountX;
S32 TileChunkCountY;
tile_chunk *TileChunks;
} world; } world;
typedef struct game_state { typedef struct game_state {
cannonical_position PlayerP; memory_arena WorldArena;
world *World;
tile_map_position PlayerP;
} game_state; } game_state;
#endif #endif
+1 -1
View File
@@ -8,7 +8,7 @@
S32 RoundF32toS32(F32 Real32) S32 RoundF32toS32(F32 Real32)
{ {
S32 Result = (S32)(Real32 + 0.5f); S32 Result = (S32)roundf(Real32);
return Result; return Result;
} }
+144
View File
@@ -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);
}
+40
View File
@@ -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