251 lines
8.2 KiB
C
251 lines
8.2 KiB
C
#include "handmade_tile.h"
|
|
|
|
#include <assert.h>
|
|
|
|
static struct tile_chunk *
|
|
get_tile_chunk(struct tile_map *tile_map,
|
|
unsigned int tile_chunk_x, unsigned int tile_chunk_y,
|
|
unsigned int tile_chunk_z)
|
|
{
|
|
struct tile_chunk *tile_chunk = NULL;
|
|
|
|
if((tile_chunk_x >= 0) && (tile_chunk_x < tile_map->tile_chunk_count_x) &&
|
|
(tile_chunk_y >= 0) && (tile_chunk_y < tile_map->tile_chunk_count_y) &&
|
|
(tile_chunk_z >= 0) && (tile_chunk_z < tile_map->tile_chunk_count_z))
|
|
{
|
|
tile_chunk =
|
|
&tile_map->tile_chunks[(tile_chunk_z * tile_map->tile_chunk_count_y *
|
|
tile_map->tile_chunk_count_x) +
|
|
(tile_chunk_y*tile_map->tile_chunk_count_x) + tile_chunk_x];
|
|
}
|
|
|
|
return tile_chunk;
|
|
}
|
|
|
|
static struct tile_chunk_position
|
|
get_chunk_position_for(struct tile_map *tile_map,
|
|
unsigned int abs_tile_x, unsigned int abs_tile_y,
|
|
unsigned int abs_tile_z)
|
|
{
|
|
struct tile_chunk_position result;
|
|
|
|
result.tile_chunk_x = abs_tile_x >> tile_map->chunk_shift;
|
|
result.tile_chunk_y = abs_tile_y >> tile_map->chunk_shift;
|
|
result.tile_chunk_z = abs_tile_z;
|
|
result.rel_tile_x = abs_tile_x & tile_map->chunk_mask;
|
|
result.rel_tile_y = abs_tile_y & tile_map->chunk_mask;
|
|
|
|
return result;
|
|
}
|
|
|
|
static unsigned int
|
|
get_tile_value_unchecked(struct tile_map *tile_map,
|
|
struct tile_chunk *tile_chunk,
|
|
unsigned int tile_x, unsigned int tile_y)
|
|
{
|
|
unsigned int tile_chunk_value;
|
|
|
|
assert(tile_chunk);
|
|
assert(tile_x < tile_map->chunk_dim);
|
|
assert(tile_y < tile_map->chunk_dim);
|
|
|
|
tile_chunk_value =
|
|
tile_chunk->tiles[tile_y * tile_map->chunk_dim + tile_x];
|
|
return tile_chunk_value;
|
|
}
|
|
|
|
static unsigned int
|
|
get_tile_chunk_value(struct tile_map *tile_map,
|
|
struct tile_chunk *tile_chunk,
|
|
unsigned int test_tile_x, unsigned int test_tile_y)
|
|
{
|
|
unsigned int tile_chunk_value = 0;
|
|
|
|
if(tile_chunk && tile_chunk->tiles) {
|
|
tile_chunk_value =
|
|
get_tile_value_unchecked(tile_map, tile_chunk,
|
|
test_tile_x, test_tile_y);
|
|
}
|
|
|
|
return tile_chunk_value;
|
|
}
|
|
|
|
static unsigned int
|
|
get_tile_value(struct tile_map *tile_map,
|
|
unsigned int abs_tile_x, unsigned int abs_tile_y,
|
|
unsigned int abs_tile_z)
|
|
{
|
|
struct tile_chunk_position chunk_pos =
|
|
get_chunk_position_for(tile_map, abs_tile_x, abs_tile_y, abs_tile_z);
|
|
struct tile_chunk *tile_chunk =
|
|
get_tile_chunk(tile_map, chunk_pos.tile_chunk_x, chunk_pos.tile_chunk_y,
|
|
chunk_pos.tile_chunk_z);
|
|
unsigned int tile_chunk_value =
|
|
get_tile_chunk_value(tile_map, tile_chunk, chunk_pos.rel_tile_x,
|
|
chunk_pos.rel_tile_y);
|
|
return tile_chunk_value;
|
|
}
|
|
|
|
static int is_tile_value_empty(unsigned int tile_value)
|
|
{
|
|
int empty = ((tile_value == 1) || (tile_value == 3) || (tile_value == 4));
|
|
return empty;
|
|
}
|
|
|
|
static unsigned int get_tile_value_by_pos(struct tile_map *tile_map,
|
|
struct tile_map_position pos)
|
|
{
|
|
unsigned int tile_chunk_value =
|
|
get_tile_value(tile_map, pos.abs_tile_x,
|
|
pos.abs_tile_y, pos.abs_tile_z);
|
|
return tile_chunk_value;
|
|
}
|
|
|
|
static void set_tile_value_unchecked(struct tile_map *tile_map,
|
|
struct tile_chunk *tile_chunk,
|
|
unsigned int tile_x,
|
|
unsigned int tile_y,
|
|
unsigned int tile_value)
|
|
{
|
|
assert(tile_chunk);
|
|
assert(tile_x < tile_map->chunk_dim);
|
|
assert(tile_y < tile_map->chunk_dim);
|
|
|
|
tile_chunk->tiles[tile_y * tile_map->chunk_dim + tile_x] = tile_value;
|
|
}
|
|
|
|
static void set_tile_chunk_value(struct tile_map *tile_map,
|
|
struct tile_chunk *tile_chunk,
|
|
unsigned int test_tile_x,
|
|
unsigned int test_tile_y,
|
|
unsigned int tile_value)
|
|
{
|
|
if(tile_chunk && tile_chunk->tiles) {
|
|
set_tile_value_unchecked(tile_map, tile_chunk,
|
|
test_tile_x, test_tile_y,
|
|
tile_value);
|
|
}
|
|
}
|
|
|
|
static int is_tile_map_point_empty(struct tile_map *tile_map,
|
|
struct tile_map_position pos)
|
|
{
|
|
unsigned int tile_chunk_value;
|
|
int empty;
|
|
|
|
tile_chunk_value = get_tile_value_by_pos(tile_map, pos);
|
|
empty = is_tile_value_empty(tile_chunk_value);
|
|
return empty;
|
|
}
|
|
|
|
static void set_tile_value(struct memory_arena *arena,
|
|
struct tile_map *tile_map,
|
|
unsigned int abs_tile_x, unsigned int abs_tile_y,
|
|
unsigned int abs_tile_z, unsigned int tile_value)
|
|
{
|
|
struct tile_chunk_position chunk_pos;
|
|
struct tile_chunk *tile_chunk;
|
|
|
|
chunk_pos = get_chunk_position_for(tile_map,
|
|
abs_tile_x, abs_tile_y, abs_tile_z);
|
|
tile_chunk = get_tile_chunk(tile_map,
|
|
chunk_pos.tile_chunk_x,
|
|
chunk_pos.tile_chunk_y,
|
|
chunk_pos.tile_chunk_z);
|
|
|
|
assert(tile_chunk);
|
|
if(!tile_chunk->tiles) {
|
|
unsigned int tile_count, tile_index;
|
|
|
|
tile_count = tile_map->chunk_dim*tile_map->chunk_dim;
|
|
|
|
tile_chunk->tiles = PUSH_ARRAY(arena, tile_count, unsigned int);
|
|
for(tile_index = 0;
|
|
tile_index < tile_count;
|
|
tile_index++)
|
|
{
|
|
tile_chunk->tiles[tile_index] = 1;
|
|
}
|
|
}
|
|
|
|
set_tile_chunk_value(tile_map, tile_chunk, chunk_pos.rel_tile_x,
|
|
chunk_pos.rel_tile_y, tile_value);
|
|
}
|
|
|
|
/* TODO: Do these belong more in a "positioning" or "geometry" file? */
|
|
|
|
static void cannonicalize_coord(struct tile_map *tile_map,
|
|
unsigned int *tile,
|
|
float *tile_rel)
|
|
{
|
|
/* NOTE: The world is assumed to be toroidal topology. If you step off
|
|
* one end, you come back on the other.*/
|
|
int offset =
|
|
round_float_to_int(*tile_rel / tile_map->tile_side_in_meters);
|
|
*tile += offset;
|
|
*tile_rel -= (float)offset * tile_map->tile_side_in_meters;
|
|
|
|
assert(*tile_rel >= -0.5f*tile_map->tile_side_in_meters);
|
|
assert(*tile_rel <= 0.5f*tile_map->tile_side_in_meters);
|
|
}
|
|
|
|
static struct tile_map_position
|
|
recannonicalize_position(struct tile_map *tile_map,
|
|
struct tile_map_position pos)
|
|
{
|
|
struct tile_map_position result = pos;
|
|
|
|
cannonicalize_coord(tile_map, &result.abs_tile_x, &result.offset.x);
|
|
cannonicalize_coord(tile_map, &result.abs_tile_y, &result.offset.y);
|
|
|
|
return result;
|
|
}
|
|
|
|
static int are_on_same_tile(struct tile_map_position *a,
|
|
struct tile_map_position *b)
|
|
{
|
|
int result = ((a->abs_tile_x == b->abs_tile_x) &&
|
|
(a->abs_tile_y == b->abs_tile_y) &&
|
|
(a->abs_tile_z == b->abs_tile_z));
|
|
return result;
|
|
}
|
|
|
|
static struct tile_map_difference
|
|
subtract_in_float(struct tile_map *tile_map,
|
|
struct tile_map_position *a, struct tile_map_position *b)
|
|
{
|
|
struct tile_map_difference result;
|
|
|
|
struct v2 d_tile_xy;
|
|
|
|
float d_tile_z;
|
|
|
|
d_tile_xy.x = (float)a->abs_tile_x - (float)b->abs_tile_x;
|
|
d_tile_xy.y = (float)a->abs_tile_y - (float)b->abs_tile_y;
|
|
|
|
d_tile_z = (float)a->abs_tile_z - (float)b->abs_tile_z;
|
|
|
|
result.d_xy = V2Add(V2Multiply(tile_map->tile_side_in_meters,
|
|
d_tile_xy),
|
|
V2Subtract(a->offset, b->offset));
|
|
|
|
/* TODO: Incomplete . . . */
|
|
result.d_z = tile_map->tile_side_in_meters*d_tile_z;
|
|
|
|
return result;
|
|
}
|
|
|
|
static struct tile_map_position
|
|
centered_tile_point(unsigned int abs_tile_x, unsigned int abs_tile_y,
|
|
unsigned int abs_tile_z)
|
|
{
|
|
struct tile_map_position result;
|
|
memset(&result, 0, sizeof(result));
|
|
|
|
result.abs_tile_x = abs_tile_x;
|
|
result.abs_tile_y = abs_tile_y;
|
|
result.abs_tile_z = abs_tile_z;
|
|
|
|
return result;
|
|
}
|