#include "handmade_tile.h" static tile_chunk *GetTileChunk(tile_map *TileMap, U32 TileChunkX, U32 TileChunkY, U32 TileChunkZ) { tile_chunk *TileChunk = NULL; if((TileChunkX >= 0) && (TileChunkX < TileMap->TileChunkCountX) && (TileChunkY >= 0) && (TileChunkY < TileMap->TileChunkCountY) && (TileChunkZ >= 0) && (TileChunkZ < TileMap->TileChunkCountZ)) { TileChunk = &TileMap->TileChunks[ (TileChunkZ*TileMap->TileChunkCountY*TileMap->TileChunkCountX) + (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, U32 AbsTileZ) { tile_chunk_position Result; Result.TileChunkX = AbsTileX >> TileMap->ChunkShift; Result.TileChunkY = AbsTileY >> TileMap->ChunkShift; Result.TileChunkZ = AbsTileZ; 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 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) { U32 TileChunkValue = 0; if(TileChunk && TileChunk->Tiles) { TileChunkValue = GetTileValueUnchecked(TileMap, TileChunk, TestTileX, TestTileY); } 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) { tile_chunk_position ChunkPos = GetChunkPositionFor(TileMap, AbsTileX, AbsTileY, AbsTileZ); tile_chunk *TileChunk = GetTileChunk(TileMap, ChunkPos.TileChunkX, ChunkPos.TileChunkY, ChunkPos.TileChunkZ); 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, CanPos.AbsTileZ); Empty = (TileChunkValue == 1); return Empty; } static void SetTileValue(memory_arena *Arena, tile_map *TileMap, 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); 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++) { TileChunk->Tiles[TileIndex] = 1; } } SetTileChunkValue(TileMap, TileChunk, ChunkPos.RelTileX, ChunkPos.RelTileY, TileValue); }