#include #include #include 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; }