mountains

This commit is contained in:
Chewico 2026-11-08 21:31:52 +01:00
parent fad6f4d697
commit b7165d226a
44 changed files with 12985 additions and 185 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
build/
textures/

View File

@ -1,6 +1,7 @@
#pragma once
#include <deerith/world/environment.h>
#include <deerith/client/graphics/mesh.h>
#include <deerith/client/graphics/camera.h>
#include <mutex>
namespace deerith
@ -16,9 +17,9 @@ namespace deerith
};
void generate_cluster(voxel_cluster_t *cluster);
void render_clusters(glm::ivec3 position, int rad);
void render_clusters(glm::ivec3 position, int rad, const camera_t &);
void flush_cluster_to_gpu();
void clear_all_clusters();
void shutdown_environment();
extern std::mutex cluster_workers_mutex;
extern std::vector<std::unique_ptr<cluster_generator_t>> cluster_workers;

View File

@ -56,5 +56,4 @@ namespace deerith
size_t index_count = 0;
size_t vertex_count = 0;
};
}

View File

@ -0,0 +1,17 @@
#pragma once
#include <deerith/engine.h>
namespace deerith
{
class texture_t
{
public:
texture_t(const uint8_t *__data, int width, int height, int channels = 4, int max_mip_map = 0);
void bind(int);
private:
uint32_t texture_id;
int max_mip_map = 0;
};
}

View File

@ -12,11 +12,17 @@ namespace deerith
glm::ivec3(0, 0, 1),
};
glm::vec2 voxel_uv_order[4] = {
glm::vec2(0.0f, 0.0f),
glm::vec2(1.0f, 0.0f),
glm::vec2(0.0f, 1.0f),
glm::vec2(1.0f, 1.0f),
};
glm::vec3 voxel_direction_vertices[6][4] = {
// -X
{
{0, 0, 0},
{0, 0, 1},
{0, 0, 0},
{0, 1, 1},
{0, 1, 0},
},
@ -24,39 +30,39 @@ namespace deerith
// +X
{
{1, 0, 0},
{1, 0, 1},
{1, 1, 0},
{1, 1, 1},
{1, 0, 1},
},
// -Y
{
{0, 0, 1},
{1, 0, 1},
{0, 0, 0},
{1, 0, 0},
{1, 0, 1},
{0, 0, 1},
},
// +Y
{
{0, 1, 0},
{1, 1, 0},
{0, 1, 1},
{1, 1, 1},
{1, 1, 0},
},
// -Z
{
{0, 0, 0},
{1, 0, 0},
{0, 1, 0},
{1, 1, 0},
{1, 0, 0},
},
// +Z
{
{0, 0, 1},
{1, 0, 1},
{0, 0, 1},
{1, 1, 1},
{0, 1, 1},
},
@ -64,10 +70,10 @@ namespace deerith
uint32_t face_indices_order[6] = {
0,
2,
1,
3,
1,
2,
0,
2,
3,
};
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace deerith
{
void init_engine_render_specific();
void shutdown_engine_render_specific();
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <deerith/client/world.h>
#include <deerith/client/graphics/texture.h>
#include <deerith/client/graphics/shader.h>
namespace deerith
{
@ -7,4 +9,9 @@ namespace deerith
void process_player_input();
void send_player_input();
void generate_voxel_texture();
void init_voxel_shader();
void shutdown_world_variables();
}

View File

@ -1,6 +1,8 @@
#pragma once
#include <deerith/world/world_core.h>
#include <deerith/world/environment.h>
#include <deerith/client/graphics/texture.h>
#include <deerith/client/graphics/shader.h>
#include <glm/glm.hpp>
namespace deerith
@ -16,5 +18,8 @@ namespace deerith
void generate_cluster(voxel_cluster_t *_cluster);
void load_clusters_to_gpu();
shader_t *get_voxel_shader();
texture_t *get_voxel_texture();
client_t *get_server_client();
}

View File

@ -0,0 +1,34 @@
#version 330 core
in vec3 frag_position;
in vec3 frag_normal;
in vec2 frag_uv;
uniform sampler2D u_texture;
uniform vec3 u_color = vec3(1, 1, 1);
uniform vec3 u_light_direction = vec3(-1, 3, -2);
out vec4 FragColor;
void main()
{
// Sample texture
vec4 tex_color = texture(u_texture, frag_uv);
// Face normal
vec3 normal = normalize(frag_normal);
// Directional lighting
vec3 light_direction = normalize(u_light_direction);
float diffuse = max(dot(normal, light_direction), 0.0);
// Ambient + diffuse
float ambient = 0.25;
float lighting = ambient + diffuse * 0.75;
// Final color
vec3 color = tex_color.rgb * u_color * lighting;
FragColor = vec4(color, tex_color.a);
}

View File

@ -0,0 +1,24 @@
#version 330 core
layout (location = 0) in vec3 a_position;
layout (location = 1) in vec3 a_normal;
layout (location = 2) in vec2 a_uv;
uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;
out vec3 frag_position;
out vec3 frag_normal;
out vec2 frag_uv;
void main()
{
vec4 world_position = u_model * vec4(a_position, 1.0);
gl_Position = u_projection * u_view * world_position;
frag_position = world_position.xyz;
frag_normal = mat3(transpose(inverse(u_model))) * a_normal;
frag_uv = a_uv;
}

View File

@ -1,5 +1,10 @@
#include <deerith/engine.h>
#include <deerith/client/internals/network.h>
#include <deerith/client/internals/engine.h>
#include <deerith/client/internals/primitive.h>
#include <deerith/client/internals/world.h>
#include <deerith/client/internals/cluster_generation.h>
void deerith::init_engine()
{
@ -16,3 +21,19 @@ void deerith::shutdown_engine()
deerith_trace("shutdown engine");
shutdown_log();
}
void deerith::init_engine_render_specific()
{
init_primitives();
init_voxel_shader();
}
void deerith::shutdown_engine_render_specific()
{
shutdown_environment();
shutdown_primitives();
shutdown_world();
shutdown_network();
shutdown_world_variables();
}

View File

@ -106,8 +106,17 @@ deerith::mesh_3d_t::mesh_3d_t(const mesh_3d_data_t &mesh_data)
sizeof(vertex_3d_t),
(void *)offsetof(vertex_3d_t, normal));
glVertexAttribPointer(
2,
2,
GL_FLOAT,
GL_FALSE,
sizeof(vertex_3d_t),
(void *)offsetof(vertex_3d_t, uv));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindVertexArray(0);
}

