146 lines
3.5 KiB
C
146 lines
3.5 KiB
C
#include "manager.h"
|
|
|
|
/* TODO: perhaps render the chunks in a circle, not a square, around
|
|
the player? */
|
|
|
|
ChunkManager chunk_manager;
|
|
|
|
guint
|
|
cm_ivec2_hash (gconstpointer key)
|
|
{
|
|
const ivec2 *v = key;
|
|
return g_int_hash(&(*v)[0]) ^ g_int_hash(&(*v)[1]);
|
|
}
|
|
|
|
gboolean
|
|
cm_ivec2_equal (gconstpointer a, gconstpointer b)
|
|
{
|
|
const ivec2 *av = a;
|
|
const ivec2 *bv = b;
|
|
return (*av)[0] == (*bv)[0] && (*av)[1] == (*bv)[1];
|
|
}
|
|
|
|
ivec2 *
|
|
cm_make_key(int x, int z)
|
|
{
|
|
ivec2 *key = malloc(sizeof(ivec2));
|
|
(*key)[0] = x;
|
|
(*key)[1] = z;
|
|
return key;
|
|
}
|
|
|
|
void
|
|
cm_world_to_chunk (float x, float z, int *ox, int *oz)
|
|
{
|
|
*ox = floor (x / (float) CHUNK_DIM);
|
|
*oz = floor (z / (float) CHUNK_DIM);
|
|
}
|
|
|
|
void
|
|
ChunkManager_init ()
|
|
{
|
|
chunk_manager.chunks = g_hash_table_new_full (cm_ivec2_hash, cm_ivec2_equal, free, (GDestroyNotify) Chunk_free);
|
|
chunk_manager.chunk_meshes = g_hash_table_new_full (cm_ivec2_hash, cm_ivec2_equal, free, (GDestroyNotify) Chunk_free);
|
|
}
|
|
|
|
/* TODO: Update the chunks only if the player has moved into another
|
|
chunk, to save frame time. */
|
|
|
|
void
|
|
ChunkManager_update (vec3 camera_position)
|
|
{
|
|
int cx, cz;
|
|
cm_world_to_chunk (camera_position[0], camera_position[2], &cx, &cz);
|
|
|
|
for (int z = cz - RENDER_DISTANCE - 1; z <= cz + RENDER_DISTANCE + 1; ++z)
|
|
{
|
|
for (int x = cx - RENDER_DISTANCE - 1; x <= cx + RENDER_DISTANCE + 1; ++x)
|
|
{
|
|
if (ChunkManager_get_Chunk_at (x, z) == NULL)
|
|
{
|
|
ChunkManager_generate_Chunk_at (x, z);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int z = cz - RENDER_DISTANCE; z <= cz + RENDER_DISTANCE; ++z)
|
|
{
|
|
for (int x = cx - RENDER_DISTANCE; x <= cx + RENDER_DISTANCE; ++x)
|
|
{
|
|
if (ChunkManager_get_ChunkMesh_at (x, z) == NULL)
|
|
{
|
|
ChunkManager_generate_ChunkMesh_at (x, z);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ChunkManager_render (vec3 camera_position, int program)
|
|
{
|
|
int cx = 0, cz = 0;
|
|
cm_world_to_chunk (camera_position[0], camera_position[2], &cx, &cz);
|
|
|
|
for (int z = cz - RENDER_DISTANCE; z <= cz + RENDER_DISTANCE; ++z)
|
|
{
|
|
for (int x = cx - RENDER_DISTANCE; x <= cx + RENDER_DISTANCE; ++x)
|
|
{
|
|
ChunkMesh *mesh = ChunkManager_get_ChunkMesh_at (x, z);
|
|
if (mesh != NULL)
|
|
{
|
|
program_set_vec3 (program, "chunk_position", x * CHUNK_DIM, 0.0, z * CHUNK_DIM);
|
|
ChunkMesh_render (mesh);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Chunk *
|
|
ChunkManager_get_Chunk_at (int x, int z)
|
|
{
|
|
return (Chunk *) g_hash_table_lookup (chunk_manager.chunks, (ivec2) { x, z });
|
|
}
|
|
|
|
void
|
|
ChunkManager_set_Chunk_at (int x, int z, Chunk *chunk)
|
|
{
|
|
g_hash_table_insert (chunk_manager.chunks, cm_make_key (x, z), chunk);
|
|
}
|
|
|
|
void
|
|
ChunkManager_generate_Chunk_at (int x, int z)
|
|
{
|
|
Chunk *chunk = Chunk_new ();
|
|
Chunk_random (chunk, x * CHUNK_DIM, z * CHUNK_DIM);
|
|
ChunkManager_set_Chunk_at (x, z, chunk);
|
|
}
|
|
|
|
void
|
|
ChunkManager_get_Chunk_neighbors_at (int x, int z, Chunk **nr, Chunk **nd, Chunk **nc)
|
|
{
|
|
*nr = ChunkManager_get_Chunk_at (x + 1, z);
|
|
*nd = ChunkManager_get_Chunk_at (x, z + 1);
|
|
*nc = ChunkManager_get_Chunk_at (x + 1, z + 1);
|
|
}
|
|
|
|
ChunkMesh *
|
|
ChunkManager_get_ChunkMesh_at (int x, int z)
|
|
{
|
|
return (ChunkMesh *) g_hash_table_lookup (chunk_manager.chunk_meshes, (ivec2) { x, z });
|
|
}
|
|
|
|
void
|
|
ChunkManager_set_ChunkMesh_at (int x, int z, ChunkMesh *mesh)
|
|
{
|
|
g_hash_table_insert (chunk_manager.chunk_meshes, cm_make_key (x, z), mesh);
|
|
}
|
|
|
|
void
|
|
ChunkManager_generate_ChunkMesh_at (int x, int z)
|
|
{
|
|
Chunk *nr, *nd, *nc;
|
|
ChunkManager_get_Chunk_neighbors_at (x, z, &nr, &nd, &nc);
|
|
ChunkManager_set_ChunkMesh_at
|
|
(x, z, ChunkMesh_build (ChunkManager_get_Chunk_at (x, z), nr, nd, nc));
|
|
}
|