Compare commits

..

2 Commits

Author SHA1 Message Date
fad6f4d697 Started texture atlas 2026-11-04 01:05:25 +01:00
12f52f6987 changed to __data 2026-11-03 23:02:44 +01:00
13 changed files with 335 additions and 75 deletions

View File

@ -0,0 +1,25 @@
#pragma once
#include <deerith/world/environment.h>
#include <deerith/client/graphics/mesh.h>
#include <mutex>
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<std::unique_ptr<cluster_generator_t>> cluster_workers;
}

View File

@ -33,12 +33,14 @@ void deerith::create_grid_mesh()
for (int i = 0; i < GRID_SIZE; i++)
{
float relative_position = static_cast<float>(i) / static_cast<float>(GRID_SIZE - 1);
float absolute_position = (relative_position * 2.0f - 1.0f) * static_cast<float>(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<float>(GRID_SIZE - 1);
float extrem = static_cast<float>(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<mesh_3d_t>(&grid_vertices[0], vertex_count, nullptr, 0);

View File

@ -2,6 +2,7 @@
#include <deerith/client/graphics/primitive_internals.h>
#include <deerith/client/internals/network.h>
#include <deerith/client/world.h>
#include <deerith/client/cluster.h>
#include <glad/gl.h>
#include <GLFW/glfw3.h>
@ -144,6 +145,8 @@ void deerith::shutdown_window()
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
clear_all_clusters();
shutdown_primitives();
shutdown_world();
shutdown_network();

View File

@ -1,39 +1,30 @@
#include <deerith/client/world.h>
#include <deerith/world/environment.h>
#include <deerith/client/internals/cluster_generation.h>
#include <deerith/client/graphics/mesh.h>
#include <deerith/client/cluster.h>
#include <vector>
#include <memory>
#include <deerith/client/graphics/mesh.h>
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<mesh_3d_t> test_mesh;
std::unique_ptr<mesh_3d_data_t> build_data;
std::mutex cluster_workers_mutex;
std::vector<std::unique_ptr<cluster_generator_t>> cluster_workers;
}
void deerith::load_clusters_to_gpu()
void deerith::generate_cluster(voxel_cluster_t *cluster)
{
if (build_data)
{
test_mesh = std::make_unique<mesh_3d_t>(*build_data);
build_data.reset();
}
std::lock_guard<std::mutex> lock(cluster_workers_mutex);
cluster_workers.push_back(std::make_unique<cluster_generator_t>());
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<mesh_3d_data_t>();
if (cluster == nullptr)
{
@ -51,13 +42,11 @@ 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];
voxel_type_id_t cur_type_id = cluster->__data[x][y][z];
const voxel_type_t &cur_type = get_voxel_type(cur_type_id);
if (!cur_type.is_solid)
@ -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)
@ -120,9 +109,11 @@ deerith::voxel_type_id_t deerith::get_cluster_voxel(int x, int y, int z)
if (in_bounds_check)
{
return cluster->data[x][y][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;

View File

@ -0,0 +1,85 @@
#include <deerith/client/cluster.h>
#include <deerith/world/environment.h>
#include <unordered_map>
#include <deerith/client/graphics/shader.h>
#include <deerith/client/graphics/camera.h>
#include <deerith/client/graphics/mesh.h>
#include <deerith/client/graphics/primitive.h>
#include <deerith/client/internals/world.h>
#include <deerith/client/cluster.h>
namespace deerith
{
std::unordered_map<glm::ivec3, std::unique_ptr<mesh_3d_t>, 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<std::mutex> lock(cluster_workers_mutex);
for (std::unique_ptr<cluster_generator_t> &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<mesh_3d_t>(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<mesh_3d_t> &cluster_mesh = loaded_clusters[pos];
float offset = static_cast<float>(CLUSTER_SIZE) * static_cast<float>(VOXEL_SIZE);
glm::vec3 position = glm::vec3(offset * static_cast<float>(pos.x), offset * static_cast<float>(pos.y), offset * static_cast<float>(pos.z));
glm::quat rotation = glm::identity<glm::quat>();
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();
}

View File

@ -99,7 +99,7 @@ void deerith::process_packet(deerith::packet_cluster_data_t &packet, client_t *c
surface_t *surface = get_create_surface(packet.surface_id);
voxel_cluster_t *cluster = surface->get_create_cluster(packet.layer);
cluster->data = *packet.__cluster_data;
cluster->__data = *packet.__cluster_data;
generate_cluster(cluster);
}

View File

@ -1,11 +1,12 @@
#include <deerith/world/components.h>
#include <deerith/client/world.h>
#include <deerith/client/graphics/shader.h>
#include <deerith/client/graphics/camera.h>
#include <deerith/client/graphics/mesh.h>
#include <deerith/client/graphics/shader.h>
#include <deerith/client/graphics/primitive.h>
#include <deerith/client/internals/world.h>
#include <deerith/client/cluster.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
@ -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::quat>(), glm::vec3(1, 1, 1), get_lit_shader());
get_grid_mesh()->draw_lines();
auto entities_view = get_entity_registry().view<component_sync_coordinates_t>(entt::exclude<component_client_sync_character_t>);
static glm::ivec3 pos;
auto entities_view = get_entity_registry().view<component_client_sync_character_t>();
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::quat>();
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::quat>();
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);
}

View File

@ -18,7 +18,7 @@ namespace deerith
int32_t layer;
glm::ivec2 surface_id;
uint32_t last_update_tick_id;
cluster_voxel_type_id_data_t data = {};
cluster_voxel_type_id_data_t __data = {};
};
struct surface_t
@ -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

View File

@ -0,0 +1,42 @@
#pragma once
#include <deerith/engine.h>
#include <glm/glm.hpp>
#include <filesystem>
#include <vector>
#include <memory>
#include <string>
#include <unordered_map>
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<texture_builder_entry_t> entries;
};
struct texture_atlas_t
{
texture_atlas_t(const texture_builder_t &);
int size_x;
int size_y;
std::unique_ptr<uint8_t[]> __texture_data;
std::unordered_map<std::string, glm::ivec2> texture_name_id_map;
// RGBA
uint8_t *get_pixel(int x, int y);
};
}