View File

@ -1,4 +1,4 @@
#include <deerith/client/graphics/primitive_internals.h>
#include <deerith/client/internals/primitive.h>
#include <deerith/client/graphics/primitive.h>
#include <deerith/client/graphics/shader.h>
#include <deerith/client/graphics/mesh.h>

View File

@ -0,0 +1,52 @@
#include <deerith/client/graphics/texture.h>
#include <glad/gl.h>
namespace deerith
{
}
deerith::texture_t::texture_t(const uint8_t *__data, int width, int height, int channels, int mip_map)
{
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
int chanel_value = 0;
switch (channels)
{
case 1:
chanel_value = GL_RED;
break;
case 2:
chanel_value = GL_RG;
break;
case 3:
chanel_value = GL_RGB;
break;
case 4:
chanel_value = GL_RGBA;
break;
default:
deerith_error("incorrect channel value {}", channels);
return;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, chanel_value, GL_UNSIGNED_BYTE, __data);
glGenerateMipmap(GL_TEXTURE_2D);
max_mip_map = mip_map;
}
void deerith::texture_t::bind(int v)
{
glActiveTexture(GL_TEXTURE0 + v);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_mip_map);
}

View File

@ -1,8 +1,10 @@
#include <deerith/client/graphics/window.h>
#include <deerith/client/graphics/primitive_internals.h>
#include <deerith/client/internals/primitive.h>
#include <deerith/client/internals/network.h>
#include <deerith/client/world.h>
#include <deerith/client/cluster.h>
#include <deerith/client/internals/world.h>
#include <deerith/client/internals/engine.h>
#include <glad/gl.h>
#include <GLFW/glfw3.h>
@ -74,9 +76,10 @@ int deerith::init_window()
glDisable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
init_primitives();
init_imgui();
init_engine_render_specific();
return 0;
}
@ -145,11 +148,7 @@ void deerith::shutdown_window()
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
clear_all_clusters();
shutdown_primitives();
shutdown_world();
shutdown_network();
shutdown_engine_render_specific();
glfwDestroyWindow(window);
glfwTerminate();

View File

