diff --git a/deerith_client/include/deerith/client/cluster.h b/deerith_client/include/deerith/client/cluster.h new file mode 100644 index 0000000..11dff58 --- /dev/null +++ b/deerith_client/include/deerith/client/cluster.h @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include + +namespace deerith +{ + struct cluster_generator_t + { + voxel_cluster_t *cluster; + mesh_3d_data_t build_data; + + void generate_voxel(int x, int y, int z); + void generate_cluster(voxel_cluster_t *cluster); + voxel_type_id_t get_cluster_voxel(int x, int y, int z); + }; + + void generate_cluster(voxel_cluster_t *cluster); + void render_clusters(glm::ivec3 position, int rad); + void flush_cluster_to_gpu(); + void clear_all_clusters(); + + extern std::mutex cluster_workers_mutex; + extern std::vector> cluster_workers; +} \ No newline at end of file diff --git a/deerith_client/src/graphics/primitives.cpp b/deerith_client/src/graphics/primitives.cpp index 1958b66..c11b4e0 100644 --- a/deerith_client/src/graphics/primitives.cpp +++ b/deerith_client/src/graphics/primitives.cpp @@ -33,12 +33,14 @@ void deerith::create_grid_mesh() for (int i = 0; i < GRID_SIZE; i++) { float relative_position = static_cast(i) / static_cast(GRID_SIZE - 1); - float absolute_position = (relative_position * 2.0f - 1.0f) * static_cast(GRID_SIZE); - grid_vertices.push_back(glm::vec3(absolute_position, 0, -GRID_SIZE)); - grid_vertices.push_back(glm::vec3(absolute_position, 0, GRID_SIZE)); + float absolute_position = (relative_position - 0.5f) * static_cast(GRID_SIZE - 1); + float extrem = static_cast(GRID_SIZE - 1) / 2.0f; - grid_vertices.push_back(glm::vec3(-GRID_SIZE, 0, absolute_position)); - grid_vertices.push_back(glm::vec3(GRID_SIZE, 0, absolute_position)); + grid_vertices.push_back(glm::vec3(absolute_position, 0, -extrem)); + grid_vertices.push_back(glm::vec3(absolute_position, 0, extrem)); + + grid_vertices.push_back(glm::vec3(-extrem, 0, absolute_position)); + grid_vertices.push_back(glm::vec3(extrem, 0, absolute_position)); } grid_mesh = std::make_unique(&grid_vertices[0], vertex_count, nullptr, 0); diff --git a/deerith_client/src/graphics/window.cpp b/deerith_client/src/graphics/window.cpp index 6dddc15..c9414b0 100644 --- a/deerith_client/src/graphics/window.cpp +++ b/deerith_client/src/graphics/window.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -144,6 +145,8 @@ void deerith::shutdown_window() ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); + clear_all_clusters(); + shutdown_primitives(); shutdown_world(); shutdown_network(); diff --git a/deerith_client/src/world/cluster_generation.cpp b/deerith_client/src/world/cluster_generation.cpp index 1e86c9a..4fed663 100644 --- a/deerith_client/src/world/cluster_generation.cpp +++ b/deerith_client/src/world/cluster_generation.cpp @@ -1,39 +1,30 @@ #include #include #include +#include +#include + #include #include -#include namespace deerith { - voxel_cluster_t *cluster = nullptr; - - void generate_voxel(int x, int y, int z); - voxel_type_id_t get_cluster_voxel(int x, int y, int z); - - std::unique_ptr test_mesh; - std::unique_ptr build_data; + std::mutex cluster_workers_mutex; + std::vector> cluster_workers; } -void deerith::load_clusters_to_gpu() +void deerith::generate_cluster(voxel_cluster_t *cluster) { - if (build_data) - { - test_mesh = std::make_unique(*build_data); - build_data.reset(); - } + std::lock_guard lock(cluster_workers_mutex); + + cluster_workers.push_back(std::make_unique()); + cluster_generator_t *generator = cluster_workers.back().get(); + generator->generate_cluster(cluster); } -void deerith::generate_cluster(voxel_cluster_t *_cluster) +void deerith::cluster_generator_t::generate_cluster(voxel_cluster_t *_cluster) { - if (build_data) - { - return; - } - cluster = _cluster; - build_data = std::make_unique(); if (cluster == nullptr) { @@ -51,11 +42,9 @@ void deerith::generate_cluster(voxel_cluster_t *_cluster) } } } - - cluster = nullptr; } -void deerith::generate_voxel(int x, int y, int z) +void deerith::cluster_generator_t::generate_voxel(int x, int y, int z) { voxel_type_id_t cur_type_id = cluster->__data[x][y][z]; const voxel_type_t &cur_type = get_voxel_type(cur_type_id); @@ -82,27 +71,27 @@ void deerith::generate_voxel(int x, int y, int z) continue; } - uint32_t starting_index = build_data->vertices.size(); + uint32_t starting_index = build_data.vertices.size(); // HEY BUILD FACE for (int v = 0; v < 4; v++) { vertex_3d_t vertex = { - .position = voxel_position + voxel_direction_vertices[i][v] * VOXEL_SIZE, + .position = voxel_position + voxel_direction_vertices[i][v], .normal = voxel_direction_order[i], }; - build_data->vertices.push_back(vertex); + build_data.vertices.push_back(vertex); } for (int index = 0; index < 6; index++) { - build_data->indices.push_back(starting_index + face_indices_order[index]); + build_data.indices.push_back(starting_index + face_indices_order[index]); } } } -deerith::voxel_type_id_t deerith::get_cluster_voxel(int x, int y, int z) +deerith::voxel_type_id_t deerith::cluster_generator_t::get_cluster_voxel(int x, int y, int z) { bool in_bounds_check = true; if (x < 0 || x >= CLUSTER_SIZE) @@ -123,6 +112,8 @@ deerith::voxel_type_id_t deerith::get_cluster_voxel(int x, int y, int z) return cluster->__data[x][y][z]; } + return 0; + glm::ivec3 coords; coords.x = x + CLUSTER_SIZE * cluster->surface_id.x; coords.y = y + CLUSTER_SIZE * cluster->layer; diff --git a/deerith_client/src/world/cluster_storage.cpp b/deerith_client/src/world/cluster_storage.cpp new file mode 100644 index 0000000..593f776 --- /dev/null +++ b/deerith_client/src/world/cluster_storage.cpp @@ -0,0 +1,85 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace deerith +{ + std::unordered_map, ivec3_hash_t> loaded_clusters; + + void render_cluster(glm::ivec3); +} + +void deerith::clear_all_clusters() +{ + loaded_clusters.clear(); +} + +void deerith::flush_cluster_to_gpu() +{ + std::lock_guard lock(cluster_workers_mutex); + + for (std::unique_ptr &cluster_generator : cluster_workers) + { + glm::ivec3 cluster_position; + cluster_position.x = cluster_generator->cluster->surface_id.x; + cluster_position.z = cluster_generator->cluster->surface_id.y; + cluster_position.y = cluster_generator->cluster->layer; + + loaded_clusters[cluster_position] = std::make_unique(cluster_generator->build_data); + } + + cluster_workers.clear(); +} + +void deerith::render_clusters(glm::ivec3 position, int rad) +{ + // Radial outward + for (int r = 0; r <= rad; r++) + { + for (int x = -r; x <= r; x++) + { + for (int y = -r; y <= r; y++) + { + for (int z = -r; z <= r; z++) + { + // Only process the current outer layer + if (std::max({std::abs(x), std::abs(y), std::abs(z)}) != r) + { + continue; + } + + glm::ivec3 cluster_position = position + glm::ivec3(x, y, z); + + render_cluster(cluster_position); + } + } + } + } +} + +void deerith::render_cluster(glm::ivec3 pos) +{ + if (!loaded_clusters.contains(pos)) + { + return; + } + + std::unique_ptr &cluster_mesh = loaded_clusters[pos]; + + float offset = static_cast(CLUSTER_SIZE) * static_cast(VOXEL_SIZE); + glm::vec3 position = glm::vec3(offset * static_cast(pos.x), offset * static_cast(pos.y), offset * static_cast(pos.z)); + glm::quat rotation = glm::identity(); + glm::vec3 scale = glm::vec3(VOXEL_SIZE, VOXEL_SIZE, VOXEL_SIZE); + + get_lit_shader()->use(); + get_lit_shader()->set_vec4("u_color", glm::vec4(1, 0.4f, 0.6f, 1)); + set_transform_to_shader(position, rotation, scale, get_lit_shader()); + cluster_mesh->draw(); +} \ No newline at end of file diff --git a/deerith_client/src/world/world_render.cpp b/deerith_client/src/world/world_render.cpp index f9692fb..ed8f70a 100644 --- a/deerith_client/src/world/world_render.cpp +++ b/deerith_client/src/world/world_render.cpp @@ -1,11 +1,12 @@ #include #include +#include #include #include -#include #include #include +#include #include #include @@ -19,7 +20,8 @@ namespace deerith void deerith::render_world() { process_player_input(); - load_clusters_to_gpu(); + flush_cluster_to_gpu(); + get_lit_shader()->set_vec3("u_color", glm::vec3(0.8f, 0.8f, 0.8f)); set_primitive_viewspace(glm::vec2(-10, -10), glm::vec2(10, 10)); @@ -46,37 +48,12 @@ void deerith::render_world() set_transform_to_shader(glm::vec3(0, 0, 0), glm::identity(), glm::vec3(1, 1, 1), get_lit_shader()); get_grid_mesh()->draw_lines(); - auto entities_view = get_entity_registry().view(entt::exclude); + static glm::ivec3 pos; + auto entities_view = get_entity_registry().view(); for (auto [entity, sync_coords] : entities_view.each()) { - glm::vec3 chords; - if (sync_coords.position.read_synced(chords)) - { - - glm::vec3 position = chords; - glm::quat rotation = glm::identity(); - glm::vec3 scale = glm::vec3(1, 1, 1); - - get_lit_shader()->set_vec4("u_color", glm::vec4(1, 0.4f, 0.6f, 1)); - set_transform_to_shader(position, rotation, scale, get_lit_shader()); - - get_lit_shader()->use(); - get_cube_mesh()->draw(); - } + pos = get_nearest_cluster(sync_coords.position); } - // we should expect only one registry - - if (test_mesh) - { - get_lit_shader()->set_vec3("u_color", glm::vec3(0.9f, 0.9f, 0.9f)); - glm::vec3 position = glm::vec3(0, 0, 0); - glm::quat rotation = glm::identity(); - glm::vec3 scale = glm::vec3(1, 1, 1); - - set_transform_to_shader(position, rotation, scale, get_lit_shader()); - - get_lit_shader()->use(); - test_mesh->draw(); - } + render_clusters(pos, 10); } \ No newline at end of file diff --git a/deerith_engine_core/include/deerith/world/environment.h b/deerith_engine_core/include/deerith/world/environment.h index 29524a0..07d55d6 100644 --- a/deerith_engine_core/include/deerith/world/environment.h +++ b/deerith_engine_core/include/deerith/world/environment.h @@ -42,6 +42,8 @@ namespace deerith int32_t get_cluster_last_tick_update(glm::ivec2 surface_id, int layer); surface_t *get_surface(glm::ivec2); surface_t *get_create_surface(glm::ivec2); + + glm::ivec3 get_nearest_cluster(glm::vec3); } namespace deerith diff --git a/deerith_engine_core/include/deerith/world/texture.h b/deerith_engine_core/include/deerith/world/texture.h new file mode 100644 index 0000000..812bf3c --- /dev/null +++ b/deerith_engine_core/include/deerith/world/texture.h @@ -0,0 +1,42 @@ +#pragma once +#include +#include + +#include +#include +#include +#include + +#include + +namespace deerith +{ + using path_t = std::filesystem::path; + + struct texture_builder_entry_t + { + std::string id; + path_t texture_location; + }; + + struct texture_builder_t + { + int unit_size = 32; + + std::vector entries; + }; + + struct texture_atlas_t + { + texture_atlas_t(const texture_builder_t &); + + int size_x; + int size_y; + + std::unique_ptr __texture_data; + std::unordered_map texture_name_id_map; + + // RGBA + uint8_t *get_pixel(int x, int y); + }; +} \ No newline at end of file diff --git a/deerith_engine_core/src/world/environment.cpp b/deerith_engine_core/src/world/environment.cpp index 0c67192..5a20354 100644 --- a/deerith_engine_core/src/world/environment.cpp +++ b/deerith_engine_core/src/world/environment.cpp @@ -108,6 +108,16 @@ glm::ivec3 deerith::get_internal_voxel_coords(glm::ivec2 coords, int height) return ic; } +glm::ivec3 deerith::get_nearest_cluster(glm::vec3 coords) +{ + glm::ivec3 coord = {}; + coord.x = std::floor(coords.x / static_cast(CLUSTER_SIZE)); + coord.y = std::floor(coords.y / static_cast(CLUSTER_SIZE)); + coord.z = std::floor(coords.z / static_cast(CLUSTER_SIZE)); + + return coord; +} + glm::ivec2 deerith::get_surface_id(glm::ivec3 coords) { glm::ivec2 surface_id = {}; diff --git a/deerith_engine_core/src/world/texture_atlas.cpp b/deerith_engine_core/src/world/texture_atlas.cpp new file mode 100644 index 0000000..7dcc520 --- /dev/null +++ b/deerith_engine_core/src/world/texture_atlas.cpp @@ -0,0 +1,18 @@ +#include + +namespace deerith +{ + +} + +uint8_t *deerith::texture_atlas_t::get_pixel(int x, int y) +{ + if (x < 0 || y < 0 || x >= size_x || y >= size_y) + return nullptr; + + return &__texture_data[(y * size_x + x) * 4]; +} + +deerith::texture_atlas_t::texture_atlas_t(const texture_builder_t &) +{ +} \ No newline at end of file diff --git a/sandbox/src/build_world.cpp b/sandbox/src/build_world.cpp index 921a269..da187f6 100644 --- a/sandbox/src/build_world.cpp +++ b/sandbox/src/build_world.cpp @@ -9,7 +9,112 @@ namespace deerith void sandbox::build_world() { - deerith::set_voxel(1, glm::vec3(0, 0, 0)); - deerith::set_voxel(1, glm::vec3(3, 4, 1)); - deerith::set_voxel(1, glm::vec3(2, 4, 1)); + + constexpr int SIZE = 32; + constexpr int WALL_HEIGHT = 5; + constexpr int TOWER_HEIGHT = 12; + + // Foundation + for (int x = 0; x < SIZE; ++x) + { + for (int z = 0; z < SIZE; ++z) + { + deerith::set_voxel(1, glm::vec3(x, 0, z)); + } + } + + // Outer walls + for (int x = 0; x < SIZE; ++x) + { + for (int y = 1; y <= WALL_HEIGHT; ++y) + { + // Entrance + if (x >= 13 && x <= 18 && y <= 3) + continue; + + deerith::set_voxel(1, glm::vec3(x, y, 0)); + deerith::set_voxel(1, glm::vec3(x, y, SIZE - 1)); + } + } + + for (int z = 0; z < SIZE; ++z) + { + for (int y = 1; y <= WALL_HEIGHT; ++y) + { + deerith::set_voxel(1, glm::vec3(0, y, z)); + deerith::set_voxel(1, glm::vec3(SIZE - 1, y, z)); + } + } + + // Corner towers + for (int tx : {0, SIZE - 1}) + { + for (int tz : {0, SIZE - 1}) + { + for (int x = tx - 2; x <= tx + 2; ++x) + { + for (int z = tz - 2; z <= tz + 2; ++z) + { + for (int y = 1; y <= TOWER_HEIGHT; ++y) + { + bool inside = + x > tx - 2 && x < tx + 2 && + z > tz - 2 && z < tz + 2; + + if (!inside) + { + deerith::set_voxel(1, glm::vec3(x, y, z)); + } + } + } + } + + // Tower roofs + for (int x = tx - 3; x <= tx + 3; ++x) + { + for (int z = tz - 3; z <= tz + 3; ++z) + { + deerith::set_voxel( + 1, glm::vec3(x, TOWER_HEIGHT + 1, z)); + } + } + } + } + + // Central keep + for (int x = 10; x <= 21; ++x) + { + for (int z = 10; z <= 21; ++z) + { + for (int y = 1; y <= 10; ++y) + { + bool inside = + x > 11 && x < 20 && + z > 11 && z < 20; + + if (!inside) + { + deerith::set_voxel(1, glm::vec3(x, y, z)); + } + } + } + } + + // Keep roof + for (int x = 9; x <= 22; ++x) + { + for (int z = 9; z <= 22; ++z) + { + deerith::set_voxel(1, glm::vec3(x, 11, z)); + } + } + + // Entrance bridge + for (int x = 13; x <= 18; ++x) + { + for (int z = -5; z < 0; ++z) + { + deerith::set_voxel(1, glm::vec3(x, 0, z)); + } + } } \ No newline at end of file