233 lines
7.3 KiB
C
233 lines
7.3 KiB
C
#include "handmade_tile.h"
|
|
|
|
static struct tile_chunk *
|
|
GetTileChunk(struct tile_map *TileMap,
|
|
unsigned int TileChunkX, unsigned int TileChunkY,
|
|
unsigned int TileChunkZ)
|
|
{
|
|
struct 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 struct tile_chunk_position
|
|
GetChunkPositionFor(struct tile_map *TileMap,
|
|
unsigned int AbsTileX, unsigned int AbsTileY,
|
|
unsigned int AbsTileZ)
|
|
{
|
|
struct 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 unsigned int
|
|
GetTileValueUnchecked(struct tile_map *TileMap,
|
|
struct tile_chunk *TileChunk,
|
|
unsigned int TileX, unsigned int TileY)
|
|
{
|
|
unsigned int TileChunkValue;
|
|
|
|
ASSERT(TileChunk);
|
|
ASSERT(TileX < TileMap->ChunkDim);
|
|
ASSERT(TileY < TileMap->ChunkDim);
|
|
|
|
TileChunkValue = TileChunk->Tiles[TileY * TileMap->ChunkDim + TileX];
|
|
return TileChunkValue;
|
|
}
|
|
|
|
static unsigned int
|
|
GetTileChunkValue(struct tile_map *TileMap, struct tile_chunk *TileChunk,
|
|
unsigned int TestTileX, unsigned int TestTileY)
|
|
{
|
|
unsigned int TileChunkValue = 0;
|
|
|
|
if(TileChunk && TileChunk->Tiles) {
|
|
TileChunkValue =
|
|
GetTileValueUnchecked(TileMap, TileChunk, TestTileX, TestTileY);
|
|
}
|
|
|
|
return TileChunkValue;
|
|
}
|
|
|
|
static unsigned int
|
|
GetTileValue(struct tile_map *TileMap,
|
|
unsigned int AbsTileX, unsigned int AbsTileY,
|
|
unsigned int AbsTileZ)
|
|
{
|
|
struct tile_chunk_position ChunkPos =
|
|
GetChunkPositionFor(TileMap, AbsTileX, AbsTileY, AbsTileZ);
|
|
struct tile_chunk *TileChunk =
|
|
GetTileChunk(TileMap, ChunkPos.TileChunkX, ChunkPos.TileChunkY,
|
|
ChunkPos.TileChunkZ);
|
|
unsigned int TileChunkValue =
|
|
GetTileChunkValue(TileMap, TileChunk, ChunkPos.RelTileX,
|
|
ChunkPos.RelTileY);
|
|
return TileChunkValue;
|
|
}
|
|
|
|
static int IsTileValueEmpty(unsigned int TileValue)
|
|
{
|
|
int Empty = ((TileValue == 1) || (TileValue == 3) || (TileValue == 4));
|
|
return Empty;
|
|
}
|
|
|
|
static unsigned int GetTileValueByPos(struct tile_map *TileMap,
|
|
struct tile_map_position Pos)
|
|
{
|
|
unsigned int TileChunkValue =
|
|
GetTileValue(TileMap, Pos.AbsTileX, Pos.AbsTileY, Pos.AbsTileZ);
|
|
return TileChunkValue;
|
|
}
|
|
|
|
static void SetTileValueUnchecked(struct tile_map *TileMap,
|
|
struct tile_chunk *TileChunk,
|
|
unsigned int TileX, unsigned int TileY,
|
|
unsigned int TileValue)
|
|
{
|
|
ASSERT(TileChunk);
|
|
ASSERT(TileX < TileMap->ChunkDim);
|
|
ASSERT(TileY < TileMap->ChunkDim);
|
|
|
|
TileChunk->Tiles[TileY * TileMap->ChunkDim + TileX] = TileValue;
|
|
}
|
|
|
|
static void SetTileChunkValue(struct tile_map *TileMap,
|
|
struct tile_chunk *TileChunk,
|
|
unsigned int TestTileX, unsigned int TestTileY,
|
|
unsigned int TileValue)
|
|
{
|
|
if(TileChunk && TileChunk->Tiles) {
|
|
SetTileValueUnchecked(TileMap, TileChunk, TestTileX, TestTileY,
|
|
TileValue);
|
|
}
|
|
}
|
|
|
|
static int IsTileMapPointEmpty(struct tile_map *TileMap,
|
|
struct tile_map_position Pos)
|
|
{
|
|
unsigned int TileChunkValue = GetTileValueByPos(TileMap, Pos);
|
|
int Empty = IsTileValueEmpty(TileChunkValue);
|
|
return Empty;
|
|
}
|
|
|
|
static void SetTileValue(struct memory_arena *Arena,
|
|
struct tile_map *TileMap,
|
|
unsigned int AbsTileX, unsigned int AbsTileY,
|
|
unsigned int AbsTileZ, unsigned int TileValue)
|
|
{
|
|
|
|
struct tile_chunk_position ChunkPos =
|
|
GetChunkPositionFor(TileMap, AbsTileX, AbsTileY, AbsTileZ);
|
|
struct tile_chunk *TileChunk =
|
|
GetTileChunk(TileMap, ChunkPos.TileChunkX, ChunkPos.TileChunkY,
|
|
ChunkPos.TileChunkZ);
|
|
|
|
ASSERT(TileChunk);
|
|
if(!TileChunk->Tiles) {
|
|
unsigned int TileCount = TileMap->ChunkDim*TileMap->ChunkDim;
|
|
unsigned int TileIndex;
|
|
|
|
TileChunk->Tiles = PUSH_ARRAY(Arena, TileCount, unsigned int);
|
|
for(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(struct tile_map *TileMap, unsigned int *Tile,
|
|
float *TileRel)
|
|
{
|
|
/* NOTE: The world is assumed to be toroidal topology. If you step off
|
|
* one end, you come back on the other.*/
|
|
int Offset = RoundFloatToInt(*TileRel / TileMap->TileSideInMeters);
|
|
*Tile += Offset;
|
|
*TileRel -= (float)Offset * TileMap->TileSideInMeters;
|
|
|
|
ASSERT(*TileRel >= -0.5f*TileMap->TileSideInMeters);
|
|
ASSERT(*TileRel <= 0.5f*TileMap->TileSideInMeters);
|
|
}
|
|
|
|
static struct tile_map_position
|
|
RecannonicalizePosition(struct tile_map *TileMap,
|
|
struct tile_map_position Pos)
|
|
{
|
|
struct tile_map_position Result = Pos;
|
|
|
|
CannonicalizeCoord(TileMap, &Result.AbsTileX, &Result.Offset.X);
|
|
CannonicalizeCoord(TileMap, &Result.AbsTileY, &Result.Offset.Y);
|
|
|
|
return Result;
|
|
}
|
|
|
|
static int AreOnSameTile(struct tile_map_position *A,
|
|
struct tile_map_position *B)
|
|
{
|
|
int Result = ((A->AbsTileX == B->AbsTileX) &&
|
|
(A->AbsTileY == B->AbsTileY) &&
|
|
(A->AbsTileZ == B->AbsTileZ));
|
|
return Result;
|
|
}
|
|
|
|
static struct tile_map_difference
|
|
SubtractInFloat(struct tile_map *TileMap,
|
|
struct tile_map_position *A, struct tile_map_position *B)
|
|
{
|
|
struct tile_map_difference Result;
|
|
|
|
struct v2 dTileXY;
|
|
|
|
float dTileZ;
|
|
|
|
dTileXY.X = (float)A->AbsTileX - (float)B->AbsTileX;
|
|
dTileXY.Y = (float)A->AbsTileY - (float)B->AbsTileY;
|
|
|
|
dTileZ = (float)A->AbsTileZ - (float)B->AbsTileZ;
|
|
|
|
Result.dXY = V2Add(V2Multiply(TileMap->TileSideInMeters,
|
|
dTileXY),
|
|
V2Subtract(A->Offset, B->Offset));
|
|
|
|
/* TODO: Incomplete . . . */
|
|
Result.dZ = TileMap->TileSideInMeters*dTileZ;
|
|
|
|
return Result;
|
|
}
|
|
|
|
static struct tile_map_position
|
|
CenteredTilePoint(unsigned int AbsTileX, unsigned int AbsTileY,
|
|
unsigned int AbsTileZ)
|
|
{
|
|
struct tile_map_position Result;
|
|
memset(&Result, 0, sizeof(Result));
|
|
|
|
Result.AbsTileX = AbsTileX;
|
|
Result.AbsTileY = AbsTileY;
|
|
Result.AbsTileZ = AbsTileZ;
|
|
|
|
return Result;
|
|
}
|