@ -55,6 +55,7 @@ void deerith::cluster_generator_t::generate_voxel(int x, int y, int z)
return;
}
texture_atlas_t *texture_atlas = get_voxel_texture_atlas();
glm::vec3 voxel_position = glm::vec3(x, y, z) * VOXEL_SIZE;
for (int i = 0; i < 6; i++)
@ -72,13 +73,15 @@ void deerith::cluster_generator_t::generate_voxel(int x, int y, int z)
}
uint32_t starting_index = build_data.vertices.size();
const voxel_material_t material = get_voxel_material(cur_type.material_id);
glm::vec2 uv_position = material.face_texture_id[i];
// HEY BUILD FACE
for (int v = 0; v < 4; v++)
{
vertex_3d_t vertex = {
.position = voxel_position + voxel_direction_vertices[i][v],
.position = voxel_position + voxel_direction_vertices[i][v] * VOXEL_SIZE,
.normal = voxel_direction_order[i],
.uv = (uv_position + voxel_uv_order[v]) / glm::vec2(texture_atlas->size_x, texture_atlas->size_y),
};
build_data.vertices.push_back(vertex);
@ -113,11 +116,4 @@ deerith::voxel_type_id_t deerith::cluster_generator_t::get_cluster_voxel(int x,
}
return 0;
glm::ivec3 coords;
coords.x = x + CLUSTER_SIZE * cluster->surface_id.x;
coords.y = y + CLUSTER_SIZE * cluster->layer;
coords.z = z + CLUSTER_SIZE * cluster->surface_id.y;
return get_voxel_id(coords);
}

View File

@ -16,7 +16,7 @@ namespace deerith
void render_cluster(glm::ivec3);
}
void deerith::clear_all_clusters()
void deerith::shutdown_environment()
{
loaded_clusters.clear();
}
@ -38,10 +38,22 @@ void deerith::flush_cluster_to_gpu()
cluster_workers.clear();
}
void deerith::render_clusters(glm::ivec3 position, int rad)
void deerith::render_clusters(glm::ivec3 position, int rad, const camera_t &camera)
{
texture_t *voxel_texture = get_voxel_texture();
get_voxel_shader()->use();
get_voxel_shader()->set_vec4("u_color", glm::vec4(1, 0.4f, 0.6f, 1));
set_camera_to_shader(camera, get_voxel_shader());
if (voxel_texture)
{
voxel_texture->bind(0);
get_voxel_shader()->set_int("u_texture", 0);
}
// Radial outward
for (int r = 0; r <= rad; r++)
for (int r = 0; r < rad; r++)
{
for (int x = -r; x <= r; x++)
{
@ -56,7 +68,6 @@ void deerith::render_clusters(glm::ivec3 position, int rad)
}
glm::ivec3 cluster_position = position + glm::ivec3(x, y, z);
render_cluster(cluster_position);
}
}
@ -76,10 +87,8 @@ void deerith::render_cluster(glm::ivec3 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);
glm::vec3 scale = glm::vec3(1, 1, 1);
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());
set_transform_to_shader(position, rotation, scale, get_voxel_shader());
cluster_mesh->draw();
}

View File

@ -19,6 +19,7 @@ void deerith::setup_base_protocols()
router_add_packet_processor<packet_destroy_entity_t>();
router_add_packet_processor<packet_voxel_data_definition_t>();
router_add_packet_processor<packet_cluster_data_t>();
router_add_packet_processor<packet_voxel_texture_atlas_t>();
}
template <>
@ -103,3 +104,10 @@ void deerith::process_packet(deerith::packet_cluster_data_t &packet, client_t *c
generate_cluster(cluster);
}
template <>
void deerith::process_packet(deerith::packet_voxel_texture_atlas_t &packet, client_t *client)
{
packet.texture_atlas->save_atlas("client_generated/voxel_texture_atlas.png");
set_voxel_texture_atlas(std::move(packet.texture_atlas));
}

View File

@ -55,5 +55,5 @@ void deerith::render_world()
pos = get_nearest_cluster(sync_coords.position);
}
render_clusters(pos, 10);
render_clusters(pos, 6, camera);
}

View File

@ -0,0 +1,53 @@
#include <deerith/client/world.h>
#include <deerith/client/internals/world.h>
#include <deerith/client/world.h>
#include <memory>
namespace deerith
{
std::unique_ptr<shader_t> voxel_shader;
std::unique_ptr<texture_t> voxel_texture;
}
deerith::shader_t *deerith::get_voxel_shader()
{
return voxel_shader.get();
}
deerith::texture_t *deerith::get_voxel_texture()
{
if (voxel_texture == nullptr)
{
generate_voxel_texture();
}
return voxel_texture.get();
}
void deerith::generate_voxel_texture()
{
texture_atlas_t *texture_atlas = get_voxel_texture_atlas();
if (texture_atlas == nullptr)
{
return;
}
voxel_texture = std::make_unique<texture_t>(
texture_atlas->__texture_data.get(),
texture_atlas->size_x * texture_atlas->unit_size,
texture_atlas->size_y * texture_atlas->unit_size,
texture_atlas_t::channel_count,
4);
}
void deerith::init_voxel_shader()
{
voxel_shader = std::make_unique<shader_t>(
"shaders/voxel.vert.glsl",
"shaders/voxel.frag.glsl");
}
void deerith::shutdown_world_variables()
{
voxel_shader.reset();
}

