mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-06-18 00:27:02 +08:00
Compare commits
1 Commits
main
...
623f991fcf
| Author | SHA1 | Date | |
|---|---|---|---|
| 623f991fcf |
@@ -58,21 +58,6 @@ if (WIN32)
|
|||||||
if(TARGET freetype)
|
if(TARGET freetype)
|
||||||
add_library(Freetype::Freetype ALIAS freetype)
|
add_library(Freetype::Freetype ALIAS freetype)
|
||||||
endif()
|
endif()
|
||||||
set(_BUILD_SHARED_LIBS_SAVED ${BUILD_SHARED_LIBS})
|
|
||||||
set(BUILD_SHARED_LIBS ON)
|
|
||||||
|
|
||||||
FetchContent_Declare(
|
|
||||||
onetbb
|
|
||||||
GIT_REPOSITORY https://github.com/uxlfoundation/oneTBB.git
|
|
||||||
GIT_TAG v2023.0.0
|
|
||||||
)
|
|
||||||
set(BUILD_TESTING OFF CACHE BOOL "Build tests" FORCE)
|
|
||||||
set(TBB_TEST OFF CACHE BOOL "Build TBB tests" FORCE)
|
|
||||||
FetchContent_MakeAvailable(onetbb)
|
|
||||||
|
|
||||||
set(BUILD_SHARED_LIBS ${_BUILD_SHARED_LIBS_SAVED})
|
|
||||||
unset(_BUILD_SHARED_LIBS_SAVED)
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
@@ -98,6 +83,7 @@ FetchContent_MakeAvailable(tomlplusplus)
|
|||||||
|
|
||||||
add_subdirectory(third_party/imgui)
|
add_subdirectory(third_party/imgui)
|
||||||
|
|
||||||
|
|
||||||
set(INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
|
set(INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME}
|
add_executable(${PROJECT_NAME}
|
||||||
@@ -178,11 +164,10 @@ target_link_libraries(${PROJECT_NAME}
|
|||||||
Freetype::Freetype
|
Freetype::Freetype
|
||||||
tomlplusplus::tomlplusplus
|
tomlplusplus::tomlplusplus
|
||||||
imgui
|
imgui
|
||||||
tbb
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
# target_link_libraries(${PROJECT_NAME} PRIVATE tbb)
|
target_link_libraries(${PROJECT_NAME} PRIVATE tbb)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNIX AND NOT APPLE)
|
if (UNIX AND NOT APPLE)
|
||||||
@@ -202,19 +187,3 @@ if (UNIX AND NOT APPLE)
|
|||||||
|
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE ${EGL_CFLAGS_OTHER} ${Wayland_CFLAGS_OTHER})
|
target_compile_options(${PROJECT_NAME} PRIVATE ${EGL_CFLAGS_OTHER} ${Wayland_CFLAGS_OTHER})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
foreach(TBB_LIB IN ITEMS tbb tbbmalloc tbbmalloc_proxy)
|
|
||||||
if(TARGET ${TBB_LIB})
|
|
||||||
add_custom_command(
|
|
||||||
TARGET ${PROJECT_NAME} POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
||||||
$<TARGET_FILE:${TBB_LIB}>
|
|
||||||
$<TARGET_FILE_DIR:${PROJECT_NAME}>
|
|
||||||
COMMENT "Copying ${TBB_LIB}.dll"
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
message(STATUS "Target ${TBB_LIB} not found, skipping copy")
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
@@ -5,6 +5,5 @@ is_discard = true
|
|||||||
is_gas = true
|
is_gas = true
|
||||||
is_liquid = false
|
is_liquid = false
|
||||||
is_passable = true
|
is_passable = true
|
||||||
is_transitional = false
|
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'air'
|
name = 'air'
|
||||||
@@ -5,6 +5,5 @@ is_discard = false
|
|||||||
is_gas = false
|
is_gas = false
|
||||||
is_liquid = false
|
is_liquid = false
|
||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = true
|
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'dirt'
|
name = 'dirt'
|
||||||
@@ -5,6 +5,5 @@ is_discard = true
|
|||||||
is_gas = false
|
is_gas = false
|
||||||
is_liquid = false
|
is_liquid = false
|
||||||
is_passable = true
|
is_passable = true
|
||||||
is_transitional = false
|
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'grass'
|
name = 'grass'
|
||||||
@@ -5,6 +5,5 @@ is_discard = false
|
|||||||
is_gas = false
|
is_gas = false
|
||||||
is_liquid = false
|
is_liquid = false
|
||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = true
|
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'grass_block'
|
name = 'grass_block'
|
||||||
@@ -5,6 +5,5 @@ is_discard = true
|
|||||||
is_gas = false
|
is_gas = false
|
||||||
is_liquid = false
|
is_liquid = false
|
||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = false
|
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'leaf'
|
name = 'leaf'
|
||||||
@@ -5,6 +5,5 @@ is_discard = false
|
|||||||
is_gas = false
|
is_gas = false
|
||||||
is_liquid = false
|
is_liquid = false
|
||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = false
|
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'log'
|
name = 'log'
|
||||||
@@ -5,6 +5,5 @@ is_discard = false
|
|||||||
is_gas = false
|
is_gas = false
|
||||||
is_liquid = false
|
is_liquid = false
|
||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = true
|
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'sand'
|
name = 'sand'
|
||||||
@@ -5,6 +5,5 @@ is_discard = false
|
|||||||
is_gas = false
|
is_gas = false
|
||||||
is_liquid = false
|
is_liquid = false
|
||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = true
|
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'snowy_grass_block'
|
name = 'snowy_grass_block'
|
||||||
@@ -5,6 +5,5 @@ is_discard = false
|
|||||||
is_gas = false
|
is_gas = false
|
||||||
is_liquid = false
|
is_liquid = false
|
||||||
is_passable = false
|
is_passable = false
|
||||||
is_transitional = true
|
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'stone'
|
name = 'stone'
|
||||||
@@ -7,4 +7,3 @@ is_cross_plane = false
|
|||||||
is_transparent = false
|
is_transparent = false
|
||||||
is_discard = false
|
is_discard = false
|
||||||
is_blend = false
|
is_blend = false
|
||||||
is_transitional = false
|
|
||||||
|
|||||||
@@ -5,6 +5,5 @@ is_discard = false
|
|||||||
is_gas = false
|
is_gas = false
|
||||||
is_liquid = true
|
is_liquid = true
|
||||||
is_passable = true
|
is_passable = true
|
||||||
is_transitional = false
|
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'water'
|
name = 'water'
|
||||||
@@ -6,7 +6,7 @@ namespace Cubed {
|
|||||||
|
|
||||||
constexpr int WORLD_SIZE_Y = 256;
|
constexpr int WORLD_SIZE_Y = 256;
|
||||||
constexpr int CHUNK_SIZE = 16;
|
constexpr int CHUNK_SIZE = 16;
|
||||||
constexpr int SEA_LEVEL = 63;
|
constexpr int SEA_LEVEL = 64;
|
||||||
|
|
||||||
constexpr int MAX_UI_NUM = 1;
|
constexpr int MAX_UI_NUM = 1;
|
||||||
constexpr int MAX_BLOCK_STATUS = 1;
|
constexpr int MAX_BLOCK_STATUS = 1;
|
||||||
|
|||||||
@@ -50,14 +50,13 @@ struct BlockData {
|
|||||||
|
|
||||||
bool is_discard = false;
|
bool is_discard = false;
|
||||||
bool is_blend = false;
|
bool is_blend = false;
|
||||||
bool is_transitional = false;
|
|
||||||
BlockData(BlockType b_id, std::string_view b_name, bool liquid,
|
BlockData(BlockType b_id, std::string_view b_name, bool liquid,
|
||||||
bool passable, bool cross_plane, bool transparent, bool gas,
|
bool passable, bool cross_plane, bool transparent, bool gas,
|
||||||
bool discard, bool blend, bool transitional)
|
bool discard, bool blend)
|
||||||
: name(b_name), id(b_id), is_liquid(liquid), is_gas(gas),
|
: name(b_name), id(b_id), is_liquid(liquid), is_gas(gas),
|
||||||
is_passable(passable), is_cross_plane(cross_plane),
|
is_passable(passable), is_cross_plane(cross_plane),
|
||||||
is_transparent(transparent), is_discard(discard), is_blend(blend),
|
is_transparent(transparent), is_discard(discard), is_blend(blend) {}
|
||||||
is_transitional(transitional) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlockManager {
|
class BlockManager {
|
||||||
@@ -78,7 +77,7 @@ public:
|
|||||||
|
|
||||||
static bool is_discard(BlockType id);
|
static bool is_discard(BlockType id);
|
||||||
static bool is_blend(BlockType id);
|
static bool is_blend(BlockType id);
|
||||||
static bool is_transitional(BlockType id);
|
|
||||||
static BlockType cross_plane_index(BlockType id);
|
static BlockType cross_plane_index(BlockType id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ public:
|
|||||||
virtual ChunkGenerator& get_chunk_generator() = 0;
|
virtual ChunkGenerator& get_chunk_generator() = 0;
|
||||||
virtual void build_biome() = 0;
|
virtual void build_biome() = 0;
|
||||||
virtual void build_vegetation() = 0;
|
virtual void build_vegetation() = 0;
|
||||||
void ocean_water_build();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void build_bottom();
|
void build_bottom();
|
||||||
void place_grass();
|
void place_grass();
|
||||||
|
void ocean_water_build();
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -1,14 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Cubed/gameplay/cave_path.hpp"
|
#include "Cubed/gameplay/cave_path.hpp"
|
||||||
|
|
||||||
#include <tbb/concurrent_hash_map.h>
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
class CaveCarver {
|
class CaveCarver {
|
||||||
using CaveHashMap = tbb::concurrent_hash_map<unsigned, CavePath>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CaveCarver();
|
CaveCarver();
|
||||||
CaveHashMap& paths();
|
std::unordered_map<unsigned, CavePath>& paths();
|
||||||
void init(unsigned world_seed);
|
void init(unsigned world_seed);
|
||||||
void reload(unsigned world_seed);
|
void reload(unsigned world_seed);
|
||||||
void add_path(const glm::vec3& pos, unsigned chunk_seed);
|
void add_path(const glm::vec3& pos, unsigned chunk_seed);
|
||||||
@@ -19,8 +15,9 @@ public:
|
|||||||
float& cave_probability();
|
float& cave_probability();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CaveHashMap m_paths;
|
std::unordered_map<unsigned, CavePath> m_paths;
|
||||||
unsigned m_seed = 0;
|
unsigned m_seed = 0;
|
||||||
|
int m_sum = 0;
|
||||||
Random m_random;
|
Random m_random;
|
||||||
float m_cave_probability = 0.035f;
|
float m_cave_probability = 0.035f;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,16 +5,12 @@
|
|||||||
#include "Cubed/tools/cubed_random.hpp"
|
#include "Cubed/tools/cubed_random.hpp"
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <tbb/concurrent_hash_map.h>
|
#include <unordered_set>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
class CavePath {
|
class CavePath {
|
||||||
using ChunkPosSet =
|
|
||||||
tbb::concurrent_hash_map<ChunkPos, bool, ChunkPos::TBBHash>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CavePath(unsigned int chunk_seed, unsigned world_seed,
|
CavePath(unsigned int world_seed, int path_id, const glm::vec3& start_pos);
|
||||||
const glm::vec3& start_pos);
|
|
||||||
const std::vector<PathPoint>& points() const;
|
const std::vector<PathPoint>& points() const;
|
||||||
void clear_chunk(const ChunkPos& pos);
|
void clear_chunk(const ChunkPos& pos);
|
||||||
bool is_finished() const;
|
bool is_finished() const;
|
||||||
@@ -38,6 +34,7 @@ private:
|
|||||||
static inline int m_step_min = 10;
|
static inline int m_step_min = 10;
|
||||||
static inline int m_step_max = 400;
|
static inline int m_step_max = 400;
|
||||||
|
|
||||||
|
int m_path_id = 0;
|
||||||
unsigned int m_seed = 0;
|
unsigned int m_seed = 0;
|
||||||
float m_yaw = 0.0f;
|
float m_yaw = 0.0f;
|
||||||
float m_pitch = 0.0f;
|
float m_pitch = 0.0f;
|
||||||
@@ -47,7 +44,7 @@ private:
|
|||||||
Random m_random;
|
Random m_random;
|
||||||
|
|
||||||
std::vector<PathPoint> m_points;
|
std::vector<PathPoint> m_points;
|
||||||
ChunkPosSet m_pending_chunks;
|
std::unordered_set<ChunkPos, ChunkPos::Hash> m_pending_chunks;
|
||||||
void collect_path_points();
|
void collect_path_points();
|
||||||
void precompute_chunk_coverage();
|
void precompute_chunk_coverage();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ class World;
|
|||||||
// if want to use, do init_chunk(), gen_vertex_data() and
|
// if want to use, do init_chunk(), gen_vertex_data() and
|
||||||
class Chunk {
|
class Chunk {
|
||||||
private:
|
private:
|
||||||
using OptionalBlockVectorArray =
|
|
||||||
std::array<std::optional<std::vector<BlockType>>, 4>;
|
|
||||||
static constexpr int SIZE_X = CHUNK_SIZE;
|
static constexpr int SIZE_X = CHUNK_SIZE;
|
||||||
static constexpr int SIZE_Y = WORLD_SIZE_Y;
|
static constexpr int SIZE_Y = WORLD_SIZE_Y;
|
||||||
static constexpr int SIZE_Z = CHUNK_SIZE;
|
static constexpr int SIZE_Z = CHUNK_SIZE;
|
||||||
@@ -48,7 +46,8 @@ private:
|
|||||||
BiomeConditions m_conditions;
|
BiomeConditions m_conditions;
|
||||||
|
|
||||||
void clear_dirty();
|
void clear_dirty();
|
||||||
void gen_vertices(const OptionalBlockVectorArray& neighbor_block);
|
void gen_vertices(
|
||||||
|
const std::array<const std::vector<BlockType>*, 4>& neighbor_block);
|
||||||
void gen_cross_plane_vertices(int world_x, int world_y, int world_z,
|
void gen_cross_plane_vertices(int world_x, int world_y, int world_z,
|
||||||
BlockType id);
|
BlockType id);
|
||||||
|
|
||||||
@@ -98,7 +97,8 @@ public:
|
|||||||
// 1 : (-1, 0)
|
// 1 : (-1, 0)
|
||||||
// 2 : (0, 1)
|
// 2 : (0, 1)
|
||||||
// 3 : (0, -1)
|
// 3 : (0, -1)
|
||||||
void gen_vertex_data(const OptionalBlockVectorArray& neighbor_block);
|
void gen_vertex_data(
|
||||||
|
const std::array<const std::vector<BlockType>*, 4>& neighbor_block);
|
||||||
void upload_to_gpu();
|
void upload_to_gpu();
|
||||||
|
|
||||||
GLuint get_normal_vao() const;
|
GLuint get_normal_vao() const;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include "Cubed/gameplay/biome.hpp"
|
#include "Cubed/gameplay/biome.hpp"
|
||||||
#include "Cubed/gameplay/block.hpp"
|
#include "Cubed/gameplay/block.hpp"
|
||||||
#include "Cubed/gameplay/builders/biome_builder.hpp"
|
#include "Cubed/gameplay/builders/biome_builder.hpp"
|
||||||
#include "Cubed/gameplay/path_point.hpp"
|
|
||||||
#include "Cubed/tools/cubed_random.hpp"
|
#include "Cubed/tools/cubed_random.hpp"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -46,7 +45,6 @@ public:
|
|||||||
Chunk& chunk();
|
Chunk& chunk();
|
||||||
Random& random();
|
Random& random();
|
||||||
const std::array<BiomeType, 8>& neighbor_biome() const;
|
const std::array<BiomeType, 8>& neighbor_biome() const;
|
||||||
void ocean_build();
|
|
||||||
void generate_cave();
|
void generate_cave();
|
||||||
void generate_river();
|
void generate_river();
|
||||||
|
|
||||||
@@ -62,9 +60,6 @@ private:
|
|||||||
unsigned m_chunk_seed = 0;
|
unsigned m_chunk_seed = 0;
|
||||||
|
|
||||||
void make_biome_builder();
|
void make_biome_builder();
|
||||||
void
|
|
||||||
carve_worm(const std::vector<PathPoint>& points, const ChunkPos& chunk_pos,
|
|
||||||
std::function<void(int /*x*/, int /*y*/, int /*z*/)> on_hit);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -16,14 +16,7 @@ struct ChunkPos {
|
|||||||
return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
|
return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
struct TBBHash {
|
|
||||||
std::size_t hash(const ChunkPos& p) const {
|
|
||||||
return ChunkPos::Hash{}(p);
|
|
||||||
}
|
|
||||||
bool equal(const ChunkPos& a, const ChunkPos& b) const {
|
|
||||||
return a == b;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ChunkPos operator+(const ChunkPos& pos) const {
|
ChunkPos operator+(const ChunkPos& pos) const {
|
||||||
return ChunkPos{x + pos.x, z + pos.z};
|
return ChunkPos{x + pos.x, z + pos.z};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,13 @@
|
|||||||
#include "Cubed/tools/cubed_random.hpp"
|
#include "Cubed/tools/cubed_random.hpp"
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <tbb/concurrent_hash_map.h>
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
class RiverPath {
|
class RiverPath {
|
||||||
using ChunkPosSet =
|
|
||||||
tbb::concurrent_hash_map<ChunkPos, bool, ChunkPos::TBBHash>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RiverPath(unsigned int chunk_seed, unsigned world_seed,
|
RiverPath(unsigned int world_seed, int path_id, const glm::vec3& start_pos);
|
||||||
const glm::vec3& start_pos);
|
|
||||||
const std::vector<PathPoint>& points() const;
|
const std::vector<PathPoint>& points() const;
|
||||||
void clear_chunk(const ChunkPos& pos);
|
void clear_chunk(const ChunkPos& pos);
|
||||||
bool is_finished() const;
|
bool is_finished() const;
|
||||||
@@ -35,12 +32,12 @@ private:
|
|||||||
static inline float m_radius_y_max = 8.0f;
|
static inline float m_radius_y_max = 8.0f;
|
||||||
static inline float m_delta_angle_min = -3.0f;
|
static inline float m_delta_angle_min = -3.0f;
|
||||||
static inline float m_delta_angle_max = 3.0f;
|
static inline float m_delta_angle_max = 3.0f;
|
||||||
static inline int m_step_min = 200;
|
static inline int m_step_min = 150;
|
||||||
static inline int m_step_max = 400;
|
static inline int m_step_max = 400;
|
||||||
|
|
||||||
|
int m_path_id = 0;
|
||||||
unsigned int m_seed = 0;
|
unsigned int m_seed = 0;
|
||||||
float m_yaw = 0.0f;
|
float m_yaw = 0.0f;
|
||||||
float m_initial_yaw = 0.0f;
|
|
||||||
float m_pitch = 0.0f;
|
float m_pitch = 0.0f;
|
||||||
int m_step = 0;
|
int m_step = 0;
|
||||||
float m_step_len = 1.0f;
|
float m_step_len = 1.0f;
|
||||||
@@ -48,7 +45,7 @@ private:
|
|||||||
Random m_random;
|
Random m_random;
|
||||||
|
|
||||||
std::vector<PathPoint> m_points;
|
std::vector<PathPoint> m_points;
|
||||||
ChunkPosSet m_pending_chunks;
|
std::unordered_set<ChunkPos, ChunkPos::Hash> m_pending_chunks;
|
||||||
void collect_path_points();
|
void collect_path_points();
|
||||||
void precompute_chunk_coverage();
|
void precompute_chunk_coverage();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,15 +4,13 @@
|
|||||||
#include "Cubed/tools/cubed_random.hpp"
|
#include "Cubed/tools/cubed_random.hpp"
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <tbb/concurrent_hash_map.h>
|
#include <unordered_map>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
class RiverWorm {
|
class RiverWorm {
|
||||||
using RiverHashMap = tbb::concurrent_hash_map<unsigned, RiverPath>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RiverWorm();
|
RiverWorm();
|
||||||
RiverHashMap& paths();
|
std::unordered_map<unsigned, RiverPath>& paths();
|
||||||
void init(unsigned world_seed);
|
void init(unsigned world_seed);
|
||||||
void reload(unsigned world_seed);
|
void reload(unsigned world_seed);
|
||||||
void add_path(const glm::vec3& pos, unsigned chunk_seed);
|
void add_path(const glm::vec3& pos, unsigned chunk_seed);
|
||||||
@@ -23,8 +21,9 @@ public:
|
|||||||
float& river_probability();
|
float& river_probability();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RiverHashMap m_paths;
|
std::unordered_map<unsigned, RiverPath> m_paths;
|
||||||
unsigned m_seed = 0;
|
unsigned m_seed = 0;
|
||||||
|
int m_sum = 0;
|
||||||
Random m_random;
|
Random m_random;
|
||||||
float m_probability = 0.01f;
|
float m_probability = 0.01f;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,10 +31,8 @@ class Player;
|
|||||||
class TextureManager;
|
class TextureManager;
|
||||||
class World {
|
class World {
|
||||||
private:
|
private:
|
||||||
using OptionalBlockVectorArray =
|
|
||||||
std::array<std::optional<std::vector<BlockType>>, 4>;
|
|
||||||
using ChunkPtrUpdateList = std::vector<std::pair<ChunkPos, Chunk*>>;
|
using ChunkPtrUpdateList = std::vector<std::pair<ChunkPos, Chunk*>>;
|
||||||
using ChunkPairVector = std::vector<std::pair<ChunkPos, Chunk>>;
|
using ChunkUpdateList = std::vector<std::pair<ChunkPos, Chunk>>;
|
||||||
using ConstChunkMap =
|
using ConstChunkMap =
|
||||||
std::unordered_map<ChunkPos, const Chunk*, ChunkPos::Hash>;
|
std::unordered_map<ChunkPos, const Chunk*, ChunkPos::Hash>;
|
||||||
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
|
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
|
||||||
@@ -72,16 +70,14 @@ private:
|
|||||||
|
|
||||||
void gen_chunks_internal();
|
void gen_chunks_internal();
|
||||||
void sync_player_pos(glm::vec3& player_pos);
|
void sync_player_pos(glm::vec3& player_pos);
|
||||||
void
|
void compute_required_chunks(ChunkPosSet& required_chunks,
|
||||||
compute_required_chunks(ChunkPosSet& required_chunks,
|
ChunkHashMap& temp_neighbor);
|
||||||
ChunkPairVector& temp_neighbor,
|
|
||||||
std::vector<ChunkPos>& need_gen_temp_chunks_pos);
|
|
||||||
void sync_and_collect_missing_chunks(std::vector<ChunkPos>&,
|
void sync_and_collect_missing_chunks(std::vector<ChunkPos>&,
|
||||||
const ChunkPosSet&);
|
const ChunkPosSet&);
|
||||||
void
|
void
|
||||||
build_neighbor_context_for_new_chunks(ConstChunkMap& new_chunks_neighbor,
|
build_neighbor_context_for_new_chunks(ConstChunkMap& new_chunks_neighbor,
|
||||||
ChunkPtrUpdateList& affected_neighbor,
|
ChunkPtrUpdateList& affected_neighbor,
|
||||||
const ChunkPairVector& new_chunks);
|
const ChunkUpdateList& new_chunks);
|
||||||
void build_neighbor_context_for_affected_neighbors(ChunkPtrUpdateList&,
|
void build_neighbor_context_for_affected_neighbors(ChunkPtrUpdateList&,
|
||||||
ConstChunkMap&);
|
ConstChunkMap&);
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,7 @@ namespace HASH {
|
|||||||
inline std::size_t str(std::string_view value) {
|
inline std::size_t str(std::string_view value) {
|
||||||
return std::hash<std::string_view>{}(value);
|
return std::hash<std::string_view>{}(value);
|
||||||
}
|
}
|
||||||
inline uint32_t combine_32(uint32_t seed, uint32_t v) {
|
inline uint32_t mix_hash(int32_t a, int32_t b, uint32_t fixed_seed) {
|
||||||
seed ^= v + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
inline uint32_t chunk_seed_hash(int32_t a, int32_t b, uint32_t fixed_seed) {
|
|
||||||
uint32_t seed =
|
|
||||||
combine_32(combine_32(fixed_seed, (uint32_t)a), (uint32_t)b);
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
inline uint32_t chunk_seed_hash(int32_t a, int32_t b, uint32_t fixed_seed) {
|
|
||||||
uint32_t h = fixed_seed;
|
uint32_t h = fixed_seed;
|
||||||
|
|
||||||
h ^= (uint32_t)a * 0xcc9e2d51u;
|
h ^= (uint32_t)a * 0xcc9e2d51u;
|
||||||
@@ -37,8 +27,10 @@ inline uint32_t chunk_seed_hash(int32_t a, int32_t b, uint32_t fixed_seed) {
|
|||||||
|
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
*/
|
inline uint32_t combine_32(uint32_t seed, uint32_t v) {
|
||||||
|
seed ^= v + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
} // namespace HASH
|
} // namespace HASH
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -11,7 +11,7 @@ void extract_frustum_planes(const glm::mat4& mvp_matrix,
|
|||||||
float smootherstep(float edge0, float edge1, float x);
|
float smootherstep(float edge0, float edge1, float x);
|
||||||
bool is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents,
|
bool is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents,
|
||||||
const std::vector<glm::vec4>& planes);
|
const std::vector<glm::vec4>& planes);
|
||||||
float deterministic_random(int x, int z, uint64_t seed);
|
|
||||||
} // namespace Math
|
} // namespace Math
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -104,13 +104,7 @@ bool BlockManager::is_blend(BlockType id) {
|
|||||||
}
|
}
|
||||||
return m_datas[id].is_blend;
|
return m_datas[id].is_blend;
|
||||||
}
|
}
|
||||||
bool BlockManager::is_transitional(BlockType id) {
|
|
||||||
if (id >= sums()) {
|
|
||||||
Logger::error("Id {}, is Over The Max Id", id, sums() - 1);
|
|
||||||
return m_datas[0].is_transitional;
|
|
||||||
}
|
|
||||||
return m_datas[id].is_transitional;
|
|
||||||
}
|
|
||||||
void BlockManager::init() {
|
void BlockManager::init() {
|
||||||
fs::path data_path{block_data_dir};
|
fs::path data_path{block_data_dir};
|
||||||
|
|
||||||
@@ -148,10 +142,9 @@ void BlockManager::init() {
|
|||||||
auto is_gas = safe_get_value(block, "is_gas", false);
|
auto is_gas = safe_get_value(block, "is_gas", false);
|
||||||
auto is_discard = safe_get_value(block, "is_discard", false);
|
auto is_discard = safe_get_value(block, "is_discard", false);
|
||||||
auto is_blend = safe_get_value(block, "is_blend", false);
|
auto is_blend = safe_get_value(block, "is_blend", false);
|
||||||
auto is_transitional = safe_get_value(block, "is_transitional", false);
|
|
||||||
m_datas.emplace_back(*id, *name, *is_liquid, *is_passable,
|
m_datas.emplace_back(*id, *name, *is_liquid, *is_passable,
|
||||||
*is_cross_plane, *is_transparent, *is_gas,
|
*is_cross_plane, *is_transparent, *is_gas,
|
||||||
*is_discard, *is_blend, *is_transitional);
|
*is_discard, *is_blend);
|
||||||
}
|
}
|
||||||
std::sort(
|
std::sort(
|
||||||
m_datas.begin(), m_datas.end(),
|
m_datas.begin(), m_datas.end(),
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ void DesertBuilder::build_blocks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ocean_water_build();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesertBuilder::build_vegetation() {}
|
void DesertBuilder::build_vegetation() {}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ void ForestBuilder::build_blocks() {
|
|||||||
m_blocks[Chunk::index(x, height, z)] = 1;
|
m_blocks[Chunk::index(x, height, z)] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ocean_water_build();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForestBuilder::build_vegetation() {
|
void ForestBuilder::build_vegetation() {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ void MountainBuilder::build_blocks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ocean_water_build();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MountainBuilder::build_vegetation() {}
|
void MountainBuilder::build_vegetation() {}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ void OceanBuilder::build_blocks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ocean_water_build();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OceanBuilder::build_vegetation() {}
|
void OceanBuilder::build_vegetation() {}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ void PlainBuilder::build_blocks() {
|
|||||||
m_blocks[Chunk::index(x, height, z)] = 1;
|
m_blocks[Chunk::index(x, height, z)] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ocean_water_build();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlainBuilder::build_vegetation() { place_grass(); }
|
void PlainBuilder::build_vegetation() { place_grass(); }
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ void SnowyPlainBuilder::build_blocks() {
|
|||||||
m_blocks[Chunk::index(x, height, z)] = 8;
|
m_blocks[Chunk::index(x, height, z)] = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ocean_water_build();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnowyPlainBuilder::build_vegetation() {}
|
void SnowyPlainBuilder::build_vegetation() {}
|
||||||
|
|||||||
@@ -5,10 +5,11 @@
|
|||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
CaveCarver::CaveCarver() {}
|
CaveCarver::CaveCarver() {}
|
||||||
|
|
||||||
CaveCarver::CaveHashMap& CaveCarver::paths() { return m_paths; }
|
std::unordered_map<unsigned, CavePath>& CaveCarver::paths() { return m_paths; }
|
||||||
|
|
||||||
void CaveCarver::init(unsigned world_seed) {
|
void CaveCarver::init(unsigned world_seed) {
|
||||||
m_seed = world_seed;
|
m_seed = world_seed;
|
||||||
|
m_sum = 0;
|
||||||
m_random.init(m_seed);
|
m_random.init(m_seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,18 +20,16 @@ void CaveCarver::reload(unsigned world_seed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CaveCarver::add_path(const glm::vec3& pos, unsigned chunk_seed) {
|
void CaveCarver::add_path(const glm::vec3& pos, unsigned chunk_seed) {
|
||||||
m_paths.emplace(chunk_seed, CavePath{chunk_seed, m_seed, pos});
|
m_paths.emplace(chunk_seed, CavePath{m_seed, m_sum, pos});
|
||||||
|
m_sum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CaveCarver::try_to_add_path(const ChunkPos& chunk_pos,
|
void CaveCarver::try_to_add_path(const ChunkPos& chunk_pos,
|
||||||
unsigned chunk_seed) {
|
unsigned chunk_seed) {
|
||||||
{
|
auto it = m_paths.find(chunk_seed);
|
||||||
CaveHashMap::const_accessor acc;
|
if (it != m_paths.end()) {
|
||||||
if (m_paths.find(acc, chunk_seed)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Random random{chunk_seed};
|
Random random{chunk_seed};
|
||||||
if (random.random_bool(static_cast<double>(m_cave_probability))) {
|
if (random.random_bool(static_cast<double>(m_cave_probability))) {
|
||||||
const int CHUNK_MIN_X = chunk_pos.x * CHUNK_SIZE;
|
const int CHUNK_MIN_X = chunk_pos.x * CHUNK_SIZE;
|
||||||
@@ -48,17 +47,10 @@ void CaveCarver::try_to_add_path(const ChunkPos& chunk_pos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CaveCarver::cleanup_finished_caves() {
|
void CaveCarver::cleanup_finished_caves() {
|
||||||
std::vector<unsigned int> finished_keys;
|
std::erase_if(m_paths,
|
||||||
for (const auto& pair : m_paths) {
|
[](const auto& kv) { return kv.second.is_finished(); });
|
||||||
if (pair.second.is_finished()) {
|
|
||||||
finished_keys.push_back(pair.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const auto& key : finished_keys) {
|
|
||||||
m_paths.erase(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CaveCarver::cave_sum() const { return m_paths.size(); }
|
int CaveCarver::cave_sum() const { return m_sum; }
|
||||||
float& CaveCarver::cave_probability() { return m_cave_probability; }
|
float& CaveCarver::cave_probability() { return m_cave_probability; }
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -6,9 +6,10 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
CavePath::CavePath(unsigned int chunk_seed, unsigned world_seed,
|
CavePath::CavePath(unsigned int world_seed, int path_id,
|
||||||
const glm::vec3& start_pos) {
|
const glm::vec3& start_pos) {
|
||||||
m_seed = HASH::combine_32(chunk_seed, world_seed);
|
m_path_id = path_id;
|
||||||
|
m_seed = HASH::combine_32(world_seed, path_id);
|
||||||
m_random.init(m_seed);
|
m_random.init(m_seed);
|
||||||
m_yaw = m_random.random_float(0.0f, 360.0f);
|
m_yaw = m_random.random_float(0.0f, 360.0f);
|
||||||
m_pitch = m_random.random_float(-10.0f, 10.0f);
|
m_pitch = m_random.random_float(-10.0f, 10.0f);
|
||||||
@@ -74,8 +75,7 @@ void CavePath::precompute_chunk_coverage() {
|
|||||||
|
|
||||||
for (int cx = min_cx; cx <= max_cx; ++cx)
|
for (int cx = min_cx; cx <= max_cx; ++cx)
|
||||||
for (int cz = min_cz; cz <= max_cz; ++cz)
|
for (int cz = min_cz; cz <= max_cz; ++cz)
|
||||||
m_pending_chunks.insert(
|
m_pending_chunks.insert({cx, cz});
|
||||||
std::make_pair(ChunkPos{cx, cz}, false));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,8 @@ int Chunk::index(const glm::vec3& pos) {
|
|||||||
return Chunk::index(pos.x, pos.y, pos.z);
|
return Chunk::index(pos.x, pos.y, pos.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chunk::gen_vertex_data(const OptionalBlockVectorArray& neighbor_block) {
|
void Chunk::gen_vertex_data(
|
||||||
|
const std::array<const std::vector<BlockType>*, 4>& neighbor_block) {
|
||||||
if (m_is_on_gen_vertex_data) {
|
if (m_is_on_gen_vertex_data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -198,8 +199,9 @@ void Chunk::gen_phase_six(
|
|||||||
Logger::error("ChunkGenerator is Nullptr");
|
Logger::error("ChunkGenerator is Nullptr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// This must be fully completed before any other operations can proceed!
|
// m_generator->blend_surface_blocks_borders(neighbor_block);
|
||||||
m_generator->blend_surface_blocks_borders(neighbor_block);
|
m_generator->generate_cave();
|
||||||
|
m_generator->generate_river();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chunk::gen_phase_seven() {
|
void Chunk::gen_phase_seven() {
|
||||||
@@ -207,10 +209,6 @@ void Chunk::gen_phase_seven() {
|
|||||||
Logger::error("ChunkGenerator is Nullptr");
|
Logger::error("ChunkGenerator is Nullptr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_generator->ocean_build();
|
|
||||||
m_generator->generate_river();
|
|
||||||
m_generator->generate_cave();
|
|
||||||
|
|
||||||
m_generator->generate_vegetation();
|
m_generator->generate_vegetation();
|
||||||
mark_dirty();
|
mark_dirty();
|
||||||
m_generator = nullptr;
|
m_generator = nullptr;
|
||||||
@@ -264,7 +262,8 @@ unsigned Chunk::seed() const {
|
|||||||
|
|
||||||
BiomeConditions& Chunk::conditions() { return m_conditions; }
|
BiomeConditions& Chunk::conditions() { return m_conditions; }
|
||||||
|
|
||||||
void Chunk::gen_vertices(const OptionalBlockVectorArray& neighbor_block) {
|
void Chunk::gen_vertices(
|
||||||
|
const std::array<const std::vector<BlockType>*, 4>& neighbor_block) {
|
||||||
static const glm::ivec3 DIR[6] = {{0, 0, 1}, {1, 0, 0}, {0, 0, -1},
|
static const glm::ivec3 DIR[6] = {{0, 0, 1}, {1, 0, 0}, {0, 0, -1},
|
||||||
{-1, 0, 0}, {0, 1, 0}, {0, -1, 0}};
|
{-1, 0, 0}, {0, 1, 0}, {0, -1, 0}};
|
||||||
|
|
||||||
@@ -297,9 +296,8 @@ void Chunk::gen_vertices(const OptionalBlockVectorArray& neighbor_block) {
|
|||||||
World::chunk_pos(world_nx, world_nz);
|
World::chunk_pos(world_nx, world_nz);
|
||||||
|
|
||||||
auto is_culled =
|
auto is_culled =
|
||||||
[&](const std::optional<std::vector<BlockType>>&
|
[&](const std::vector<BlockType>* chunk_blocks) {
|
||||||
chunk_blocks) {
|
if (chunk_blocks == nullptr) {
|
||||||
if (chunk_blocks == std::nullopt) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ namespace Cubed {
|
|||||||
|
|
||||||
using enum BiomeType;
|
using enum BiomeType;
|
||||||
|
|
||||||
constexpr int BLEND_RADIUS = 8;
|
constexpr int BLEND_RADIUS = 12;
|
||||||
ChunkGenerator::ChunkGenerator(Chunk& chunk) : m_chunk(chunk) {
|
ChunkGenerator::ChunkGenerator(Chunk& chunk) : m_chunk(chunk) {
|
||||||
ASSERT_MSG(is_init, "ChunksGenerator is not init");
|
ASSERT_MSG(is_init, "ChunksGenerator is not init");
|
||||||
ChunkPos pos = m_chunk.get_chunk_pos();
|
ChunkPos pos = m_chunk.get_chunk_pos();
|
||||||
unsigned seed = HASH::chunk_seed_hash(pos.x, pos.z, m_generator_seed);
|
unsigned seed = HASH::mix_hash(pos.x, pos.z, m_generator_seed);
|
||||||
m_random.init(seed);
|
m_random.init(seed);
|
||||||
m_chunk_seed = seed;
|
m_chunk_seed = seed;
|
||||||
}
|
}
|
||||||
@@ -477,11 +477,9 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
for (int y = WORLD_HEIGHT - 1; y >= 0; --y) {
|
for (int y = WORLD_HEIGHT - 1; y >= 0; --y) {
|
||||||
int idx = Chunk::index(nx, y,
|
int idx = Chunk::index(nx, y,
|
||||||
nz); // linear index: y * area + z * size + x
|
nz); // linear index: y * area + z * size + x
|
||||||
if (idx >= 0 && idx < static_cast<int>(blocks.size())) {
|
if (idx >= 0 && idx < static_cast<int>(blocks.size()) &&
|
||||||
BlockType neighbor_type = blocks[idx];
|
blocks[idx] != 0) {
|
||||||
if (BlockManager::is_transitional(neighbor_type)) {
|
return blocks[idx];
|
||||||
return neighbor_type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0; // fallback, should not happen for valid chunks
|
return 0; // fallback, should not happen for valid chunks
|
||||||
@@ -501,8 +499,8 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
|
|
||||||
// Weight map: type -> total weight
|
// Weight map: type -> total weight
|
||||||
std::unordered_map<BlockType, float> weights;
|
std::unordered_map<BlockType, float> weights;
|
||||||
float self_weight = 1.0f;
|
weights[type_self] = 1.0f; // self weight
|
||||||
weights[type_self] = self_weight;
|
|
||||||
// --- Right neighbor (index 0) ---
|
// --- Right neighbor (index 0) ---
|
||||||
if (neighbor_block[0] && x >= CHUNK_SIZE - BLEND_RADIUS) {
|
if (neighbor_block[0] && x >= CHUNK_SIZE - BLEND_RADIUS) {
|
||||||
int dist = (CHUNK_SIZE - 1) - x;
|
int dist = (CHUNK_SIZE - 1) - x;
|
||||||
@@ -551,41 +549,34 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weights.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Find type with maximum total weight
|
// Find type with maximum total weight
|
||||||
BlockType final_type = type_self;
|
BlockType final_type = type_self;
|
||||||
/*float max_weight = weights[type_self];
|
float max_weight = weights[type_self];
|
||||||
for (const auto& [type, w] : weights) {
|
for (const auto& [type, w] : weights) {
|
||||||
if (w > max_weight) {
|
if (w > max_weight) {
|
||||||
max_weight = w;
|
max_weight = w;
|
||||||
final_type = type;
|
final_type = type;
|
||||||
}
|
}
|
||||||
}*/
|
|
||||||
|
|
||||||
float sum = 0.0f;
|
|
||||||
for (auto& kv : weights) {
|
|
||||||
sum += kv.second;
|
|
||||||
}
|
|
||||||
float rnd = m_random.random_float(0.0f, 1.0f);
|
|
||||||
float accum = 0.0f;
|
|
||||||
for (auto [t, w] : weights) {
|
|
||||||
accum += w / sum;
|
|
||||||
if (rnd < accum) {
|
|
||||||
final_type = t;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BlockManager::is_transitional(final_type)) {
|
if (final_type == 0) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the top block if the type changed
|
// Update the top block if the type changed
|
||||||
if (final_type != type_self) {
|
if (final_type != type_self) {
|
||||||
// top block
|
// top block
|
||||||
BlockType new_surface = final_type;
|
if (final_type == 7 && top_y > SEA_LEVEL) {
|
||||||
m_blocks[Chunk::index(x, top_y, z)] = new_surface;
|
if (type_self == 7) {
|
||||||
|
m_blocks[Chunk::index(x, top_y, z)] = 0;
|
||||||
|
} else {
|
||||||
|
m_blocks[Chunk::index(x, top_y, z)] = type_self;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
m_blocks[Chunk::index(x, top_y, z)] = final_type;
|
||||||
|
}
|
||||||
|
|
||||||
// bottom block
|
// bottom block
|
||||||
unsigned fill_type = 2;
|
unsigned fill_type = 2;
|
||||||
if (final_type == 1 || final_type == 8) {
|
if (final_type == 1 || final_type == 8) {
|
||||||
@@ -593,12 +584,16 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
} else {
|
} else {
|
||||||
fill_type = final_type;
|
fill_type = final_type;
|
||||||
}
|
}
|
||||||
for (int y = std::max(0, top_y - 5); y < top_y; y++) {
|
for (int y = top_y - 5; y < top_y; y++) {
|
||||||
|
if (fill_type == 7 && y > SEA_LEVEL) {
|
||||||
|
m_blocks[Chunk::index(x, y, z)] = 0;
|
||||||
|
} else {
|
||||||
m_blocks[Chunk::index(x, y, z)] = fill_type;
|
m_blocks[Chunk::index(x, y, z)] = fill_type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkGenerator::generate_vegetation() {
|
void ChunkGenerator::generate_vegetation() {
|
||||||
@@ -640,31 +635,29 @@ void ChunkGenerator::make_biome_builder() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkGenerator::ocean_build() { m_biome_builder->ocean_water_build(); }
|
void ChunkGenerator::generate_cave() {
|
||||||
|
auto& cave_carver = m_chunk.world().cave_carcer();
|
||||||
void ChunkGenerator::carve_worm(
|
auto& paths = cave_carver.paths();
|
||||||
const std::vector<PathPoint>& points, const ChunkPos& chunk_pos,
|
const auto& chunk_pos = m_chunk.chunk_pos();
|
||||||
std::function<void(int /*x*/, int /*y*/, int /*z*/)> on_hit) {
|
auto& blocks = m_chunk.blocks();
|
||||||
const int CHUNK_MIN_X = chunk_pos.x * CHUNK_SIZE;
|
const int CHUNK_MIN_X = chunk_pos.x * CHUNK_SIZE;
|
||||||
const int CHUNK_MIN_Z = chunk_pos.z * CHUNK_SIZE;
|
const int CHUNK_MIN_Z = chunk_pos.z * CHUNK_SIZE;
|
||||||
const int CHUNK_MAX_X = CHUNK_MIN_X + SIZE_X - 1;
|
const int CHUNK_MAX_X = CHUNK_MIN_X + SIZE_X - 1;
|
||||||
const int CHUNK_MAX_Z = CHUNK_MIN_Z + SIZE_Z - 1;
|
const int CHUNK_MAX_Z = CHUNK_MIN_Z + SIZE_Z - 1;
|
||||||
const int CHUNK_MIN_Y = 0;
|
const int CHUNK_MIN_Y = 0;
|
||||||
const int CHUNK_MAX_Y = SIZE_Y - 1;
|
const int CHUNK_MAX_Y = SIZE_Y - 1;
|
||||||
for (const auto& point : points) {
|
|
||||||
|
|
||||||
|
for (auto& [id, path] : paths) {
|
||||||
|
for (const auto& point : path.points()) {
|
||||||
|
if ((m_chunk.biome() == BiomeType::RIVER) ||
|
||||||
|
(m_chunk.biome() == BiomeType::OCEAN)) {
|
||||||
|
path.clear_chunk(chunk_pos);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const glm::vec3& center = point.pos;
|
const glm::vec3& center = point.pos;
|
||||||
float rad_xz = point.rad_xz;
|
float rad_xz = point.rad_xz;
|
||||||
float rad_y = point.rad_y;
|
float rad_y = point.rad_y;
|
||||||
|
|
||||||
if (center.x + rad_xz < CHUNK_MIN_X ||
|
|
||||||
center.x - rad_xz > CHUNK_MAX_X ||
|
|
||||||
center.z + rad_xz < CHUNK_MIN_Z ||
|
|
||||||
center.z - rad_xz > CHUNK_MAX_Z || center.y + rad_y < CHUNK_MIN_Y ||
|
|
||||||
center.y - rad_y > CHUNK_MAX_Y) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int min_x = static_cast<int>(std::floor(center.x - rad_xz));
|
int min_x = static_cast<int>(std::floor(center.x - rad_xz));
|
||||||
int max_x = static_cast<int>(std::floor(center.x + rad_xz));
|
int max_x = static_cast<int>(std::floor(center.x + rad_xz));
|
||||||
int min_z = static_cast<int>(std::floor(center.z - rad_xz));
|
int min_z = static_cast<int>(std::floor(center.z - rad_xz));
|
||||||
@@ -679,61 +672,28 @@ void ChunkGenerator::carve_worm(
|
|||||||
min_y = std::max(min_y, CHUNK_MIN_Y);
|
min_y = std::max(min_y, CHUNK_MIN_Y);
|
||||||
max_y = std::min(max_y, CHUNK_MAX_Y);
|
max_y = std::min(max_y, CHUNK_MAX_Y);
|
||||||
|
|
||||||
glm::vec3 right_raw =
|
|
||||||
glm::cross(point.tangent, glm::vec3(0.0f, 1.0f, 0.0f));
|
|
||||||
if (glm::dot(right_raw, right_raw) < 1e-6f)
|
|
||||||
right_raw = glm::cross(point.tangent, glm::vec3(1.0f, 0.0f, 0.0f));
|
|
||||||
glm::vec3 right = glm::normalize(right_raw);
|
|
||||||
glm::vec3 up = glm::normalize(glm::cross(point.tangent, right));
|
|
||||||
|
|
||||||
float inv_a2 = 1.0f / (point.rad_xz * point.rad_xz);
|
|
||||||
float inv_b2 = 1.0f / (point.rad_y * point.rad_y);
|
|
||||||
|
|
||||||
for (int wy = min_y; wy <= max_y; ++wy) {
|
|
||||||
if (wy == 0)
|
|
||||||
continue;
|
|
||||||
float dy = static_cast<float>(wy) - point.pos.y;
|
|
||||||
|
|
||||||
float vy_contrib = dy * up.y;
|
|
||||||
float vy2 = vy_contrib * vy_contrib * inv_b2;
|
|
||||||
if (vy2 >= 1.0f)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (int wx = min_x; wx <= max_x; ++wx) {
|
for (int wx = min_x; wx <= max_x; ++wx) {
|
||||||
float dx = static_cast<float>(wx) - point.pos.x;
|
|
||||||
for (int wz = min_z; wz <= max_z; ++wz) {
|
|
||||||
float dz = static_cast<float>(wz) - point.pos.z;
|
|
||||||
glm::vec3 to_point(dx, dy, dz);
|
|
||||||
|
|
||||||
float h = glm::dot(to_point, right);
|
|
||||||
float v = glm::dot(to_point, up);
|
|
||||||
|
|
||||||
if (h * h * inv_a2 + v * v * inv_b2 > 1.0f)
|
|
||||||
continue;
|
|
||||||
int x = wx - CHUNK_MIN_X;
|
int x = wx - CHUNK_MIN_X;
|
||||||
on_hit(x, wy, wz - CHUNK_MIN_Z);
|
for (int wz = min_z; wz <= max_z; ++wz) {
|
||||||
|
int z = wz - CHUNK_MIN_Z;
|
||||||
|
for (int wy = min_y; wy <= max_y; ++wy) {
|
||||||
|
int y = wy;
|
||||||
|
glm::vec3 pos(static_cast<float>(wx),
|
||||||
|
static_cast<float>(wy),
|
||||||
|
static_cast<float>(wz));
|
||||||
|
if (point.contains(pos)) {
|
||||||
|
if (y == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (blocks[Chunk::index(x, y, z)] == 7) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
blocks[Chunk::index(x, y, z)] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void ChunkGenerator::generate_cave() {
|
|
||||||
auto& cave_carver = m_chunk.world().cave_carcer();
|
|
||||||
auto& paths = cave_carver.paths();
|
|
||||||
const auto& chunk_pos = m_chunk.chunk_pos();
|
|
||||||
auto& blocks = m_chunk.blocks();
|
|
||||||
|
|
||||||
for (auto& [id, path] : paths) {
|
|
||||||
|
|
||||||
carve_worm(path.points(), chunk_pos, [&](int x, int y, int z) -> void {
|
|
||||||
int idx = Chunk::index(x, y, z);
|
|
||||||
if (blocks[idx] == 7)
|
|
||||||
return;
|
|
||||||
if (y < WORLD_SIZE_Y - 1 && blocks[Chunk::index(x, y + 1, z)] == 7)
|
|
||||||
return;
|
|
||||||
blocks[idx] = 0;
|
|
||||||
});
|
|
||||||
path.clear_chunk(chunk_pos);
|
path.clear_chunk(chunk_pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -744,27 +704,64 @@ void ChunkGenerator::generate_river() {
|
|||||||
auto& paths = river_worm.paths();
|
auto& paths = river_worm.paths();
|
||||||
const auto& chunk_pos = m_chunk.chunk_pos();
|
const auto& chunk_pos = m_chunk.chunk_pos();
|
||||||
auto& blocks = m_chunk.blocks();
|
auto& blocks = m_chunk.blocks();
|
||||||
|
const int CHUNK_MIN_X = chunk_pos.x * CHUNK_SIZE;
|
||||||
|
const int CHUNK_MIN_Z = chunk_pos.z * CHUNK_SIZE;
|
||||||
|
const int CHUNK_MAX_X = CHUNK_MIN_X + SIZE_X - 1;
|
||||||
|
const int CHUNK_MAX_Z = CHUNK_MIN_Z + SIZE_Z - 1;
|
||||||
|
const int CHUNK_MIN_Y = 0;
|
||||||
|
const int CHUNK_MAX_Y = SIZE_Y - 1;
|
||||||
|
|
||||||
bool is_river = false;
|
bool is_river = false;
|
||||||
|
|
||||||
for (auto& [id, path] : paths) {
|
for (auto& [id, path] : paths) {
|
||||||
|
for (const auto& point : path.points()) {
|
||||||
if ((m_chunk.biome() == BiomeType::DESERT) ||
|
if ((m_chunk.biome() == BiomeType::DESERT) ||
|
||||||
(m_chunk.biome() == BiomeType::OCEAN)) {
|
(m_chunk.biome() == BiomeType::OCEAN)) {
|
||||||
path.clear_chunk(chunk_pos);
|
path.clear_chunk(chunk_pos);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
carve_worm(path.points(), chunk_pos, [&](int x, int y, int z) -> void {
|
const glm::vec3& center = point.pos;
|
||||||
int idx = Chunk::index(x, y, z);
|
float rad_xz = point.rad_xz;
|
||||||
|
float rad_y = point.rad_y;
|
||||||
|
|
||||||
|
int min_x = static_cast<int>(std::floor(center.x - rad_xz));
|
||||||
|
int max_x = static_cast<int>(std::floor(center.x + rad_xz));
|
||||||
|
int min_z = static_cast<int>(std::floor(center.z - rad_xz));
|
||||||
|
int max_z = static_cast<int>(std::floor(center.z + rad_xz));
|
||||||
|
int min_y = static_cast<int>(std::floor(center.y - rad_y));
|
||||||
|
int max_y = static_cast<int>(std::floor(center.y + rad_y));
|
||||||
|
|
||||||
|
min_x = std::max(min_x, CHUNK_MIN_X);
|
||||||
|
max_x = std::min(max_x, CHUNK_MAX_X);
|
||||||
|
min_z = std::max(min_z, CHUNK_MIN_Z);
|
||||||
|
max_z = std::min(max_z, CHUNK_MAX_Z);
|
||||||
|
min_y = std::max(min_y, CHUNK_MIN_Y);
|
||||||
|
max_y = std::min(max_y, CHUNK_MAX_Y);
|
||||||
|
|
||||||
|
for (int wx = min_x; wx <= max_x; ++wx) {
|
||||||
|
int x = wx - CHUNK_MIN_X;
|
||||||
|
for (int wz = min_z; wz <= max_z; ++wz) {
|
||||||
|
int z = wz - CHUNK_MIN_Z;
|
||||||
|
for (int wy = min_y; wy <= max_y; ++wy) {
|
||||||
|
int y = wy;
|
||||||
|
glm::vec3 pos(static_cast<float>(wx),
|
||||||
|
static_cast<float>(wy),
|
||||||
|
static_cast<float>(wz));
|
||||||
|
if (point.contains(pos)) {
|
||||||
if (y > SEA_LEVEL) {
|
if (y > SEA_LEVEL) {
|
||||||
blocks[idx] = 0;
|
blocks[Chunk::index(x, y, z)] = 0;
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
is_river = true;
|
is_river = true;
|
||||||
if (blocks[idx] == 0) {
|
if (blocks[Chunk::index(x, y, z)] == 0) {
|
||||||
return;
|
continue;
|
||||||
|
}
|
||||||
|
blocks[Chunk::index(x, y, z)] = 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
blocks[idx] = 7;
|
|
||||||
});
|
|
||||||
path.clear_chunk(chunk_pos);
|
path.clear_chunk(chunk_pos);
|
||||||
}
|
}
|
||||||
if (is_river) {
|
if (is_river) {
|
||||||
|
|||||||
@@ -5,15 +5,12 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
RiverPath::RiverPath(unsigned int chunk_seed, unsigned world_seed,
|
RiverPath::RiverPath(unsigned int world_seed, int path_id,
|
||||||
const glm::vec3& start_pos) {
|
const glm::vec3& start_pos) {
|
||||||
|
m_path_id = path_id;
|
||||||
m_seed = HASH::combine_32(chunk_seed, world_seed);
|
m_seed = HASH::combine_32(world_seed, path_id);
|
||||||
m_random.init(m_seed);
|
m_random.init(m_seed);
|
||||||
|
|
||||||
m_yaw = m_random.random_float(0.0f, 360.0f);
|
m_yaw = m_random.random_float(0.0f, 360.0f);
|
||||||
|
|
||||||
m_initial_yaw = m_yaw;
|
|
||||||
m_pitch = 0.0f;
|
m_pitch = 0.0f;
|
||||||
m_start_path_point.pos = start_pos;
|
m_start_path_point.pos = start_pos;
|
||||||
m_start_path_point.rad_xz =
|
m_start_path_point.rad_xz =
|
||||||
@@ -44,15 +41,14 @@ void RiverPath::collect_path_points() {
|
|||||||
|
|
||||||
float t = Math::smootherstep(0, m_step - 1, i);
|
float t = Math::smootherstep(0, m_step - 1, i);
|
||||||
|
|
||||||
float drad_xz = m_start_path_point.rad_xz * t;
|
float drad_xz = m_start_path_point.rad_xz * (1.0f - t);
|
||||||
float drad_y = m_start_path_point.rad_y * t;
|
float drad_y = m_start_path_point.rad_y * (1.0f - t);
|
||||||
drad_xz = std::max(drad_xz, 4.0f);
|
drad_xz = std::max(drad_xz, 4.0f);
|
||||||
drad_y = std::max(drad_y, 4.0f);
|
drad_y = std::max(drad_y, 4.0f);
|
||||||
m_points.emplace_back(m_points[i].pos + glm::vec3{dx, dy, dz}, drad_xz,
|
m_points.emplace_back(m_points[i].pos + glm::vec3{dx, dy, dz}, drad_xz,
|
||||||
drad_y);
|
drad_y);
|
||||||
|
|
||||||
m_yaw += m_random.random_float(m_delta_angle_min, m_delta_angle_max);
|
m_yaw += m_random.random_float(m_delta_angle_min, m_delta_angle_max);
|
||||||
m_yaw = std::clamp(m_yaw, m_initial_yaw - 10.0f, m_initial_yaw + 10.0f);
|
|
||||||
}
|
}
|
||||||
auto n = m_points.size();
|
auto n = m_points.size();
|
||||||
if (n >= 2) {
|
if (n >= 2) {
|
||||||
@@ -76,8 +72,7 @@ void RiverPath::precompute_chunk_coverage() {
|
|||||||
|
|
||||||
for (int cx = min_cx; cx <= max_cx; ++cx)
|
for (int cx = min_cx; cx <= max_cx; ++cx)
|
||||||
for (int cz = min_cz; cz <= max_cz; ++cz)
|
for (int cz = min_cz; cz <= max_cz; ++cz)
|
||||||
m_pending_chunks.insert(
|
m_pending_chunks.insert({cx, cz});
|
||||||
std::make_pair(ChunkPos{cx, cz}, false));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
RiverWorm::RiverWorm() {}
|
RiverWorm::RiverWorm() {}
|
||||||
|
|
||||||
RiverWorm::RiverHashMap& RiverWorm::paths() { return m_paths; }
|
std::unordered_map<unsigned, RiverPath>& RiverWorm::paths() { return m_paths; }
|
||||||
|
|
||||||
void RiverWorm::init(unsigned world_seed) {
|
void RiverWorm::init(unsigned world_seed) {
|
||||||
m_seed = world_seed;
|
m_seed = world_seed;
|
||||||
|
m_sum = 0;
|
||||||
m_random.init(m_seed);
|
m_random.init(m_seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,17 +20,16 @@ void RiverWorm::reload(unsigned world_seed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RiverWorm::add_path(const glm::vec3& pos, unsigned chunk_seed) {
|
void RiverWorm::add_path(const glm::vec3& pos, unsigned chunk_seed) {
|
||||||
m_paths.emplace(chunk_seed, RiverPath{chunk_seed, m_seed, pos});
|
m_paths.emplace(chunk_seed, RiverPath{m_seed, m_sum, pos});
|
||||||
|
m_sum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RiverWorm::try_to_add_path(const ChunkPos& chunk_pos,
|
void RiverWorm::try_to_add_path(const ChunkPos& chunk_pos,
|
||||||
unsigned chunk_seed) {
|
unsigned chunk_seed) {
|
||||||
{
|
auto it = m_paths.find(chunk_seed);
|
||||||
RiverHashMap::const_accessor acc;
|
if (it != m_paths.end()) {
|
||||||
if (m_paths.find(acc, chunk_seed)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Random random{chunk_seed};
|
Random random{chunk_seed};
|
||||||
if (random.random_bool(static_cast<double>(m_probability))) {
|
if (random.random_bool(static_cast<double>(m_probability))) {
|
||||||
const int CHUNK_MIN_X = chunk_pos.x * CHUNK_SIZE;
|
const int CHUNK_MIN_X = chunk_pos.x * CHUNK_SIZE;
|
||||||
@@ -45,17 +44,10 @@ void RiverWorm::try_to_add_path(const ChunkPos& chunk_pos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RiverWorm::cleanup_finished_rivers() {
|
void RiverWorm::cleanup_finished_rivers() {
|
||||||
std::vector<unsigned> finished_keys;
|
std::erase_if(m_paths,
|
||||||
for (const auto& pair : m_paths) {
|
[](const auto& kv) { return kv.second.is_finished(); });
|
||||||
if (pair.second.is_finished()) {
|
|
||||||
finished_keys.push_back(pair.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const auto& key : finished_keys) {
|
|
||||||
m_paths.erase(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RiverWorm::river_sum() const { return m_paths.size(); }
|
int RiverWorm::river_sum() const { return m_sum; }
|
||||||
float& RiverWorm::river_probability() { return m_probability; }
|
float& RiverWorm::river_probability() { return m_probability; }
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "Cubed/gameplay/tree.hpp"
|
#include "Cubed/gameplay/tree.hpp"
|
||||||
|
|
||||||
#include "Cubed/gameplay/chunk.hpp"
|
#include "Cubed/gameplay/chunk.hpp"
|
||||||
|
#include "Cubed/tools/log.hpp"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ bool build_tree(Chunk& chunk, const glm::ivec3& pos) {
|
|||||||
auto& block = chunk.get_chunk_blocks();
|
auto& block = chunk.get_chunk_blocks();
|
||||||
|
|
||||||
if (block[Chunk::index(pos)] != 1) {
|
if (block[Chunk::index(pos)] != 1) {
|
||||||
|
Logger::info("Root is not Grass Block");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (const auto& d : TREE) {
|
for (const auto& d : TREE) {
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
#include "Cubed/tools/cubed_assert.hpp"
|
#include "Cubed/tools/cubed_assert.hpp"
|
||||||
#include "Cubed/tools/cubed_hash.hpp"
|
#include "Cubed/tools/cubed_hash.hpp"
|
||||||
|
|
||||||
#include <execution>
|
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
struct ChunkRenderData {
|
struct ChunkRenderData {
|
||||||
@@ -91,7 +89,6 @@ void World::init_world() {
|
|||||||
void World::init_chunks() {
|
void World::init_chunks() {
|
||||||
hot_reload();
|
hot_reload();
|
||||||
while (!m_chunk_gen_finished) {
|
while (!m_chunk_gen_finished) {
|
||||||
// Logger::info("World Spawn: {:.2f}%", m_chunk_gen_fraction.load());
|
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,10 +319,8 @@ void World::gen_chunks_internal() {
|
|||||||
m_chunk_gen_fraction = 0.0f;
|
m_chunk_gen_fraction = 0.0f;
|
||||||
m_chunk_gen_finished = false;
|
m_chunk_gen_finished = false;
|
||||||
ChunkPosSet required_chunks;
|
ChunkPosSet required_chunks;
|
||||||
ChunkPairVector temp_neighbor;
|
ChunkHashMap temp_neighbor;
|
||||||
std::vector<ChunkPos> need_gen_temp_chunks_pos;
|
compute_required_chunks(required_chunks, temp_neighbor);
|
||||||
compute_required_chunks(required_chunks, temp_neighbor,
|
|
||||||
need_gen_temp_chunks_pos);
|
|
||||||
|
|
||||||
ASSERT_MSG(!required_chunks.empty(), "required chunks is empty!!");
|
ASSERT_MSG(!required_chunks.empty(), "required chunks is empty!!");
|
||||||
|
|
||||||
@@ -343,14 +338,11 @@ void World::gen_chunks_internal() {
|
|||||||
|
|
||||||
m_chunk_gen_fraction = 0.1f;
|
m_chunk_gen_fraction = 0.1f;
|
||||||
|
|
||||||
ChunkPairVector new_chunks;
|
ChunkUpdateList new_chunks;
|
||||||
ChunkHashMap new_temp_chunks;
|
|
||||||
for (auto& pos : need_gen_chunks_pos) {
|
for (auto& pos : need_gen_chunks_pos) {
|
||||||
new_chunks.push_back({pos, Chunk(*this, pos)});
|
new_chunks.push_back({pos, Chunk(*this, pos)});
|
||||||
}
|
}
|
||||||
for (auto& pos : need_gen_temp_chunks_pos) {
|
|
||||||
new_temp_chunks.emplace(pos, Chunk(*this, pos));
|
|
||||||
}
|
|
||||||
ConstChunkMap new_chunks_neighbor;
|
ConstChunkMap new_chunks_neighbor;
|
||||||
// affected neighbor
|
// affected neighbor
|
||||||
ChunkPtrUpdateList affected_neighbor;
|
ChunkPtrUpdateList affected_neighbor;
|
||||||
@@ -360,28 +352,17 @@ void World::gen_chunks_internal() {
|
|||||||
|
|
||||||
// build new chunk, but the neighbor in m_chunks also need to re-build
|
// build new chunk, but the neighbor in m_chunks also need to re-build
|
||||||
|
|
||||||
std::for_each(std::execution::par, new_chunks.begin(), new_chunks.end(),
|
for (auto& [pos, chunk] : new_chunks) {
|
||||||
[this](std::pair<ChunkPos, Chunk>& new_chunk) {
|
|
||||||
auto& [pos, chunk] = new_chunk;
|
|
||||||
chunk.gen_phase_one();
|
chunk.gen_phase_one();
|
||||||
m_cave_carcer.try_to_add_path(pos, chunk.seed());
|
m_cave_carcer.try_to_add_path(pos, chunk.seed());
|
||||||
m_river_worm.try_to_add_path(pos, chunk.seed());
|
m_river_worm.try_to_add_path(pos, chunk.seed());
|
||||||
});
|
}
|
||||||
|
|
||||||
std::for_each(new_temp_chunks.begin(), new_temp_chunks.end(),
|
|
||||||
[](std::pair<const ChunkPos, Chunk>& new_chunk) {
|
|
||||||
auto& [pos, chunk] = new_chunk;
|
|
||||||
chunk.gen_phase_one();
|
|
||||||
});
|
|
||||||
// precompute path to ensure the continuity of the path
|
// precompute path to ensure the continuity of the path
|
||||||
std::for_each(std::execution::par, temp_neighbor.begin(),
|
for (auto& [pos, chunk] : temp_neighbor) {
|
||||||
temp_neighbor.end(),
|
|
||||||
[this](std::pair<ChunkPos, Chunk>& new_chunk) {
|
|
||||||
auto& [pos, chunk] = new_chunk;
|
|
||||||
chunk.gen_phase_one();
|
chunk.gen_phase_one();
|
||||||
m_cave_carcer.try_to_add_path(pos, chunk.seed());
|
m_cave_carcer.try_to_add_path(pos, chunk.seed());
|
||||||
m_river_worm.try_to_add_path(pos, chunk.seed());
|
m_river_worm.try_to_add_path(pos, chunk.seed());
|
||||||
});
|
}
|
||||||
|
|
||||||
m_chunk_gen_fraction = 0.2f;
|
m_chunk_gen_fraction = 0.2f;
|
||||||
|
|
||||||
@@ -419,19 +400,15 @@ void World::gen_chunks_internal() {
|
|||||||
|
|
||||||
m_chunk_gen_fraction = 0.3f;
|
m_chunk_gen_fraction = 0.3f;
|
||||||
|
|
||||||
std::for_each(std::execution::par, new_chunks.begin(), new_chunks.end(),
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
[](std::pair<ChunkPos, Chunk>& pair) {
|
|
||||||
auto& [pos, chunks] = pair;
|
|
||||||
chunks.gen_phase_three();
|
chunks.gen_phase_three();
|
||||||
});
|
|
||||||
|
|
||||||
for (auto& [pos, chunk] : new_temp_chunks) {
|
|
||||||
chunk.gen_phase_three();
|
|
||||||
}
|
}
|
||||||
// for (auto& [pos, chunks] : temp_neighbor) {
|
// for (auto& [pos, chunks] : temp_neighbor) {
|
||||||
// chunks.gen_phase_three();
|
// chunks.gen_phase_three();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
m_chunk_gen_fraction = 0.4f;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
for (auto& [pos, chunks] : temp_neighbor) {
|
for (auto& [pos, chunks] : temp_neighbor) {
|
||||||
@@ -475,106 +452,68 @@ void World::gen_chunks_internal() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
m_chunk_gen_fraction = 0.4f;
|
|
||||||
|
|
||||||
|
m_chunk_gen_fraction = 0.5f;
|
||||||
for (auto& [pos, chunks] : new_chunks) {
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
chunks.gen_phase_five();
|
chunks.gen_phase_five();
|
||||||
}
|
}
|
||||||
m_chunk_gen_fraction = 0.45f;
|
|
||||||
for (auto& [pos, chunk] : new_temp_chunks) {
|
|
||||||
chunk.gen_phase_five();
|
|
||||||
}
|
|
||||||
m_chunk_gen_fraction = 0.5f;
|
|
||||||
/*
|
/*
|
||||||
for (auto& [pos, chunks] : temp_neighbor) {
|
for (auto& [pos, chunks] : temp_neighbor) {
|
||||||
chunks.gen_phase_five();
|
chunks.gen_phase_five();
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::vector<std::pair<Chunk*, OptionalBlockVectorArray>>
|
std::array<std::optional<std::vector<BlockType>>, 4> neighbor_blocks_data;
|
||||||
new_chunks_surface_blend_data(new_chunks.size());
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
for (size_t idx = 0; idx < new_chunks.size(); idx++) {
|
|
||||||
auto& [pos, chunk] = new_chunks[idx];
|
|
||||||
new_chunks_surface_blend_data[idx].first = &chunk;
|
|
||||||
{
|
{
|
||||||
// std::lock_guard lk(m_chunks_mutex);
|
// std::lock_guard lk(m_chunks_mutex);
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
auto neighbor_pos = pos + CHUNK_DIR[i];
|
auto neighbor_pos = pos + CHUNK_DIR[i];
|
||||||
auto it = new_chunks_neighbor.find(neighbor_pos);
|
auto it = new_chunks_neighbor.find(neighbor_pos);
|
||||||
if (it == new_chunks_neighbor.end()) {
|
if (it == new_chunks_neighbor.end()) {
|
||||||
auto it = new_temp_chunks.find(neighbor_pos);
|
neighbor_blocks_data[i] = std::nullopt;
|
||||||
if (it == new_temp_chunks.end()) {
|
|
||||||
new_chunks_surface_blend_data[idx].second[i] =
|
|
||||||
std::nullopt;
|
|
||||||
Logger::warn(
|
|
||||||
"Can't find neighbor for chunk surface blend");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
new_chunks_surface_blend_data[idx].second[i] =
|
neighbor_blocks_data[i] = it->second->get_chunk_blocks();
|
||||||
it->second.get_chunk_blocks();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
new_chunks_surface_blend_data[idx].second[i] =
|
|
||||||
it->second->get_chunk_blocks();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
chunks.gen_phase_six(neighbor_blocks_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::for_each(
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
std::execution::par, new_chunks_surface_blend_data.begin(),
|
chunks.gen_phase_seven();
|
||||||
new_chunks_surface_blend_data.end(),
|
}
|
||||||
[](std::pair<Chunk*, OptionalBlockVectorArray>& new_chunk_data) {
|
|
||||||
auto& [chunk, neighbor_data] = new_chunk_data;
|
|
||||||
chunk->gen_phase_six(neighbor_data);
|
|
||||||
});
|
|
||||||
|
|
||||||
m_chunk_gen_fraction = 0.55f;
|
|
||||||
std::for_each(std::execution::par, new_chunks.begin(), new_chunks.end(),
|
|
||||||
[](std::pair<ChunkPos, Chunk>& new_chunk) {
|
|
||||||
auto& [pos, chunk] = new_chunk;
|
|
||||||
chunk.gen_phase_seven();
|
|
||||||
});
|
|
||||||
|
|
||||||
m_chunk_gen_fraction = 0.6f;
|
m_chunk_gen_fraction = 0.6f;
|
||||||
|
|
||||||
std::vector<std::pair<Chunk*, OptionalBlockVectorArray>>
|
std::array<const std::vector<BlockType>*, 4> neighbor_block;
|
||||||
new_chunk_vertices_data(new_chunks.size());
|
for (auto& [pos, chunk] : new_chunks) {
|
||||||
for (size_t idx = 0; idx < new_chunks.size(); idx++) {
|
|
||||||
auto& [pos, chunk] = new_chunks[idx];
|
|
||||||
new_chunk_vertices_data[idx].first = &chunk;
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
auto it = new_chunks_neighbor.find(pos + CHUNK_DIR[i]);
|
auto it = new_chunks_neighbor.find(pos + CHUNK_DIR[i]);
|
||||||
if (it != new_chunks_neighbor.end()) {
|
if (it != new_chunks_neighbor.end()) {
|
||||||
new_chunk_vertices_data[idx].second[i] =
|
neighbor_block[i] = &(it->second->get_chunk_blocks());
|
||||||
(it->second->get_chunk_blocks());
|
|
||||||
} else {
|
} else {
|
||||||
new_chunk_vertices_data[idx].second[i] = std::nullopt;
|
neighbor_block[i] = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
chunk.gen_vertex_data(neighbor_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::for_each(
|
|
||||||
std::execution::par, new_chunk_vertices_data.begin(),
|
|
||||||
new_chunk_vertices_data.end(),
|
|
||||||
[](std::pair<Chunk*, OptionalBlockVectorArray>& new_chunk_data) {
|
|
||||||
auto& [chunk, neighbor_data] = new_chunk_data;
|
|
||||||
chunk->gen_vertex_data(neighbor_data);
|
|
||||||
});
|
|
||||||
|
|
||||||
m_chunk_gen_fraction = 0.7f;
|
m_chunk_gen_fraction = 0.7f;
|
||||||
|
|
||||||
build_neighbor_context_for_affected_neighbors(affected_neighbor,
|
build_neighbor_context_for_affected_neighbors(affected_neighbor,
|
||||||
new_chunks_neighbor);
|
new_chunks_neighbor);
|
||||||
|
|
||||||
m_chunk_gen_fraction = 0.8f;
|
m_chunk_gen_fraction = 0.8f;
|
||||||
OptionalBlockVectorArray neighbor_block;
|
|
||||||
for (auto& [pos, chunk] : affected_neighbor) {
|
for (auto& [pos, chunk] : affected_neighbor) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
auto it = new_chunks_neighbor.find(pos + CHUNK_DIR[i]);
|
auto it = new_chunks_neighbor.find(pos + CHUNK_DIR[i]);
|
||||||
if (it != new_chunks_neighbor.end()) {
|
if (it != new_chunks_neighbor.end()) {
|
||||||
neighbor_block[i] = (it->second->get_chunk_blocks());
|
neighbor_block[i] = &(it->second->get_chunk_blocks());
|
||||||
} else {
|
} else {
|
||||||
neighbor_block[i] = std::nullopt;
|
neighbor_block[i] = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chunk->gen_vertex_data(neighbor_block);
|
chunk->gen_vertex_data(neighbor_block);
|
||||||
@@ -600,53 +539,32 @@ void World::sync_player_pos(glm::vec3& player_pos) {
|
|||||||
player_pos = m_gen_player_pos;
|
player_pos = m_gen_player_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::compute_required_chunks(
|
void World::compute_required_chunks(ChunkPosSet& required_chunks,
|
||||||
ChunkPosSet& required_chunks, ChunkPairVector& temp_neighbor,
|
ChunkHashMap& temp_neighbor) {
|
||||||
std::vector<ChunkPos>& need_gen_temp_chunks_pos) {
|
|
||||||
glm::vec3 player_pos;
|
glm::vec3 player_pos;
|
||||||
sync_player_pos(player_pos);
|
sync_player_pos(player_pos);
|
||||||
|
|
||||||
int x = std::floor(player_pos.x);
|
int x = std::floor(player_pos.x);
|
||||||
int z = std::floor(player_pos.z);
|
int z = std::floor(player_pos.z);
|
||||||
auto [chunk_x, chunk_z] = chunk_pos(x, z);
|
auto [chunk_x, chunk_z] = chunk_pos(x, z);
|
||||||
int radius = m_rendering_distance;
|
|
||||||
int r2 = radius * radius;
|
|
||||||
required_chunks.reserve(radius * radius);
|
|
||||||
|
|
||||||
for (int dx = -radius; dx <= radius; ++dx) {
|
required_chunks.reserve(m_rendering_distance * m_rendering_distance);
|
||||||
for (int dz = -radius; dz <= radius; ++dz) {
|
int half = m_rendering_distance / 2;
|
||||||
if (dx * dx + dz * dz <= r2) {
|
for (int u = chunk_x - half; u <= chunk_x + half; ++u) {
|
||||||
required_chunks.emplace(chunk_x + dx, chunk_z + dz);
|
for (int v = chunk_z - half; v <= chunk_z + half; ++v) {
|
||||||
}
|
required_chunks.emplace(u, v);
|
||||||
}
|
|
||||||
}
|
|
||||||
int new_radius = radius + 1;
|
|
||||||
int new_r2 = new_radius * new_radius;
|
|
||||||
for (int dx = -new_radius; dx <= new_radius; ++dx) {
|
|
||||||
for (int dz = -new_radius; dz <= new_radius; ++dz) {
|
|
||||||
if (dx * dx + dz * dz <= new_r2) {
|
|
||||||
int nx = chunk_x + dx;
|
|
||||||
int nz = chunk_z + dz;
|
|
||||||
auto it = required_chunks.find({nx, nz});
|
|
||||||
if (it == required_chunks.end()) {
|
|
||||||
need_gen_temp_chunks_pos.push_back({nx, nz});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int max_path_len = std::max(CavePath::step_max(), RiverPath::step_max());
|
int max_path_len = std::max(CavePath::step_max(), RiverPath::step_max());
|
||||||
radius = max_path_len / 2;
|
half = std::ceil(static_cast<float>(max_path_len) / CHUNK_SIZE) * 2;
|
||||||
r2 = radius * radius;
|
for (int u = chunk_x - half; u <= chunk_x + half; ++u) {
|
||||||
for (int dx = -radius; dx <= radius; ++dx) {
|
for (int v = chunk_z - half; v <= chunk_z + half; ++v) {
|
||||||
for (int dz = -radius; dz <= radius; ++dz) {
|
ChunkPos pos{u, v};
|
||||||
if (dx * dx + dz * dz <= r2) {
|
|
||||||
ChunkPos pos{chunk_x + dx, chunk_z + dz};
|
|
||||||
auto it = required_chunks.find(pos);
|
auto it = required_chunks.find(pos);
|
||||||
if (it != required_chunks.end()) {
|
if (it != required_chunks.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
temp_neighbor.emplace_back(pos, Chunk(*this, pos));
|
temp_neighbor.emplace(pos, Chunk(*this, pos));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -673,7 +591,7 @@ void World::sync_and_collect_missing_chunks(
|
|||||||
|
|
||||||
void World::build_neighbor_context_for_new_chunks(
|
void World::build_neighbor_context_for_new_chunks(
|
||||||
ConstChunkMap& new_chunks_neighbor, ChunkPtrUpdateList& affected_neighbor,
|
ConstChunkMap& new_chunks_neighbor, ChunkPtrUpdateList& affected_neighbor,
|
||||||
const ChunkPairVector& new_chunks) {
|
const ChunkUpdateList& new_chunks) {
|
||||||
{
|
{
|
||||||
std::lock_guard lk(m_chunks_mutex);
|
std::lock_guard lk(m_chunks_mutex);
|
||||||
for (auto& [pos, chunk] : new_chunks) {
|
for (auto& [pos, chunk] : new_chunks) {
|
||||||
@@ -918,13 +836,13 @@ void World::update(float delta_time) {
|
|||||||
for (auto& [pos, chunk] : m_chunks) {
|
for (auto& [pos, chunk] : m_chunks) {
|
||||||
if (chunk.is_dirty()) {
|
if (chunk.is_dirty()) {
|
||||||
// the curial fator influence
|
// the curial fator influence
|
||||||
OptionalBlockVectorArray neighbor_block;
|
std::array<const std::vector<BlockType>*, 4> neighbor_block;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
auto it = m_chunks.find(pos + CHUNK_DIR[i]);
|
auto it = m_chunks.find(pos + CHUNK_DIR[i]);
|
||||||
if (it != m_chunks.end()) {
|
if (it != m_chunks.end()) {
|
||||||
neighbor_block[i] = (it->second.get_chunk_blocks());
|
neighbor_block[i] = &(it->second.get_chunk_blocks());
|
||||||
} else {
|
} else {
|
||||||
neighbor_block[i] = std::nullopt;
|
neighbor_block[i] = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chunk.gen_vertex_data(neighbor_block);
|
chunk.gen_vertex_data(neighbor_block);
|
||||||
|
|||||||
@@ -5,15 +5,8 @@ namespace Cubed {
|
|||||||
Random::Random() {}
|
Random::Random() {}
|
||||||
Random::Random(unsigned seed) { init(seed); }
|
Random::Random(unsigned seed) { init(seed); }
|
||||||
bool Random::random_bool(double probability) {
|
bool Random::random_bool(double probability) {
|
||||||
if (probability <= 0.0)
|
std::bernoulli_distribution dist(probability);
|
||||||
return false;
|
return dist(m_engine);
|
||||||
if (probability >= 1.0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
const double MAX_VAL = 4294967295.0;
|
|
||||||
unsigned threshold = static_cast<unsigned>(probability * MAX_VAL);
|
|
||||||
|
|
||||||
return m_engine() <= threshold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::mt19937& Random::engine() { return m_engine; }
|
std::mt19937& Random::engine() { return m_engine; }
|
||||||
@@ -25,23 +18,12 @@ void Random::init(unsigned seed) {
|
|||||||
m_engine.seed(seed);
|
m_engine.seed(seed);
|
||||||
}
|
}
|
||||||
int Random::random_int(int min, int max) {
|
int Random::random_int(int min, int max) {
|
||||||
unsigned range = static_cast<unsigned>(max - min) + 1;
|
std::uniform_int_distribution<int> dist(min, max);
|
||||||
|
return dist(m_engine);
|
||||||
const unsigned LIMIT =
|
|
||||||
(std::numeric_limits<unsigned>::max() / range) * range;
|
|
||||||
unsigned r;
|
|
||||||
do {
|
|
||||||
r = m_engine();
|
|
||||||
} while (r >= LIMIT);
|
|
||||||
|
|
||||||
return min + static_cast<int>(r % range);
|
|
||||||
}
|
}
|
||||||
float Random::random_float(float min, float max) {
|
float Random::random_float(float min, float max) {
|
||||||
|
std::uniform_real_distribution<float> dist(min, max);
|
||||||
unsigned r = m_engine() >> 8;
|
return dist(m_engine);
|
||||||
float t = static_cast<float>(r) * (1.0f / 16777216.0f);
|
|
||||||
float result = min + t * (max - min);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -59,12 +59,7 @@ bool is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents,
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
float deterministic_random(int x, int z, uint64_t seed) {
|
|
||||||
uint64_t h = seed;
|
|
||||||
h = h * 6364136223846793005ULL + (uint64_t)x;
|
|
||||||
h = h * 6364136223846793005ULL + (uint64_t)z;
|
|
||||||
return (float)(h >> 40) / (float)(1 << 24);
|
|
||||||
}
|
|
||||||
} // namespace Math
|
} // namespace Math
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
Reference in New Issue
Block a user