189 lines
6.4 KiB
C
189 lines
6.4 KiB
C
#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 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)
|
|
{
|
|
ASSERT(TileChunk);
|
|
ASSERT(TileX < TileMap->ChunkDim);
|
|
ASSERT(TileY < TileMap->ChunkDim);
|
|
|
|
U32 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 && TileChunk->Tiles) {
|
|
TileChunkValue = GetTileValueUnchecked(TileMap,
|
|
TileChunk,
|
|
TestTileX,
|
|
TestTileY);
|
|
}
|
|
|
|
return TileChunkValue;
|
|
}
|
|
|
|
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 U32 GetTileValueByPos(tile_map *TileMap, tile_map_position Pos)
|
|
{
|
|
U32 TileChunkValue = GetTileValue(TileMap,
|
|
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;
|
|
}
|
|
|
|
static void SetTileValue(memory_arena *Arena,
|
|
tile_map *TileMap,
|
|
U32 AbsTileX, U32 AbsTileY, U32 AbsTileZ,
|
|
U32 TileValue)
|
|
{
|
|
|
|
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;
|
|
|
|
TileChunk->Tiles = PUSH_ARRAY(Arena, TileCount, U32);
|
|
for(U32 TileIndex = 0; TileIndex < TileCount; TileIndex++) {
|
|
TileChunk->Tiles[TileIndex] = 1;
|
|
}
|
|
|
|
}
|
|
|
|
SetTileChunkValue(TileMap, TileChunk,
|
|
ChunkPos.RelTileX,
|
|
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;
|
|
}
|