File diff suppressed because it is too large Load Diff

View File

@ -3,9 +3,11 @@
#include <deerith/world/voxels.h>
#include <deerith/world/environment.h>
#include <deerith/network/serialization_ext.h>
#include <cereal/types/vector.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/array.hpp>
#include <cereal/types/unordered_map.hpp>
#include <memory>
@ -29,11 +31,32 @@ namespace deerith
}
};
struct packet_cluster_data_t
struct packet_voxel_texture_atlas_t
{
static constexpr uint16_t packet_id = 1002;
static constexpr bool reliable = true;
std::unique_ptr<texture_atlas_t> texture_atlas;
template <typename Archive>
void save(Archive &archive) const
{
archive(*texture_atlas);
}
template <typename Archive>
void load(Archive &archive)
{
texture_atlas = std::make_unique<texture_atlas_t>();
archive(*texture_atlas);
}
};
struct packet_cluster_data_t
{
static constexpr uint16_t packet_id = 1003;
static constexpr bool reliable = true;
int layer;
glm::ivec2 surface_id;

View File

@ -40,6 +40,7 @@ namespace deerith
const voxel_type_t &get_voxel(glm::ivec3 coordinates);
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);

View File

@ -19,24 +19,66 @@ namespace deerith
path_t texture_location;
};
struct texture_builder_t
struct atlas_builder_t
{
int unit_size = 32;
std::vector<texture_builder_entry_t> entries;
};
struct texture_atlas_t
{
texture_atlas_t(const texture_builder_t &);
static constexpr int channel_count = 4;
int size_x;
int size_y;
int unit_size;
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);
};
void copy_image(const uint8_t *data, int x_pos, int y_pos, int width, int height);
void save_atlas(const path_t &location);
glm::ivec2 get_texture_position(const std::string &);
template <typename Archive>
void serialize(Archive &archive)
{
archive(unit_size);
archive(size_x);
archive(size_y);
archive(texture_name_id_map);
int data_size = unit_size * unit_size * size_x * size_y * texture_atlas_t::channel_count;
if constexpr (Archive::is_loading::value)
{
__texture_data = std::make_unique<uint8_t[]>(data_size);
}
for (int i = 0; i < data_size; i++)
{
archive(__texture_data.get()[i]);
}
}
texture_atlas_t() = default;
texture_atlas_t(const texture_atlas_t &other)
{
size_x = other.size_x;
size_y = other.size_y;
unit_size = other.unit_size;
texture_name_id_map = other.texture_name_id_map;
int data_size = unit_size * unit_size * size_x * size_y * channel_count;
__texture_data = std::make_unique<uint8_t[]>(data_size);
std::copy(other.__texture_data.get(), other.__texture_data.get() + data_size, __texture_data.get());
}
};
std::unique_ptr<texture_atlas_t> generate_texture_atlas(const atlas_builder_t &builder);
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <deerith/engine.h>
#include <deerith/world/texture.h>
#include <string>
#include <vector>
@ -9,6 +10,13 @@ namespace deerith
using voxel_type_id_t = uint16_t;
using voxel_material_id_t = uint16_t;
constexpr int direction_left = 0;
constexpr int direction_right = 1;
constexpr int direction_down = 2;
constexpr int direction_up = 3;
constexpr int direction_front = 4;
constexpr int direction_back = 5;
enum class voxel_material_type_t : int
{
AIR = 0,
@ -19,6 +27,7 @@ namespace deerith
{
// universal identifies
std::string id;
glm::ivec2 face_texture_id[6] = {};
voxel_material_type_t material_type = voxel_material_type_t::AIR;
template <typename Archive>
@ -26,7 +35,16 @@ namespace deerith
{
archive(id);
archive(material_type);
archive(face_texture_id[0]);
archive(face_texture_id[1]);
archive(face_texture_id[2]);
archive(face_texture_id[3]);
archive(face_texture_id[4]);
archive(face_texture_id[5]);
}
void set_same_face_texture(glm::ivec2);
};
struct voxel_type_t
@ -47,6 +65,10 @@ namespace deerith
}
};
void set_voxel_texture_atlas(const atlas_builder_t &builder);
void set_voxel_texture_atlas(std::unique_ptr<texture_atlas_t> texture_atlas);
texture_atlas_t *get_voxel_texture_atlas();
void set_voxel_materials(const std::vector<voxel_material_t> &mats);
voxel_material_id_t register_voxel_material(const voxel_material_t &type);
voxel_material_id_t get_voxel_material_id(const std::string &name);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb/stb_image_write.h>