View File

@ -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<float>(CLUSTER_SIZE));
coord.y = std::floor(coords.y / static_cast<float>(CLUSTER_SIZE));
coord.z = std::floor(coords.z / static_cast<float>(CLUSTER_SIZE));
return coord;
}
glm::ivec2 deerith::get_surface_id(glm::ivec3 coords)
{
glm::ivec2 surface_id = {};
@ -137,7 +147,7 @@ void deerith::set_voxel(voxel_type_id_t voxel_id, glm::ivec3 coordinates)
voxel_cluster_t *cluster = surface->get_create_cluster(layer);
cluster->last_update_tick_id = get_world_tick();
cluster->data[internal_voxel_id.x][internal_voxel_id.y][internal_voxel_id.z] = voxel_id;
cluster->__data[internal_voxel_id.x][internal_voxel_id.y][internal_voxel_id.z] = voxel_id;
}
deerith::voxel_type_id_t deerith::get_voxel_id(glm::ivec3 coordinates)
@ -160,7 +170,7 @@ deerith::voxel_type_id_t deerith::get_voxel_id(glm::ivec3 coordinates)
return 0;
}
return cluster->data[internal_voxel_id.x][internal_voxel_id.y][internal_voxel_id.z];
return cluster->__data[internal_voxel_id.x][internal_voxel_id.y][internal_voxel_id.z];
}
const deerith::voxel_type_t &deerith::get_voxel(glm::ivec3 coordinates)

View File

@ -0,0 +1,18 @@
#include <deerith/world/texture.h>
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 &)
{
}

View File

@ -103,7 +103,7 @@ void deerith::send_cluster_info_to_client(client_t *client, voxel_cluster_t *clu
cluster_data.layer = cluster->layer;
cluster_data.__cluster_data = std::make_unique<cluster_voxel_type_id_data_t>();
*cluster_data.__cluster_data = cluster->data;
*cluster_data.__cluster_data = cluster->__data;
router_send_packet(cluster_data, client);
deerith_trace("sent cluster data to client in {} ms", get_chrono_ms());

View File

@ -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));
}
}
}