214 lines
6.5 KiB
C
214 lines
6.5 KiB
C
#include <world.h>
|
|
#include <state.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
tc_worldgen_s tc_default_terrain_generator_g;
|
|
tc_entity_type_s *tc_chunk_entity_type_g = NULL;
|
|
|
|
void tc_upload_chunk(tc_chunk_s *chunk)
|
|
{
|
|
// If the chunk has no mesh, it's probably only air.
|
|
if(chunk->num_vertices == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(chunk->vao != 0) glDeleteVertexArrays(1, &chunk->vao);
|
|
if(chunk->vertex_data != 0) glDeleteBuffers(1, &chunk->vertex_data);
|
|
|
|
glGenVertexArrays(1, &chunk->vao);
|
|
glBindVertexArray(chunk->vao);
|
|
|
|
glGenBuffers(1, &chunk->vertex_data);
|
|
glBindBuffer(GL_ARRAY_BUFFER, chunk->vertex_data);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, chunk->num_vertices * 5 * sizeof(float), NULL, GL_STATIC_DRAW);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0,
|
|
chunk->num_vertices * 3 * sizeof(float),
|
|
chunk->vertex_positions
|
|
);
|
|
glBufferSubData(GL_ARRAY_BUFFER,
|
|
chunk->num_vertices * 3 * sizeof(float),
|
|
chunk->num_vertices * 2 * sizeof(float),
|
|
chunk->vertex_uvs
|
|
);
|
|
glBindVertexArray(0);
|
|
}
|
|
|
|
void tc_draw_chunk_entity(tc_entity_s *entity)
|
|
{
|
|
tc_chunk_s *chunk = entity->specific;
|
|
|
|
tc_mat4f_s model_matrix = tc_mat4f_identity();
|
|
|
|
tc_vec3f_s position_3f;
|
|
position_3f.x = chunk->position.x * 32;
|
|
position_3f.y = chunk->position.y * 32;
|
|
position_3f.z = chunk->position.z * 32;
|
|
|
|
model_matrix =
|
|
tc_mat4f_translate(model_matrix, position_3f);
|
|
|
|
tc_shader_uniform_mat4f(&tc_game_state_g.renderer.draw_shader, "model_matrix", model_matrix);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, chunk->vertex_data);
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) 0);
|
|
glEnableVertexAttribArray(0);
|
|
|
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,
|
|
2 * sizeof(float),
|
|
(void *) (sizeof(float) * 3 * chunk->num_vertices)
|
|
);
|
|
|
|
glEnableVertexAttribArray(1);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glUniform1i(
|
|
glGetUniformLocation(tc_game_state_g.renderer.draw_shader.program_id, "block_atlas"),
|
|
0
|
|
);
|
|
glBindTexture(GL_TEXTURE_2D, tc_game_state_g.block_texture_atlas->gl_identifier);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, chunk->num_vertices);
|
|
|
|
glBindVertexArray(0);
|
|
}
|
|
|
|
void tc_init_world_generators()
|
|
{
|
|
tc_default_terrain_generator_g.name = "Default Terrain Generator";
|
|
tc_default_terrain_generator_g.fn_generate_chunk = &tc_generate_default_terrain_chunk;
|
|
}
|
|
|
|
|
|
// The userdata should be the corresponding world
|
|
void tc_create_chunk_entity(tc_entity_s *entity, void *userdata)
|
|
{
|
|
tc_chunk_s *chunk = tc_allocate_chunk();
|
|
tc_world_s *world = userdata;
|
|
|
|
tc_set_string_for_entity(entity, "type", "chunk");
|
|
tc_set_integer_for_entity(entity, "grid_x", 0);
|
|
tc_set_integer_for_entity(entity, "grid_y", 0);
|
|
tc_set_integer_for_entity(entity, "grid_z", 0);
|
|
entity->specific = chunk;
|
|
|
|
tc_run_hooklist(&world->on_chunk_create, chunk);
|
|
}
|
|
|
|
void tc_spawn_chunk_entity(tc_entity_s *entity, tc_location_s location)
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
void tc_teleport_chunk_entity(tc_entity_s *entity, tc_location_s location)
|
|
{
|
|
tc_chunk_s *chunk = entity->specific;
|
|
chunk->world = location.world;
|
|
chunk->position.x = location.position.x / 32;
|
|
chunk->position.y = location.position.y / 32;
|
|
chunk->position.z = location.position.z / 32;
|
|
}
|
|
|
|
void tc_delete_chunk_entity(tc_entity_s *entity)
|
|
{
|
|
tc_free_chunk(entity->specific);
|
|
}
|
|
|
|
void tc_receive_chunk_entity_event(tc_entity_s *entity, tc_entity_event_s event)
|
|
{
|
|
|
|
}
|
|
|
|
void tc_add_chunk_entity_type()
|
|
{
|
|
tc_fn_entity_s chunk_functions;
|
|
chunk_functions.fn_create = &tc_create_chunk_entity;
|
|
chunk_functions.fn_spawn = &tc_spawn_chunk_entity;
|
|
chunk_functions.fn_teleport = &tc_teleport_chunk_entity;
|
|
chunk_functions.fn_draw = &tc_draw_chunk_entity;
|
|
chunk_functions.fn_delete = &tc_delete_chunk_entity;
|
|
chunk_functions.fn_send_event = &tc_receive_chunk_entity_event;
|
|
|
|
tc_entity_type_s chunk_type;
|
|
chunk_type.internal_name = "chunk";
|
|
chunk_type.display_name = NULL;
|
|
chunk_type.functions = chunk_functions;
|
|
chunk_type.instances_capacity = 512;
|
|
|
|
tc_register_entity_type(chunk_type);
|
|
tc_chunk_entity_type_g = tc_get_entity_type_with_name("chunk");
|
|
}
|
|
|
|
void tc_init_worlds()
|
|
{
|
|
tc_init_chunk_pool(256);
|
|
tc_add_chunk_entity_type();
|
|
tc_init_world_generators();
|
|
}
|
|
|
|
|
|
|
|
void tc_set_block_in_chunk(
|
|
tc_chunk_s *chunk,
|
|
uint8_t x, uint8_t y, uint8_t z,
|
|
tc_block_s block
|
|
) {
|
|
chunk->blocks[x][y][z] = block.type_identifier;
|
|
}
|
|
|
|
void tc_draw_world(tc_world_s *world)
|
|
{
|
|
tc_draw_all_entities_of_type("chunk");
|
|
}
|
|
tc_chunkloader_s tc_create_chunkloader(tc_world_s *world)
|
|
{
|
|
tc_chunkloader_s loader;
|
|
loader.extent.x = UPDATE_DISTANCE * 2 + 1;
|
|
loader.extent.y = UPDATE_DISTANCE * 2 + 1;
|
|
loader.extent.z = UPDATE_DISTANCE * 2 + 1;
|
|
loader.center.x = 0;
|
|
loader.center.y = 0;
|
|
loader.center.z = 0;
|
|
loader.chunks_capacity = 512;
|
|
loader.chunks = calloc(sizeof(tc_entity_s *), loader.chunks_capacity);
|
|
loader.num_chunks = 0;
|
|
loader.needs_reload = false;
|
|
|
|
return loader;
|
|
}
|
|
|
|
tc_chunkloader_s tc_create_spawn_loader(tc_world_s *world)
|
|
{
|
|
tc_chunkloader_s loader = tc_create_chunkloader(world);
|
|
loader.needs_reload = true;
|
|
loader.world = world;
|
|
|
|
return loader;
|
|
}
|
|
|
|
tc_world_s * tc_new_world(tc_worldgen_s *generator)
|
|
{
|
|
tc_world_s *world = calloc(sizeof(tc_world_s), 1);
|
|
world->worldgen = &tc_default_terrain_generator_g;
|
|
world->num_loaders = 1;
|
|
world->loaders = malloc(sizeof(tc_chunkloader_s) * world->num_loaders);
|
|
world->loaders[0] = tc_create_spawn_loader(world);
|
|
world->spawn_loader = &world->loaders[0];
|
|
world->on_chunk_create = tc_new_hooklist(16);
|
|
world->on_chunk_generate = tc_new_hooklist(16);
|
|
world->after_chunk_generate = tc_new_hooklist(16);
|
|
world->on_chunk_delete = tc_new_hooklist(16);
|
|
world->on_chunk_update = tc_new_hooklist(16);
|
|
|
|
tc_add_to_hooklist(&world->after_chunk_generate, tc_meshize_chunk, NULL);
|
|
|
|
tc_run_hooklist(&tc_game_state_g.on_world_create, world);
|
|
|
|
return world;
|
|
}
|
|
|