View File

@ -19,8 +19,6 @@ namespace deerith
glm::ivec3 get_internal_voxel_coords(glm::ivec3 coords);
glm::ivec3 get_internal_voxel_coords(glm::ivec2 coords, int height = 0);
surface_t *get_surface(glm::ivec2);
surface_t *get_create_surface(glm::ivec2);
}
deerith::voxel_cluster_t *deerith::surface_t::get_cluster(int layer)

View File

@ -1,18 +1,131 @@
#include <deerith/world/texture.h>
#include <stb/stb_image.h>
#include <stb/stb_image_write.h>
#include <vector>
#include <algorithm>
#include <math.h>
#include <functional>
#include <filesystem>
namespace deerith
{
struct temp_image_data_t
{
std::string id;
int width;
int height;
int channels;
uint8_t *data;
};
}
uint8_t *deerith::texture_atlas_t::get_pixel(int x, int y)
{
if (x < 0 || y < 0 || x >= size_x || y >= size_y)
if (x < 0 || y < 0 || x >= size_x * unit_size || y >= size_y * unit_size)
return nullptr;
return &__texture_data[(y * size_x + x) * 4];
return &__texture_data[(y * size_x * unit_size + x) * channel_count];
}
deerith::texture_atlas_t::texture_atlas_t(const texture_builder_t &)
glm::ivec2 deerith::texture_atlas_t::get_texture_position(const std::string &str)
{
if (!texture_name_id_map.contains(str))
{
deerith_error("get_texture_position could not find {}", str.c_str());
return glm::ivec2(0, 0);
}
return texture_name_id_map[str];
}
std::unique_ptr<deerith::texture_atlas_t> deerith::generate_texture_atlas(const atlas_builder_t &builder)
{
stbi_set_flip_vertically_on_load(true);
std::unique_ptr<texture_atlas_t> texture_atlas = std::make_unique<texture_atlas_t>();
std::vector<temp_image_data_t> temp_data;
int total_area = 1;
for (const texture_builder_entry_t &entry : builder.entries)
{
int width;
int height;
int channels;
uint8_t *data = stbi_load(entry.texture_location.generic_string().c_str(), &width, &height, &channels, texture_atlas_t::channel_count);
if (data == nullptr)
{
deerith_error("failed to find {} while processing image {}", entry.texture_location.generic_string().c_str(), entry.id.c_str());
continue;
}
total_area += 1;
temp_data.push_back(
temp_image_data_t{
.id = entry.id,
.width = width,
.height = height,
.channels = channels,
.data = data,
});
}
int atlas_map_width = static_cast<int>(std::ceilf(std::sqrtf(total_area)));
texture_atlas->unit_size = builder.unit_size;
texture_atlas->size_x = atlas_map_width;
texture_atlas->size_y = atlas_map_width;
texture_atlas->__texture_data = std::make_unique<uint8_t[]>(atlas_map_width * atlas_map_width * texture_atlas_t::channel_count * builder.unit_size * builder.unit_size);
int x_pos = 0;
int y_pos = 0;
for (const temp_image_data_t &temp_image : temp_data)
{
int max_x_size = std::min(builder.unit_size, temp_image.width);
int max_y_size = std::min(builder.unit_size, temp_image.height);
texture_atlas->texture_name_id_map[temp_image.id] = glm::ivec2(x_pos, y_pos);
texture_atlas->copy_image(temp_image.data, x_pos * builder.unit_size, y_pos * builder.unit_size, max_x_size, max_y_size);
stbi_image_free(temp_image.data);
x_pos++;
if (x_pos >= atlas_map_width)
{
x_pos = 0;
y_pos++;
}
}
return texture_atlas;
}
void deerith::texture_atlas_t::copy_image(const uint8_t *data, int x_pos, int y_pos, int width, int height)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
uint8_t *pixel = get_pixel(x + x_pos, y + y_pos);
const uint8_t *data_pixel = &data[(x + y * width) * channel_count];
pixel[0] = data_pixel[0];
pixel[1] = data_pixel[1];
pixel[2] = data_pixel[2];
pixel[3] = data_pixel[3];
}
}
}
void deerith::texture_atlas_t::save_atlas(const path_t &location)
{
stbi_flip_vertically_on_write(true);
std::filesystem::create_directories(location.parent_path());
int result = stbi_write_png(location.generic_string().c_str(), size_x * unit_size, size_y * unit_size, channel_count, __texture_data.get(), size_x * unit_size * channel_count);
if (!result)
{
deerith_error("failed to save atlas at {}", location.generic_string().c_str());
}
}

