diff --git a/code/source-c/chunk_loader.c b/code/source-c/chunk_loader.c new file mode 100644 index 0000000..d9a3efc --- /dev/null +++ b/code/source-c/chunk_loader.c @@ -0,0 +1,178 @@ +#include "world.h" + +#include +#include + +void tc_on_each_chunkloader(tc_world_s *world, bool (*fn_do)(tc_chunkloader_s *loader, void *userdata), void *userdata) +{ + for(uint32_t loader_index = 0; loader_index < world->num_loaders; ++loader_index) + if(fn_do(&world->loaders[loader_index], userdata)) return; +} + +void tc_on_each_loaded_chunk(tc_world_s *world, bool (*fn_do)(tc_chunk_s *chunk, void *userdata), void *userdata) +{ + for(uint32_t loader_index = 0; loader_index < world->num_loaders; ++loader_index) + for(uint32_t chunk_index = 0; chunk_index < world->loaders[loader_index].num_chunks; ++chunk_index) + if(fn_do(world->loaders[loader_index].chunks[chunk_index], userdata)) return; +} + +void tc_on_each_chunk_of_loader(tc_chunkloader_s *loader, bool (*fn_do)(tc_chunk_s *chunk, void *userdata), void *userdata) +{ + uint32_t chunk_index = 0; + while(chunk_index < loader->num_chunks) + { + if(fn_do(loader->chunks[chunk_index], userdata)) return; + ++chunk_index; + } +} + + +bool tc_coord_is_within_loaders_range(tc_chunkloader_s *loader, tc_vec3i_s coord) +{ + if(coord.x < (loader->center.x - loader->extent.x / 2)) return false; + if(coord.y < (loader->center.y - loader->extent.y / 2)) return false; + if(coord.z < (loader->center.z - loader->extent.z / 2)) return false; + + if(coord.x > (loader->center.x + loader->extent.x / 2)) return false; + if(coord.y > (loader->center.y + loader->extent.y / 2)) return false; + if(coord.z > (loader->center.z + loader->extent.z / 2)) return false; + + return true; +} + +tc_chunkloader_s * tc_get_corresponding_loader(tc_world_s *world, tc_vec3i_s coord) +{ + for(uint32_t loader_index = 0; loader_index < world->num_loaders; ++loader_index) + if(tc_coord_is_within_loaders_range(&world->loaders[loader_index], coord)) + return &world->loaders[loader_index]; + + return NULL; +} + +tc_chunk_s * tc_get_chunk_of_loader(tc_chunkloader_s *loader, tc_vec3i_s coord) +{ + for(uint32_t chunk_index = 0; chunk_index < loader->num_chunks; ++chunk_index) + if(tc_vec3i_equ(loader->chunks[chunk_index]->position, coord)) + return loader->chunks[chunk_index]; + + return NULL; +} + +tc_chunk_s * tc_get_loaded_chunk(tc_world_s *world, tc_vec3i_s coord) +{ + tc_chunkloader_s *loader = tc_get_corresponding_loader(world, coord); + if(loader == NULL) return NULL; + + return tc_get_chunk_of_loader(loader, coord); +} + +tc_chunk_s * tc_load_chunk_of_loader(tc_chunkloader_s *loader, tc_vec3i_s coord) +{ + tc_chunk_s *chunk = tc_get_chunk_of_loader(loader, coord); + + if(chunk == NULL) + { + printf("Creating chunk at: %d %d %d\n", coord.x, coord.y, coord.z); + + chunk = tc_allocate_chunk(loader->world); + chunk->position = coord; + + loader->world->worldgen->fn_generate_chunk(loader->world->worldgen, chunk); + tc_upload_chunk(chunk); + + tc_add_chunk_to_loader(loader, chunk); + } + return chunk; +} + +void tc_reload_chunk_of_loader(tc_chunkloader_s *loader, tc_vec3i_s coord) +{ + tc_chunk_s *chunk = tc_get_chunk_of_loader(loader, coord); + if(chunk == NULL) return; + + tc_meshize_chunk(chunk); + tc_upload_chunk(chunk); +} + +void tc_reload_chunk(tc_world_s *world, tc_vec3i_s coord) +{ + tc_chunkloader_s *loader = tc_get_corresponding_loader(world, coord); + if(loader == NULL) return; + + tc_reload_chunk_of_loader(loader, coord); +} + +void tc_remove_loaders_chunk(tc_chunkloader_s *loader, uint32_t index) +{ + tc_free_chunk(loader->world, loader->chunks[index]); + + // This is is NOT last element + if((index+1) < loader->num_chunks) + { + loader->chunks[index] = loader->chunks[loader->num_chunks-1]; // move last chunk into gap + } + + --loader->num_chunks; +} + +void tc_remove_unnecessary_chunks_of_loader(tc_chunkloader_s *loader) +{ + for(uint32_t chunk_index = 0; chunk_index < loader->num_chunks; ++chunk_index) + { + tc_chunk_s *chunk = loader->chunks[chunk_index]; + if(!tc_coord_is_within_loaders_range(loader, chunk->position)) + { + printf("Chunk at %d %d %d isn't in range\n", chunk->position.x, chunk->position.y, chunk->position.z); + tc_remove_loaders_chunk(loader, chunk_index); + } + } +} + +void tc_load_all_chunks_of_chunkloader(tc_chunkloader_s *loader) +{ + for(uint32_t x = 0; x < loader->extent.x; ++x) + { + for(uint32_t y = 0; y < loader->extent.y; ++y) + { + for(uint32_t z = 0; z < loader->extent.z; ++z) + { + tc_vec3i_s coords; + /* + coords.x = ((x + loader->center.x) - (loader->extent.x / 2)) + loader->extent.x; + coords.y = ((y + loader->center.y) - (loader->extent.y / 2)) + loader->extent.y; + coords.z = ((z + loader->center.z) - (loader->extent.z / 2)) + loader->extent.z; + */ + coords.x = loader->center.x + (x - (loader->extent.x / 2)); + coords.y = loader->center.y + (y - (loader->extent.y / 2)); + coords.z = loader->center.z + (z - (loader->extent.z / 2)); + + tc_load_chunk_of_loader(loader, coords); + } + } + } +} + +void tc_reload_chunkloader_zone(tc_chunkloader_s *loader) +{ + tc_remove_unnecessary_chunks_of_loader(loader); + tc_load_all_chunks_of_chunkloader(loader); +} + +void tc_update_world(tc_world_s *world) +{ + world->loaders[0].center.x = world->loading_center.x; + world->loaders[0].center.y = world->loading_center.y; + world->loaders[0].center.z = world->loading_center.z; + + uint32_t chunkloader_index = 0; + while(chunkloader_index < world->num_loaders) + { + if(world->loaders[chunkloader_index].needs_reload) + { + tc_reload_chunkloader_zone(&world->loaders[chunkloader_index]); + } + ++chunkloader_index; + } +} + +// TODO: Set center chunk diff --git a/code/source-c/chunk_loading.c b/code/source-c/chunk_loading.c deleted file mode 100644 index 1eb41bc..0000000 --- a/code/source-c/chunk_loading.c +++ /dev/null @@ -1,324 +0,0 @@ -#include "world.h" - -#include -#include - -void tc_on_each_chunkloader(tc_world_s *world, bool (*fn_do)(tc_chunkloader_s *loader, void *userdata), void *userdata) -{ - for(uint32_t loader_index = 0; loader_index < world->num_loaders; ++loader_index) - if(fn_do(&world->loaders[loader_index], userdata)) return; -} - -void tc_on_each_loaded_chunk(tc_world_s *world, bool (*fn_do)(tc_chunk_s *chunk, void *userdata), void *userdata) -{ - for(uint32_t loader_index = 0; loader_index < world->num_loaders; ++loader_index) - for(uint32_t chunk_index = 0; chunk_index < world->loaders[loader_index].num_chunks; ++chunk_index) - if(fn_do(world->loaders[loader_index].chunks[chunk_index], userdata)) return; -} - -void tc_on_each_chunk_of_loader(tc_chunkloader_s *loader, bool (*fn_do)(tc_chunk_s *chunk, void *userdata), void *userdata) -{ - uint32_t chunk_index = 0; - while(chunk_index < loader->num_chunks) - { - if(fn_do(loader->chunks[chunk_index], userdata)) return; - ++chunk_index; - } -} - -// TODO: Create and use vectors - -typedef struct tc_chunk_grid_distance -{ - int32_t x; - int32_t y; - int32_t z; - -} tc_chunk_grid_distance_s; - -tc_chunk_grid_distance_s tc_chunk_distance_to( - int32_t first_x, int32_t first_y, int32_t first_z, - int32_t last_x, int32_t last_y, int32_t last_z -) { - tc_chunk_grid_distance_s distance; - distance.x = last_x - first_x; - distance.y = last_y - first_y; - distance.z = last_z - first_z; - - return distance; -} - -bool tc_chunk_coordinate_is_within_loaded_zone(tc_world_s *world, int32_t x, int32_t y, int32_t z) -{ - if((world->loading_center.x + world->load_radius) < x) return false; - if((world->loading_center.y + world->load_radius) < y) return false; - if((world->loading_center.z + world->load_radius) < z) return false; - if((world->loading_center.x - world->load_radius) > x) return false; - if((world->loading_center.y - world->load_radius) > y) return false; - if((world->loading_center.z - world->load_radius) > z) return false; - - return true; -} - -bool tc_chunk_exists(tc_world_s *world, int32_t x, int32_t y, int32_t z) -{ - uint32_t loader_index = 0; - while(loader_index < world->num_loaders) - { - tc_chunkloader_s *loader = &world->loaders[loader_index]; - - for(uint32_t chunk_index = 0; chunk_index < loader->num_chunks; ++chunk_index) - { - tc_chunk_s *chunk = loader->chunks[chunk_index]; - - if(chunk->position.x != x) continue; - if(chunk->position.y != y) continue; - if(chunk->position.z != z) continue; - - return true; - } - ++loader_index; - } - - return false; -} - -bool tc_chunk_is_loaded(tc_world_s *world, int32_t x, int32_t y, int32_t z) -{ - // TODO: Further checks - - if(!tc_chunk_coordinate_is_within_loaded_zone(world, x, y, z)) return false; - if(!tc_chunk_exists(world, x, y, z)) return false; - printf("Checked for a chunk at %d:%d:%d and found it!\n", x, y, z); - return true; -} - -bool tc_check_chunk_coordinate_equality_for_getting_a_loaded_chunk(tc_chunk_s *chunk, void *userdata) -{ - struct payload { - int32_t x; - int32_t y; - int32_t z; - tc_chunk_s *result; - } *payload = userdata; - - if(chunk->position.x != payload->x) return false; - if(chunk->position.y != payload->y) return false; - if(chunk->position.z != payload->z) return false; - payload->result = chunk; - return true; -} - -tc_chunk_s * tc_get_loaded_chunk_at(tc_world_s *world, int32_t x, int32_t y, int32_t z) -{ - struct payload { - int32_t x; - int32_t y; - int32_t z; - tc_chunk_s *result; - } payload; - - payload.x = x; - payload.y = y; - payload.z = z; - payload.result = NULL; - - tc_on_each_loaded_chunk(world, &tc_check_chunk_coordinate_equality_for_getting_a_loaded_chunk, &payload); - - return payload.result; -} - - /* - tc_chunk_s *chunk = tc_chunk_at_south_east_bottom(world); - - tc_chunk_grid_distance_s distance = tc_chunk_distance_to( - chunk->position.x, chunk->position.y, chunk->position.z, - x, y, z - ); - - while(distance.x > 0) - { - chunk = chunk->east; - --distance.x; - } - - while(distance.y > 0) - { - chunk = chunk->top; - --distance.y; - } - - while(distance.z > 0) - { - chunk = chunk->north; - --distance.z; - } - - return chunk; -void tc_reassociate_surrounding_chunks(tc_chunk_s *old_chunk, tc_chunk_s *chunk) -{ - if(old_chunk->top != NULL) old_chunk->top->bottom = chunk; - if(old_chunk->bottom != NULL) old_chunk->bottom->top = chunk; - - if(old_chunk->east != NULL) old_chunk->east->west = chunk; - if(old_chunk->west != NULL) old_chunk->west->east = chunk; - - if(old_chunk->north != NULL) old_chunk->north->south = chunk; - if(old_chunk->south != NULL) old_chunk->south->north = chunk; -} -*/ - -void tc_place_chunk_at(tc_world_s *world, tc_chunk_s *chunk, int32_t x, int32_t y, int32_t z) -{ - tc_chunk_s *old_chunk = tc_get_loaded_chunk_at(world, x, y, z); - // tc_reassociate_surrounding_chunks(old_chunk, chunk); - tc_free_chunk(world, old_chunk); -} - -tc_chunk_s * tc_create_chunk_at(tc_world_s *world, int32_t x, int32_t y, int32_t z) -{ - tc_chunk_s *chunk = tc_allocate_chunk(world); - chunk->position.x = x; - chunk->position.y = y; - chunk->position.z = z; - - world->worldgen->fn_generate_chunk(world->worldgen, chunk); - tc_upload_chunk(chunk); - tc_place_chunk_at(world, chunk, x, y, z); - - return chunk; -} - -tc_chunk_s * tc_load_chunk_at(tc_world_s *world, int32_t x, int32_t y, int32_t z) -{ - if(!tc_chunk_is_loaded(world, x, y, z)) - { - return tc_create_chunk_at(world, x, y, z); - } - return tc_get_loaded_chunk_at(world, x, y, z); -} - -// Creates & Generates a chunk and provides a pointer to it -tc_chunk_s * tc_new_chunk(tc_world_s *world, int32_t x, int32_t y, int32_t z) -{ - tc_chunk_s *chunk = tc_allocate_chunk(world); - chunk->position.x = x; - chunk->position.y = y; - chunk->position.z = z; - world->worldgen->fn_generate_chunk(world->worldgen, chunk); - - return chunk; -} -/*c_ -void tc_shift_chunks_on_axis_x(tc_world_s *world, int32_t difference) -{ - - - -} - -void tc_shift_chunks_on_axis_y(tc_world_s *world, int32_t difference) -{ - - - -} - -// Go one further west with loading -void tc_shift_loading_one_west(tc_world_s *world) -{ - tc_chunk_s *north_eastern = world->center_chunk; - while(north_eastern->east != NULL) north_eastern = north_eastern->east; - while(north_eastern->north != NULL) north_eastern = north_eastern->north; - - tc_chunk_s *north_western = world->center_chunk; - while(north_western->west != NULL) north_western = north_western->west; - while(north_western->north != NULL) north_western = north_western->north; - - tc_chunk_s *eastern_edge = north_eastern; - while((eastern_edge != NULL) && (western_edge != NULL)) - { - eastern_west = western_edge; - eastern_edge = eastern_edge->south; - western_edge = western_edge->south; - } - - // Load new row - while(north_eastern != NULL) - { - north_ - north_eastern = north_eastern->south; - } - - tc_load_chunk(); -} - -void tc_shift_chunks_on_axis_z(tc_world_s *world, int32_t difference) -{ - if(difference > 0) - { - for(; difference > 0; --difference) - tc_shift_one_west(world); - } - - if(difference < 0) - { - for(; difference < 0; ++difference) - tc_shift_one_east(world); - } -} -*/ - -tc_chunk_s * tc_reload_chunk_of_loader(tc_chunkloader_s *loader, int32_t x, int32_t y, int32_t z) -{ - - - -} - -void tc_reload_chunkloader_zone(tc_world_s *world, tc_chunkloader_s *chunkloader) -{ - int32_t last_x = chunkloader->center_x + chunkloader->width; - int32_t last_y = chunkloader->center_y + chunkloader->height; - int32_t last_z = chunkloader->center_z + chunkloader->depth; - - int32_t chunk_x = chunkloader->center_x - chunkloader->width; - while(chunk_x < last_x) - { - int32_t chunk_y = chunkloader->center_y - chunkloader->height; - while(chunk_y < last_y) - { - int32_t chunk_z = chunkloader->center_z - chunkloader->depth; - while(chunk_z < last_z) - { - tc_chunk_s *chunk = tc_get_loaded_chunk_at(world, chunk_x, chunk_y, chunk_z); - if(chunk == NULL) - { - chunk = tc_allocate_chunk(world); - chunk->position.x = chunk_x; - chunk->position.y = chunk_y; - chunk->position.z = chunk_z; - tc_add_chunk_to_loader(chunkloader, world); - } - ++chunk_z; - } - ++chunk_y; - } - ++chunk_x; - } -} - -void tc_update_world(tc_world_s *world) -{ - uint32_t chunkloader_index = 0; - while(chunkloader_index < world->num_loaders) - { - if(world->loaders[chunkloader_index].needs_reload) - { - tc_reload_chunkloader_zone(world, &world->loaders[chunkloader_index]); - } - ++chunkloader_index; - } -} - -// TODO: Set center chunk diff --git a/code/source-c/chunk_pool.c b/code/source-c/chunk_pool.c index 75abc7a..3ca573a 100644 --- a/code/source-c/chunk_pool.c +++ b/code/source-c/chunk_pool.c @@ -54,6 +54,18 @@ void tc_free_chunk(tc_world_s *world, tc_chunk_s *chunk) { tc_chunk_pool_s *pool = world->pool; + if(chunk->vao != 0) glDeleteVertexArrays(1, &chunk->vertex_data); + chunk->vao = 0; + + if(chunk->vertex_data != 0) glDeleteBuffers(1, &chunk->vertex_data); + chunk->vertex_data = 0; + + if(chunk->vertex_positions != NULL) free(chunk->vertex_positions); + chunk->vertex_positions = NULL; + + if(chunk->vertex_uvs != NULL) free(chunk->vertex_uvs); + chunk->vertex_uvs = NULL; + chunk->superstructure->next = pool->first_free; pool->first_free = chunk->superstructure; } diff --git a/code/source-c/default_terrain_generator.c b/code/source-c/default_terrain_generator.c index 6801c5a..0ec4aec 100644 --- a/code/source-c/default_terrain_generator.c +++ b/code/source-c/default_terrain_generator.c @@ -8,6 +8,8 @@ bool tc_generate_default_terrain_chunk(tc_worldgen_s *gen, tc_chunk_s *chunk) block.position.y = 0.0f; block.position.z = 0.0f; + if(chunk->position.y > 0) return true; + uint32_t x_in_chunk = 0; uint32_t y_in_chunk = 0; uint32_t z_in_chunk = 0; diff --git a/code/source-c/main.c b/code/source-c/main.c index 92ae38f..779a80e 100644 --- a/code/source-c/main.c +++ b/code/source-c/main.c @@ -293,9 +293,9 @@ bool update() tc_camera_rotation.y += 0.1f / (3.1415 * 2); } - tc_game_state_g.main_world->loading_center.x = tc_camera_position.x / 32.0f; - tc_game_state_g.main_world->loading_center.y = tc_camera_position.y / 32.0f; - tc_game_state_g.main_world->loading_center.z = tc_camera_position.z / 32.0f; + tc_game_state_g.main_world->loading_center.x = ((int32_t) tc_camera_position.x) / 32; + tc_game_state_g.main_world->loading_center.y = ((int32_t) tc_camera_position.y) / 32; + tc_game_state_g.main_world->loading_center.z = ((int32_t) tc_camera_position.z) / 32; tc_update_world(tc_game_state_g.main_world); @@ -305,7 +305,7 @@ bool update() int main(int argc, char **argv) { tc_init(); - tc_new_chunk(tc_game_state_g.main_world, 1.0f, 1.0f, 1.0f); + // tc_new_chunk(tc_game_state_g.main_world, 1.0f, 1.0f, 1.0f); block = tc_new_block_at_3f(0.0, 0.0, 0.0); diff --git a/code/source-c/utility.h b/code/source-c/utility.h index 7cc4467..8cf0a69 100644 --- a/code/source-c/utility.h +++ b/code/source-c/utility.h @@ -1,7 +1,10 @@ -#ifndef TC_UTILITY_H +#ifndef TC_UTILITY_H #define TC_UTILITY_H +#include +#include + typedef struct tc_vec3 { float x; @@ -10,6 +13,16 @@ typedef struct tc_vec3 } tc_vec3_s; +typedef struct tc_vec3i +{ + int32_t x; + int32_t y; + int32_t z; + +} tc_vec3i_s; + +bool tc_vec3i_equ(tc_vec3i_s first, tc_vec3i_s second); + typedef struct tc_object { uint32_t vbo; diff --git a/code/source-c/vector.c b/code/source-c/vector.c new file mode 100644 index 0000000..e665ede --- /dev/null +++ b/code/source-c/vector.c @@ -0,0 +1,9 @@ +#include "utility.h" + +bool tc_vec3i_equ(tc_vec3i_s first, tc_vec3i_s second) +{ + if(first.x != second.x) return false; + if(first.y != second.y) return false; + if(first.z != second.z) return false; + return true; +} diff --git a/code/source-c/world.c b/code/source-c/world.c index aed3546..7b386d0 100644 --- a/code/source-c/world.c +++ b/code/source-c/world.c @@ -15,6 +15,9 @@ void tc_upload_chunk(tc_chunk_s *chunk) tc_meshize_chunk(chunk); } + 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); @@ -40,7 +43,7 @@ void tc_draw_chunk(tc_chunk_s *chunk, tc_world_s *world) mat4x4_translate_in_place(model_matrix, chunk->position.x*32, chunk->position.y*32, -chunk->position.z*32); int model_matrix_uniform_location = - glGetUniformLocation(tc_game_state_g.renderer.draw_shader.program_id, "model_matrix"); + glGetUniformLocation(tc_game_state_g.renderer.draw_shader.program_id, "model_matrix"); glUniformMatrix4fv(model_matrix_uniform_location, 1, GL_FALSE, &model_matrix[0][0]); // glBindVertexArray(chunk->vao); @@ -115,12 +118,12 @@ void tc_setup_terrain(tc_world_s *world) tc_chunkloader_s tc_create_chunkloader(tc_world_s *world) { tc_chunkloader_s loader; - loader.width = world->load_radius * 2 + 1; - loader.height = world->load_radius * 2 + 1; - loader.depth = world->load_radius * 2 + 1; - loader.center_x = 0; - loader.center_y = 0; - loader.center_z = 0; + loader.extent.x = world->load_radius * 2 + 1; + loader.extent.y = world->load_radius * 2 + 1; + loader.extent.z = world->load_radius * 2 + 1; + loader.center.x = 0; + loader.center.y = 0; + loader.center.z = 0; loader.chunks_capacity = 512; loader.chunks = calloc(sizeof(tc_chunk_s *), loader.chunks_capacity); loader.num_chunks = 0; @@ -144,6 +147,7 @@ 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; } @@ -154,7 +158,7 @@ tc_world_s * tc_new_world(tc_worldgen_s *generator) world->pool = tc_new_chunk_pool(128); world->worldgen = &tc_default_terrain_generator_g; // world->center_chunk = tc_new_chunk(world, 0, 0, 0); - world->load_radius = 3; + world->load_radius = 1; world->num_loaders = 1; world->loaders = malloc(sizeof(tc_chunkloader_s) * world->num_loaders); world->loaders[0] = tc_create_spawn_loader(world); diff --git a/code/source-c/world.h b/code/source-c/world.h index df93d39..a857242 100644 --- a/code/source-c/world.h +++ b/code/source-c/world.h @@ -36,7 +36,7 @@ struct tc_chunk { tc_chunk_pool_entry_s *superstructure; - tc_vec3_s position; + tc_vec3i_s position; uint32_t blocks[32][32][32]; uint32_t num_vertices; @@ -45,13 +45,6 @@ struct tc_chunk uint32_t vao; uint32_t vertex_data; - - tc_chunk_s *top; - tc_chunk_s *bottom; - tc_chunk_s *north; - tc_chunk_s *south; - tc_chunk_s *east; - tc_chunk_s *west; }; struct tc_chunk_pool_entry @@ -64,17 +57,13 @@ struct tc_chunk_pool_entry typedef struct tc_chunkloader { - uint32_t center_x; - uint32_t center_y; - uint32_t center_z; - - uint32_t width; - uint32_t height; - uint32_t depth; + tc_vec3i_s center; + tc_vec3i_s extent; uint32_t chunks_capacity; uint32_t num_chunks; tc_chunk_s **chunks; + tc_world_s *world; bool needs_reload;