View File

@ -2,6 +2,7 @@
#include <vector>
#include <unordered_map>
#include <utility>
namespace deerith
{
@ -10,6 +11,8 @@ namespace deerith
std::vector<voxel_material_t> voxel_material_array;
std::unordered_map<std::string, voxel_material_id_t> voxel_material_name_id;
std::unique_ptr<texture_atlas_t> voxel_texture_atlas;
}
deerith::voxel_type_id_t deerith::register_voxel_type(const voxel_type_t &type)
@ -63,6 +66,21 @@ const std::vector<deerith::voxel_type_t> &deerith::get_voxel_type_vector()
return voxel_type_array;
}
void deerith::set_voxel_texture_atlas(const atlas_builder_t &builder)
{
voxel_texture_atlas = generate_texture_atlas(builder);
}
void deerith::set_voxel_texture_atlas(std::unique_ptr<texture_atlas_t> texture_atlas)
{
voxel_texture_atlas = std::move(texture_atlas);
}
deerith::texture_atlas_t *deerith::get_voxel_texture_atlas()
{
return voxel_texture_atlas.get();
}
void deerith::set_voxel_materials(const std::vector<deerith::voxel_material_t> &mats)
{
voxel_material_array = mats;
@ -86,3 +104,13 @@ void deerith::set_voxel_types(const std::vector<deerith::voxel_type_t> &types)
voxel_type_name_id[type.id] = id;
}
}
void deerith::voxel_material_t::set_same_face_texture(glm::ivec2 pos)
{
face_texture_id[0] = pos;
face_texture_id[1] = pos;
face_texture_id[2] = pos;
face_texture_id[3] = pos;
face_texture_id[4] = pos;
face_texture_id[5] = pos;
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <deerith/network/client.h>
#include <deerith/world/components.h>
#include <deerith/server/runtime_settings.h>
namespace deerith
{
@ -21,4 +22,6 @@ namespace deerith
void send_entity_data();
void send_voxel_data_to_client(client_t *client);
void send_clients_environment_data();
extern world_settings_t world_settings;
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <deerith/world/environment.h>
#include <functional>
namespace deerith
{
struct world_settings_t
{
int port = 8080;
std::function<void(atlas_builder_t &)> define_voxel_texture_atlas_function;
std::function<void(texture_atlas_t *)> define_voxels_materials_function;
std::function<void()> define_voxels_types_function;
std::function<void(voxel_cluster_t *)> generate_voxel_cluster;
};
}

View File

@ -1,9 +1,10 @@
#pragma once
#include <deerith/world/world_core.h>
#include <deerith/server/runtime_settings.h>
namespace deerith
{
void run_world(int port);
void run_world(const world_settings_t &);
void shutdown_world();
bool is_world_running();

View File

@ -0,0 +1,29 @@
#include <deerith/engine.h>
#include <deerith/server/world.h>
namespace deerith
{
extern world_settings_t world_settings;
void init_voxel_data();
}
void deerith::init_world()
{
init_voxel_data();
}
void deerith::init_voxel_data()
{
{
atlas_builder_t atlas_builder;
world_settings.define_voxel_texture_atlas_function(atlas_builder);
set_voxel_texture_atlas(atlas_builder);
}
texture_atlas_t *voxel_texture_atlas = get_voxel_texture_atlas();
voxel_texture_atlas->save_atlas("generated/voxel_texture_atlas.png");
world_settings.define_voxels_materials_function(voxel_texture_atlas);
world_settings.define_voxels_types_function();
}

View File

@ -25,6 +25,13 @@ void deerith::send_voxel_data_to_client(client_t *client)
voxel_data_definition.voxel_types = get_voxel_type_vector();
router_send_packet(voxel_data_definition, client);
texture_atlas_t *texture_atlas = get_voxel_texture_atlas();
packet_voxel_texture_atlas_t voxel_texture_atlas;
voxel_texture_atlas.texture_atlas = std::make_unique<texture_atlas_t>(*texture_atlas);
router_send_packet(voxel_texture_atlas, client);
}
void deerith::send_clients_environment_data()
@ -57,10 +64,8 @@ void deerith::check_client_surface_knowledge(client_t *client, component_client_
for (int z = -SURFACE_RADIUS; z <= SURFACE_RADIUS; z++)
{
glm::ivec2 surface_id = {surface_x + x, surface_z + z};
surface_t *surface = get_surface(surface_id);
surface_t *surface = get_create_surface(surface_id);
if (surface != nullptr)
{
if (check_client_cluster_knowledge(client, knowledge, surface))
{
return;
@ -68,13 +73,18 @@ void deerith::check_client_surface_knowledge(client_t *client, component_client_
}
}
}
}
bool deerith::check_client_cluster_knowledge(client_t *client, component_client_environment_knowledge_t &knowledge, surface_t *surface)
{
for (int i = 0; i < surface->voxel_clusters.size(); i++)
for (int layer = -3; layer < 4; layer++)
{
voxel_cluster_t *cluster = surface->voxel_clusters[i].get();
voxel_cluster_t *cluster = surface->get_cluster(layer);
if (cluster == nullptr)
{
cluster = surface->get_create_cluster(layer);
world_settings.generate_voxel_cluster(cluster);
}
int32_t cluster_last_update = cluster->last_update_tick_id;
int32_t actual_cluster_kknowledge = -1;

View File

@ -7,17 +7,23 @@
namespace deerith
{
void server_loop();
void init_world();
world_settings_t world_settings;
}
void deerith::run_world(int port)
void deerith::run_world(const world_settings_t &__world_settings)
{
if (!init_server(port))
world_settings = __world_settings;
if (!init_server(world_settings.port))
{
deerith_error("could not init server");
return;
}
deerith_trace("server init on port {}", port);
init_world();
deerith_trace("server init on port {}", world_settings.port);
while (true)
{
server_loop();

View File

@ -18,6 +18,13 @@ target_link_libraries(Sandbox
DeerithServer
)
add_custom_target(DeerithSandboxTextures ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_CURRENT_SOURCE_DIR}/textures"
"${CMAKE_CURRENT_BINARY_DIR}/textures"
COMMENT "Copying DeerithClient shaders"
)
target_compile_definitions(Sandbox PRIVATE
$<$<CONFIG:Debug>:DEBUG>
)

View File

@ -1,8 +1,11 @@
#pragma once
#include <deerith/world/environment.h>
namespace sandbox
{
void define_voxel_materials();
void define_voxel_texture_atlas(deerith::atlas_builder_t &);
void define_voxels_materials(deerith::texture_atlas_t *);
void define_voxels_types();
void generate_voxel_cluster(deerith::voxel_cluster_t *);
}

View File

@ -1,6 +0,0 @@
#pragma once
namespace sandbox
{
void build_world();
}

View File

@ -1,120 +1,44 @@
#include "world.h"
#include "voxels.h"
#include <FastNoise/FastNoiseLite.h>
#include <deerith/world/environment.h>
namespace deerith
{
}
void sandbox::generate_voxel_cluster(deerith::voxel_cluster_t *cluster)
{
FastNoiseLite noise;
noise.SetNoiseType(FastNoiseLite::NoiseType_Perlin);
void sandbox::build_world()
for (int x = 0; x < deerith::CLUSTER_SIZE; x++)
{
for (int z = 0; z < deerith::CLUSTER_SIZE; z++)
{
float world_x = static_cast<float>(cluster->surface_id.x * deerith::CLUSTER_SIZE + x) * deerith::VOXEL_SIZE;
float world_z = static_cast<float>(cluster->surface_id.y * deerith::CLUSTER_SIZE + z) * deerith::VOXEL_SIZE;
constexpr int SIZE = 32;
constexpr int WALL_HEIGHT = 5;
constexpr int TOWER_HEIGHT = 12;
float noise_height_1 = noise.GetNoise(world_x, world_z);
float noise_height_2 = noise.GetNoise(world_x * 5 + 101, world_z * 5 + 221);
float noise_height_3 = noise.GetNoise(world_x * 8 - 1030, world_z * 8 - 540);
// Foundation
for (int x = 0; x < SIZE; ++x)
{
for (int z = 0; z < SIZE; ++z)
{
deerith::set_voxel(1, glm::vec3(x, 0, z));
}
}
// Terrain height in voxel units
int terrain_height = static_cast<int>(noise_height_1 * 240.0f * deerith::VOXEL_SIZE);
terrain_height += static_cast<int>(noise_height_2 * 20.0f * deerith::VOXEL_SIZE);
terrain_height += static_cast<int>(noise_height_3 * 5.0f * deerith::VOXEL_SIZE);
// 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;
// Cluster's bottom position in voxel units
int cluster_bottom = cluster->layer * deerith::CLUSTER_SIZE;
deerith::set_voxel(1, glm::vec3(x, y, 0));
deerith::set_voxel(1, glm::vec3(x, y, SIZE - 1));
}
}
// Height relative to this cluster
int relative_height = terrain_height - cluster_bottom;
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));
}
}
relative_height = std::clamp(relative_height, 0, deerith::CLUSTER_SIZE);
// Corner towers
for (int tx : {0, SIZE - 1})
for (int y = 0; y < relative_height; y++)
{
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));
cluster->__data[x][y][z] = 1;
}
}
}
}
// 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));
}
}
}

View File

@ -1,7 +1,34 @@
#include "voxels.h"
#include <deerith/world/voxels.h>
#include <deerith/world/texture.h>
void sandbox::define_voxel_materials()
#include <memory>
void define_voxels_materials(deerith::texture_atlas_t *);
void define_voxels_types();
void sandbox::define_voxel_texture_atlas(deerith::atlas_builder_t &builder)
{
builder.unit_size = 64;
{
deerith::texture_builder_entry_t entry;
entry.id = "snow";
entry.texture_location = "textures/snow.png";
builder.entries.push_back(entry);
}
{
deerith::texture_builder_entry_t entry;
entry.id = "grass_block_snow";
entry.texture_location = "textures/grass_block_snow.png";
builder.entries.push_back(entry);
}
}
void sandbox::define_voxels_materials(deerith::texture_atlas_t *voxel_atlas)
{
// air
{
@ -12,13 +39,14 @@ void sandbox::define_voxel_materials()
deerith::register_voxel_material(voxel_material);
}
// rock
// snow
{
deerith::voxel_material_t voxel_material;
voxel_material.id = "rock";
voxel_material.id = "snow";
voxel_material.material_type = deerith::voxel_material_type_t::SOLID;
// textures...
voxel_material.set_same_face_texture(voxel_atlas->get_texture_position("grass_block_snow"));
voxel_material.face_texture_id[deerith::direction_up] = voxel_atlas->get_texture_position("snow");
deerith::register_voxel_material(voxel_material);
}
@ -40,9 +68,9 @@ void sandbox::define_voxels_types()
{
deerith::voxel_type_t voxel_type;
voxel_type.is_solid = true;
voxel_type.id = "rock";
voxel_type.id = "snow";
voxel_type.material_id = deerith::get_voxel_material_id("rock");
voxel_type.material_id = deerith::get_voxel_material_id("snow");
deerith::register_voxel_type(voxel_type);
}
}

View File

@ -5,23 +5,23 @@
#include <args/argh.h>
#include "voxels.h"
#include "world.h"
int main(int argc, const char **argv)
{
deerith::init_engine();
auto cmdl = argh::parser(argc, argv);
int port = 8080;
cmdl("port", 8080) >> port;
deerith::world_settings_t world_settings;
cmdl("port", 8080) >> world_settings.port;
sandbox::define_voxel_materials();
sandbox::define_voxels_types();
world_settings.define_voxel_texture_atlas_function = sandbox::define_voxel_texture_atlas;
world_settings.define_voxels_materials_function = sandbox::define_voxels_materials;
world_settings.define_voxels_types_function = sandbox::define_voxels_types;
sandbox::build_world();
world_settings.generate_voxel_cluster = sandbox::generate_voxel_cluster;
#ifdef DEBUG
if (cmdl[{"-s", "--single"}] && !deerith::execute_client("../deerith_client/DeerithClient", port))
if (cmdl[{"-s", "--single"}] && !deerith::execute_client("../deerith_client/DeerithClient", world_settings.port))
{
deerith_error("could not start server");
deerith::shutdown_engine();
@ -29,7 +29,7 @@ int main(int argc, const char **argv)
}
#endif
deerith::run_world(8080);
deerith::run_world(world_settings);
deerith::shutdown_executing_servers();
deerith::shutdown_engine();