refactor: terrain generation (#9)
* feat: add BlockType * refactor: use fBM for heightmap generation * feat: improve mountain realism * refactor: adjust mountain spawn probability * feat: add biome boundary blending * refactor: remove resolve_biome_adjacency_conflict function * feat: add snowy plain * perf: speed up world generation * refactor: lower overall terrain height
@@ -119,6 +119,7 @@ add_executable(${PROJECT_NAME}
|
|||||||
src/gameplay/builders/forest_builder.cpp
|
src/gameplay/builders/forest_builder.cpp
|
||||||
src/gameplay/cave_carver.cpp
|
src/gameplay/cave_carver.cpp
|
||||||
src/gameplay/cave_path.cpp
|
src/gameplay/cave_path.cpp
|
||||||
|
src/gameplay/builders/snowy_plain_builder.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
|
|||||||
BIN
assets/texture/block/snowy_grass_block/back.png
Normal file
|
After Width: | Height: | Size: 568 B |
BIN
assets/texture/block/snowy_grass_block/base.png
Normal file
|
After Width: | Height: | Size: 482 B |
BIN
assets/texture/block/snowy_grass_block/front.png
Normal file
|
After Width: | Height: | Size: 568 B |
BIN
assets/texture/block/snowy_grass_block/left.png
Normal file
|
After Width: | Height: | Size: 568 B |
BIN
assets/texture/block/snowy_grass_block/right.png
Normal file
|
After Width: | Height: | Size: 568 B |
BIN
assets/texture/block/snowy_grass_block/top.png
Normal file
|
After Width: | Height: | Size: 394 B |
BIN
assets/texture/item/block/snowy_grass_block.png
Normal file
|
After Width: | Height: | Size: 499 B |
@@ -8,7 +8,7 @@ constexpr int WORLD_SIZE_Y = 256;
|
|||||||
constexpr int CHUNK_SIZE = 16;
|
constexpr int CHUNK_SIZE = 16;
|
||||||
constexpr int SEA_LEVEL = 64;
|
constexpr int SEA_LEVEL = 64;
|
||||||
|
|
||||||
constexpr int MAX_BLOCK_NUM = 8;
|
constexpr int MAX_BLOCK_NUM = 9;
|
||||||
constexpr int MAX_UI_NUM = 1;
|
constexpr int MAX_UI_NUM = 1;
|
||||||
constexpr int MAX_BLOCK_STATUS = 1;
|
constexpr int MAX_BLOCK_STATUS = 1;
|
||||||
constexpr int MAX_BIOME_SUM = 4;
|
constexpr int MAX_BIOME_SUM = 4;
|
||||||
|
|||||||
@@ -5,9 +5,24 @@
|
|||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
constexpr float BIOME_NOISE_FREQUENCY = 0.03f;
|
constexpr float BIOME_NOISE_FREQUENCY = 0.06f;
|
||||||
|
constexpr float HEIGHTMAP_NOISE_FREQUENCY = 0.001f;
|
||||||
|
constexpr float MOUNTAINOUS_NOISE_FREQUENCY = 0.003f;
|
||||||
|
enum class BiomeType {
|
||||||
|
PLAIN = 0,
|
||||||
|
FOREST,
|
||||||
|
DESERT,
|
||||||
|
MOUNTAIN,
|
||||||
|
RIVER,
|
||||||
|
SNOWY_PLAIN,
|
||||||
|
NONE
|
||||||
|
};
|
||||||
|
|
||||||
enum class BiomeType { PLAIN = 0, FOREST, DESERT, MOUNTAIN, RIVER, NONE };
|
struct BiomeConditions {
|
||||||
|
float temp = 0.0f;
|
||||||
|
float humid = 0.0f;
|
||||||
|
float mountainous = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
struct BiomeHeightRange {
|
struct BiomeHeightRange {
|
||||||
int base_y;
|
int base_y;
|
||||||
@@ -47,13 +62,14 @@ struct MountainParams : public BaseBiomeParams {};
|
|||||||
struct RiverParams : public BaseBiomeParams {};
|
struct RiverParams : public BaseBiomeParams {};
|
||||||
|
|
||||||
std::string get_biome_str(BiomeType biome);
|
std::string get_biome_str(BiomeType biome);
|
||||||
BiomeType get_biome_from_noise(float temp, float humid);
|
// std::array<float, 3> get_noise_frequencies_for_biome(BiomeType biome);
|
||||||
std::array<float, 3> get_noise_frequencies_for_biome(BiomeType biome);
|
// BiomeHeightRange get_biome_height_range(BiomeType biome);
|
||||||
BiomeHeightRange get_biome_height_range(BiomeType biome);
|
|
||||||
BiomeType safe_int_to_biome(int x);
|
BiomeType safe_int_to_biome(int x);
|
||||||
int get_interpolated_height(float world_x, float world_z, float temp,
|
int get_interpolated_height(float world_x, float world_z, float temp,
|
||||||
float humid);
|
float humid);
|
||||||
|
|
||||||
|
BiomeType determine_biome(const BiomeConditions& conditions);
|
||||||
|
|
||||||
PlainParams& plain_params();
|
PlainParams& plain_params();
|
||||||
ForestParams& forest_params();
|
ForestParams& forest_params();
|
||||||
DesertParams& desert_params();
|
DesertParams& desert_params();
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
|
using BlockType = uint8_t;
|
||||||
|
|
||||||
struct BlockTexture {
|
struct BlockTexture {
|
||||||
std::string name;
|
std::string name;
|
||||||
unsigned id;
|
unsigned id;
|
||||||
@@ -39,10 +41,11 @@ struct LookBlock {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::array<std::string_view, MAX_BLOCK_NUM> BLOCK_REISTER{
|
constexpr std::array<std::string_view, MAX_BLOCK_NUM> BLOCK_REISTER{
|
||||||
"air", "grass_block", "dirt", "stone", "sand", "log", "leaf", "water"};
|
"air", "grass_block", "dirt", "stone", "sand", "log", "leaf",
|
||||||
|
"water", "snowy_grass_block"};
|
||||||
|
|
||||||
const std::array<bool, MAX_BLOCK_NUM> TRANSPARENT_MAP{
|
const std::array<bool, MAX_BLOCK_NUM> TRANSPARENT_MAP{
|
||||||
true, false, false, false, false, false, true};
|
true, false, false, false, false, false, true, false, false};
|
||||||
|
|
||||||
inline bool is_in_transparent_map(unsigned id) {
|
inline bool is_in_transparent_map(unsigned id) {
|
||||||
ASSERT_MSG(id < MAX_BLOCK_NUM, "ID is invaild");
|
ASSERT_MSG(id < MAX_BLOCK_NUM, "ID is invaild");
|
||||||
|
|||||||
21
include/Cubed/gameplay/builders/snowy_plain_builder.hpp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Cubed/gameplay/builders/biome_builder.hpp"
|
||||||
|
namespace Cubed {
|
||||||
|
|
||||||
|
class ChunkGenerator;
|
||||||
|
|
||||||
|
class SnowyPlainBuilder : public BiomeBuilder {
|
||||||
|
public:
|
||||||
|
SnowyPlainBuilder(ChunkGenerator& chunk_generator);
|
||||||
|
void build_biome() override;
|
||||||
|
ChunkGenerator& get_chunk_generator() override;
|
||||||
|
void build_vegetation() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ChunkGenerator& m_chunk_generator;
|
||||||
|
|
||||||
|
void build_blocks();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
#include "Cubed/primitive_data.hpp"
|
#include "Cubed/primitive_data.hpp"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
@@ -32,13 +31,16 @@ private:
|
|||||||
World& m_world;
|
World& m_world;
|
||||||
HeightMapArray m_heightmap;
|
HeightMapArray m_heightmap;
|
||||||
// the index is a array of block id
|
// the index is a array of block id
|
||||||
std::vector<uint8_t> m_blocks;
|
std::vector<BlockType> m_blocks;
|
||||||
GLuint m_vbo = 0;
|
GLuint m_vbo = 0;
|
||||||
std::vector<Vertex> m_vertexs_data;
|
std::vector<Vertex> m_vertexs_data;
|
||||||
|
|
||||||
float frequency = 0.01f;
|
float frequency = 0.01f;
|
||||||
float height = 80;
|
float height = 80;
|
||||||
unsigned m_seed = 0;
|
unsigned m_seed = 0;
|
||||||
|
|
||||||
|
BiomeConditions m_conditions;
|
||||||
|
|
||||||
void clear_dirty();
|
void clear_dirty();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -49,12 +51,21 @@ public:
|
|||||||
Chunk(Chunk&&) noexcept;
|
Chunk(Chunk&&) noexcept;
|
||||||
Chunk& operator=(Chunk&&) noexcept;
|
Chunk& operator=(Chunk&&) noexcept;
|
||||||
|
|
||||||
|
static std::tuple<int, int, int> world_to_block(int world_x, int world_y,
|
||||||
|
int world_z, int chunk_x,
|
||||||
|
int chunk_z);
|
||||||
|
static std::tuple<int, int, int> world_to_block(const glm::ivec3& block_pos,
|
||||||
|
ChunkPos chunk_pos);
|
||||||
|
static std::tuple<int, int, int> block_to_world(int x, int y, int z,
|
||||||
|
int chunk_x, int chunk_z);
|
||||||
|
static std::tuple<int, int, int> block_to_world(const glm::ivec3& block_pos,
|
||||||
|
ChunkPos chunk_pos);
|
||||||
BiomeType get_biome() const;
|
BiomeType get_biome() const;
|
||||||
ChunkPos get_chunk_pos() const;
|
ChunkPos get_chunk_pos() const;
|
||||||
const std::vector<uint8_t>& get_chunk_blocks() const;
|
const std::vector<BlockType>& get_chunk_blocks() const;
|
||||||
HeightMapArray get_heightmap() const;
|
HeightMapArray get_heightmap() const;
|
||||||
static int get_index(int x, int y, int z);
|
static int index(int x, int y, int z);
|
||||||
static int get_index(const glm::vec3& pos);
|
static int index(const glm::vec3& pos);
|
||||||
// Init Chunk
|
// Init Chunk
|
||||||
// Determine biome from temperature and humidity noise
|
// Determine biome from temperature and humidity noise
|
||||||
void gen_phase_one();
|
void gen_phase_one();
|
||||||
@@ -69,8 +80,8 @@ public:
|
|||||||
// Generate terrain blocks from heightmap and biome
|
// Generate terrain blocks from heightmap and biome
|
||||||
void gen_phase_five();
|
void gen_phase_five();
|
||||||
// Blend surface blocks at chunk borders with neighbors
|
// Blend surface blocks at chunk borders with neighbors
|
||||||
void gen_phase_six(const std::array<std::optional<std::vector<uint8_t>>, 4>&
|
void gen_phase_six(const std::array<std::optional<std::vector<BlockType>>,
|
||||||
neighbor_block);
|
4>& neighbor_block);
|
||||||
// Generate biome-specific vegetation/structures
|
// Generate biome-specific vegetation/structures
|
||||||
void gen_phase_seven();
|
void gen_phase_seven();
|
||||||
// void gen_vertex_data();
|
// void gen_vertex_data();
|
||||||
@@ -79,7 +90,7 @@ public:
|
|||||||
// 2 : (0, 1)
|
// 2 : (0, 1)
|
||||||
// 3 : (0, -1)
|
// 3 : (0, -1)
|
||||||
void gen_vertex_data(
|
void gen_vertex_data(
|
||||||
const std::array<const std::vector<uint8_t>*, 4>& neighbor_block);
|
const std::array<const std::vector<BlockType>*, 4>& neighbor_block);
|
||||||
void upload_to_gpu();
|
void upload_to_gpu();
|
||||||
|
|
||||||
GLuint get_vbo() const;
|
GLuint get_vbo() const;
|
||||||
@@ -97,9 +108,10 @@ public:
|
|||||||
BiomeType biome() const;
|
BiomeType biome() const;
|
||||||
void biome(BiomeType b);
|
void biome(BiomeType b);
|
||||||
HeightMapArray& heightmap();
|
HeightMapArray& heightmap();
|
||||||
std::vector<uint8_t>& blocks();
|
std::vector<BlockType>& blocks();
|
||||||
World& world();
|
World& world();
|
||||||
unsigned seed() const;
|
unsigned seed() const;
|
||||||
|
BiomeConditions& conditions();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Cubed/constants.hpp"
|
#include "Cubed/constants.hpp"
|
||||||
#include "Cubed/gameplay/biome.hpp"
|
#include "Cubed/gameplay/biome.hpp"
|
||||||
|
#include "Cubed/gameplay/block.hpp"
|
||||||
#include "Cubed/gameplay/builders/biome_builder.hpp"
|
#include "Cubed/gameplay/builders/biome_builder.hpp"
|
||||||
#include "Cubed/tools/cubed_random.hpp"
|
#include "Cubed/tools/cubed_random.hpp"
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ public:
|
|||||||
void generate_terrain_blocks();
|
void generate_terrain_blocks();
|
||||||
// Adjust Block;
|
// Adjust Block;
|
||||||
void blend_surface_blocks_borders(
|
void blend_surface_blocks_borders(
|
||||||
const std::array<std::optional<std::vector<uint8_t>>, 4>&
|
const std::array<std::optional<std::vector<BlockType>>, 4>&
|
||||||
neighbor_block);
|
neighbor_block);
|
||||||
// Generate Structure
|
// Generate Structure
|
||||||
void generate_vegetation();
|
void generate_vegetation();
|
||||||
@@ -44,6 +45,7 @@ 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 generate_cave();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static inline std::atomic<bool> is_init{false};
|
static inline std::atomic<bool> is_init{false};
|
||||||
@@ -57,7 +59,6 @@ private:
|
|||||||
unsigned m_chunk_seed = 0;
|
unsigned m_chunk_seed = 0;
|
||||||
|
|
||||||
void make_biome_builder();
|
void make_biome_builder();
|
||||||
void generate_cave();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
class PerlinNoise {
|
class PerlinNoise3D {
|
||||||
public:
|
public:
|
||||||
static void init(unsigned seed);
|
static void init(unsigned seed);
|
||||||
static float noise(float x, float y, float z);
|
static float noise(float x, float y, float z);
|
||||||
@@ -18,4 +18,19 @@ private:
|
|||||||
static float grad(int hash, float x, float y, float z);
|
static float grad(int hash, float x, float y, float z);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PerlinNoise2D {
|
||||||
|
public:
|
||||||
|
static void init(unsigned seed);
|
||||||
|
static float noise(float x, float y);
|
||||||
|
static void reload(unsigned seed);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline std::atomic<bool> is_init = false;
|
||||||
|
static inline std::vector<int> p;
|
||||||
|
|
||||||
|
static float fade(float t);
|
||||||
|
static float lerp(float t, float a, float b);
|
||||||
|
static float grad(int hash, float x, float y);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
#include "Cubed/gameplay/biome.hpp"
|
#include "Cubed/gameplay/biome.hpp"
|
||||||
|
|
||||||
#include "Cubed/tools/cubed_assert.hpp"
|
#include "Cubed/tools/cubed_assert.hpp"
|
||||||
#include "Cubed/tools/log.hpp"
|
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
|
using enum BiomeType;
|
||||||
|
|
||||||
static PlainParams plain{{BiomeType::PLAIN,
|
static PlainParams plain{{BiomeType::PLAIN,
|
||||||
{0.0f, 0.5f},
|
{0.0f, 0.5f},
|
||||||
{0.0f, 0.5f},
|
{0.0f, 0.5f},
|
||||||
@@ -59,6 +60,8 @@ std::string get_biome_str(BiomeType biome) {
|
|||||||
case RIVER:
|
case RIVER:
|
||||||
str = "River";
|
str = "River";
|
||||||
break;
|
break;
|
||||||
|
case SNOWY_PLAIN:
|
||||||
|
str = "Snowy Plain";
|
||||||
case NONE:
|
case NONE:
|
||||||
str = "Unknown";
|
str = "Unknown";
|
||||||
break;
|
break;
|
||||||
@@ -84,27 +87,7 @@ Biome get_biome_from_noise(float temp, float humid) {
|
|||||||
return Biome::FOREST;
|
return Biome::FOREST;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
BiomeType get_biome_from_noise(float temp, float humid) {
|
/*
|
||||||
using enum BiomeType;
|
|
||||||
if (plain.temp.first <= temp && temp < plain.temp.second &&
|
|
||||||
plain.humid.first <= humid && humid < plain.humid.second) {
|
|
||||||
return PLAIN;
|
|
||||||
}
|
|
||||||
if (forest.temp.first <= temp && temp < forest.temp.second &&
|
|
||||||
forest.humid.first <= humid && humid < forest.humid.second) {
|
|
||||||
return FOREST;
|
|
||||||
}
|
|
||||||
if (desert.temp.first <= temp && temp < desert.temp.second &&
|
|
||||||
desert.humid.first <= humid && humid < desert.humid.second) {
|
|
||||||
return DESERT;
|
|
||||||
}
|
|
||||||
if (mountain.temp.first <= temp && temp <= mountain.temp.second &&
|
|
||||||
mountain.humid.first <= humid && humid <= mountain.humid.second) {
|
|
||||||
return MOUNTAIN;
|
|
||||||
}
|
|
||||||
Logger::warn("Invail Temp {} or Humid {}", temp, humid);
|
|
||||||
return PLAIN;
|
|
||||||
}
|
|
||||||
std::array<float, 3> get_noise_frequencies_for_biome(BiomeType biome) {
|
std::array<float, 3> get_noise_frequencies_for_biome(BiomeType biome) {
|
||||||
using enum BiomeType;
|
using enum BiomeType;
|
||||||
switch (biome) {
|
switch (biome) {
|
||||||
@@ -125,7 +108,8 @@ std::array<float, 3> get_noise_frequencies_for_biome(BiomeType biome) {
|
|||||||
Logger::warn("Unknown Biome");
|
Logger::warn("Unknown Biome");
|
||||||
return {0.003f, 0.015f, 0.06f};
|
return {0.003f, 0.015f, 0.06f};
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
BiomeHeightRange get_biome_height_range(BiomeType biome) {
|
BiomeHeightRange get_biome_height_range(BiomeType biome) {
|
||||||
using enum BiomeType;
|
using enum BiomeType;
|
||||||
switch (biome) {
|
switch (biome) {
|
||||||
@@ -146,7 +130,7 @@ BiomeHeightRange get_biome_height_range(BiomeType biome) {
|
|||||||
Logger::warn("Unknown Biome");
|
Logger::warn("Unknown Biome");
|
||||||
return {62, 4};
|
return {62, 4};
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
BiomeType safe_int_to_biome(int x) {
|
BiomeType safe_int_to_biome(int x) {
|
||||||
using enum BiomeType;
|
using enum BiomeType;
|
||||||
static const std::unordered_map<int, BiomeType> INT_TO_BIOME_MAP{
|
static const std::unordered_map<int, BiomeType> INT_TO_BIOME_MAP{
|
||||||
@@ -201,6 +185,30 @@ int get_interpolated_height(float world_x, float world_z, float temp,
|
|||||||
return static_cast<int>(h);
|
return static_cast<int>(h);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
BiomeType determine_biome(const BiomeConditions& conditions) {
|
||||||
|
if (conditions.mountainous > 0.75) {
|
||||||
|
return MOUNTAIN;
|
||||||
|
}
|
||||||
|
auto temp = conditions.temp;
|
||||||
|
auto humid = conditions.humid;
|
||||||
|
if (temp < 0.5) {
|
||||||
|
if (humid < 0.5) {
|
||||||
|
return SNOWY_PLAIN;
|
||||||
|
} else {
|
||||||
|
return PLAIN;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (humid < 0.5) {
|
||||||
|
return DESERT;
|
||||||
|
} else {
|
||||||
|
return FOREST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PLAIN;
|
||||||
|
}
|
||||||
|
|
||||||
PlainParams& plain_params() { return plain; }
|
PlainParams& plain_params() { return plain; }
|
||||||
ForestParams& forest_params() { return forest; }
|
ForestParams& forest_params() { return forest; }
|
||||||
DesertParams& desert_params() { return desert; }
|
DesertParams& desert_params() { return desert; }
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ void BiomeBuilder::build_bottom() {
|
|||||||
for (int x = 0; x < CHUNK_SIZE; x++) {
|
for (int x = 0; x < CHUNK_SIZE; x++) {
|
||||||
for (int y = 0; y < 5; y++) {
|
for (int y = 0; y < 5; y++) {
|
||||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ void BiomeBuilder::fill_water() {
|
|||||||
}
|
}
|
||||||
int height = heightmap[x][z];
|
int height = heightmap[x][z];
|
||||||
for (int y = height; y < SEA_LEVEL; y++) {
|
for (int y = height; y < SEA_LEVEL; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 7;
|
m_blocks[Chunk::index(x, y, z)] = 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ void DesertBuilder::build_blocks() {
|
|||||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||||
int height = static_cast<int>(m_heightmap[x][z]);
|
int height = static_cast<int>(m_heightmap[x][z]);
|
||||||
for (int y = 5; y < height - 5; y++) {
|
for (int y = 5; y < height - 5; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int y = height - 5; y <= height; y++) {
|
for (int y = height - 5; y <= height; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 4;
|
m_blocks[Chunk::index(x, y, z)] = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ void ForestBuilder::build_blocks() {
|
|||||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||||
int height = static_cast<int>(m_heightmap[x][z]);
|
int height = static_cast<int>(m_heightmap[x][z]);
|
||||||
for (int y = 5; y < height - 5; y++) {
|
for (int y = 5; y < height - 5; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||||
}
|
}
|
||||||
for (int y = height - 5; y < height; y++) {
|
for (int y = height - 5; y < height; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 2;
|
m_blocks[Chunk::index(x, y, z)] = 2;
|
||||||
}
|
}
|
||||||
m_blocks[Chunk::get_index(x, height, z)] = 1;
|
m_blocks[Chunk::index(x, height, z)] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,8 @@ void MountainBuilder::build_blocks() {
|
|||||||
for (int x = 0; x < CHUNK_SIZE; x++) {
|
for (int x = 0; x < CHUNK_SIZE; x++) {
|
||||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||||
int height = static_cast<int>(m_heightmap[x][z]);
|
int height = static_cast<int>(m_heightmap[x][z]);
|
||||||
for (int y = 5; y < height - 5; y++) {
|
for (int y = 5; y <= height; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||||
}
|
|
||||||
for (int y = height - 5; y <= height - 1; y++) {
|
|
||||||
if (y > 110) {
|
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
|
||||||
} else {
|
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (height > 110) {
|
|
||||||
m_blocks[Chunk::get_index(x, height, z)] = 3;
|
|
||||||
} else {
|
|
||||||
m_blocks[Chunk::get_index(x, height, z)] = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ void PlainBuilder::build_blocks() {
|
|||||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||||
int height = static_cast<int>(m_heightmap[x][z]);
|
int height = static_cast<int>(m_heightmap[x][z]);
|
||||||
for (int y = 5; y < height - 5; y++) {
|
for (int y = 5; y < height - 5; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||||
}
|
}
|
||||||
for (int y = height - 5; y < height; y++) {
|
for (int y = height - 5; y < height; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 2;
|
m_blocks[Chunk::index(x, y, z)] = 2;
|
||||||
}
|
}
|
||||||
m_blocks[Chunk::get_index(x, height, z)] = 1;
|
m_blocks[Chunk::index(x, height, z)] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,16 +19,16 @@ void RiverBuilder::build_blocks() {
|
|||||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||||
int height = static_cast<int>(m_heightmap[x][z]);
|
int height = static_cast<int>(m_heightmap[x][z]);
|
||||||
for (int y = 5; y < height - 5; y++) {
|
for (int y = 5; y < height - 5; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||||
}
|
}
|
||||||
for (int y = height - 5; y <= height - 1; y++) {
|
for (int y = height - 5; y <= height - 1; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 2;
|
m_blocks[Chunk::index(x, y, z)] = 2;
|
||||||
}
|
}
|
||||||
for (int y = height; y <= height; y++) {
|
for (int y = height; y <= height; y++) {
|
||||||
if (y >= SEA_LEVEL - 1) {
|
if (y >= SEA_LEVEL - 1) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 1;
|
m_blocks[Chunk::index(x, y, z)] = 1;
|
||||||
} else {
|
} else {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 2;
|
m_blocks[Chunk::index(x, y, z)] = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ void RiverBuilder::build_vegetation() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (int y = height + 1; y < SEA_LEVEL; y++) {
|
for (int y = height + 1; y < SEA_LEVEL; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = 7;
|
m_blocks[Chunk::index(x, y, z)] = 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/gameplay/builders/snowy_plain_builder.cpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include "Cubed/gameplay/builders/snowy_plain_builder.hpp"
|
||||||
|
|
||||||
|
#include "Cubed/gameplay/chunk.hpp"
|
||||||
|
#include "Cubed/gameplay/chunk_generator.hpp"
|
||||||
|
namespace Cubed {
|
||||||
|
SnowyPlainBuilder::SnowyPlainBuilder(ChunkGenerator& chunk_generator)
|
||||||
|
: m_chunk_generator(chunk_generator) {}
|
||||||
|
|
||||||
|
void SnowyPlainBuilder::build_biome() {
|
||||||
|
BiomeBuilder::build_bottom();
|
||||||
|
build_blocks();
|
||||||
|
};
|
||||||
|
|
||||||
|
void SnowyPlainBuilder::build_blocks() {
|
||||||
|
auto& m_chunk = m_chunk_generator.chunk();
|
||||||
|
auto& m_blocks = m_chunk.blocks();
|
||||||
|
auto& m_heightmap = m_chunk.heightmap();
|
||||||
|
for (int x = 0; x < CHUNK_SIZE; x++) {
|
||||||
|
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||||
|
int height = static_cast<int>(m_heightmap[x][z]);
|
||||||
|
for (int y = 5; y < height - 5; y++) {
|
||||||
|
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||||
|
}
|
||||||
|
for (int y = height - 5; y < height; y++) {
|
||||||
|
m_blocks[Chunk::index(x, y, z)] = 2;
|
||||||
|
}
|
||||||
|
m_blocks[Chunk::index(x, height, z)] = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnowyPlainBuilder::build_vegetation() { fill_water(); }
|
||||||
|
|
||||||
|
ChunkGenerator& SnowyPlainBuilder::get_chunk_generator() {
|
||||||
|
return m_chunk_generator;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
@@ -24,7 +24,8 @@ Chunk::Chunk(Chunk&& other) noexcept
|
|||||||
m_chunk_pos(std::move(other.m_chunk_pos)), m_world(other.m_world),
|
m_chunk_pos(std::move(other.m_chunk_pos)), m_world(other.m_world),
|
||||||
m_heightmap(std::move(other.m_heightmap)),
|
m_heightmap(std::move(other.m_heightmap)),
|
||||||
m_blocks(std::move(other.m_blocks)), m_vbo(other.m_vbo),
|
m_blocks(std::move(other.m_blocks)), m_vbo(other.m_vbo),
|
||||||
m_vertexs_data(std::move(other.m_vertexs_data)), m_seed(other.m_seed) {
|
m_vertexs_data(std::move(other.m_vertexs_data)), m_seed(other.m_seed),
|
||||||
|
m_conditions(other.m_conditions) {
|
||||||
other.m_vbo = 0;
|
other.m_vbo = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,14 +45,46 @@ Chunk& Chunk::operator=(Chunk&& other) noexcept {
|
|||||||
m_need_upload = other.m_need_upload.load();
|
m_need_upload = other.m_need_upload.load();
|
||||||
m_vertex_sum = other.m_vertex_sum.load();
|
m_vertex_sum = other.m_vertex_sum.load();
|
||||||
m_seed = other.m_seed;
|
m_seed = other.m_seed;
|
||||||
|
m_conditions = other.m_conditions;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::tuple<int, int, int> Chunk::world_to_block(int world_x, int world_y,
|
||||||
|
int world_z, int chunk_x,
|
||||||
|
int chunk_z) {
|
||||||
|
int x, y, z;
|
||||||
|
y = world_y;
|
||||||
|
x = world_x - chunk_x * CHUNK_SIZE;
|
||||||
|
z = world_z - chunk_z * CHUNK_SIZE;
|
||||||
|
return {x, y, z};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<int, int, int> Chunk::world_to_block(const glm::ivec3& block_pos,
|
||||||
|
ChunkPos chunk_pos) {
|
||||||
|
return world_to_block(block_pos.x, block_pos.y, block_pos.z, chunk_pos.x,
|
||||||
|
chunk_pos.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<int, int, int> Chunk::block_to_world(int x, int y, int z,
|
||||||
|
int chunk_x, int chunk_z) {
|
||||||
|
int world_x = x + chunk_x * CHUNK_SIZE;
|
||||||
|
int world_z = z + chunk_z * CHUNK_SIZE;
|
||||||
|
int world_y = y;
|
||||||
|
return {world_x, world_y, world_z};
|
||||||
|
}
|
||||||
|
std::tuple<int, int, int> Chunk::block_to_world(const glm::ivec3& block_pos,
|
||||||
|
ChunkPos chunk_pos) {
|
||||||
|
return block_to_world(block_pos.x, block_pos.y, block_pos.z, chunk_pos.x,
|
||||||
|
chunk_pos.z);
|
||||||
|
}
|
||||||
|
|
||||||
BiomeType Chunk::get_biome() const { return m_biome.load(); }
|
BiomeType Chunk::get_biome() const { return m_biome.load(); }
|
||||||
|
|
||||||
ChunkPos Chunk::get_chunk_pos() const { return m_chunk_pos; }
|
ChunkPos Chunk::get_chunk_pos() const { return m_chunk_pos; }
|
||||||
|
|
||||||
const std::vector<uint8_t>& Chunk::get_chunk_blocks() const { return m_blocks; }
|
const std::vector<BlockType>& Chunk::get_chunk_blocks() const {
|
||||||
|
return m_blocks;
|
||||||
|
}
|
||||||
|
|
||||||
HeightMapArray Chunk::get_heightmap() const {
|
HeightMapArray Chunk::get_heightmap() const {
|
||||||
// Logger::info("Chunk pos {} {} in get_heightmap this {}", m_chunk_pos.x,
|
// Logger::info("Chunk pos {} {} in get_heightmap this {}", m_chunk_pos.x,
|
||||||
@@ -59,7 +92,7 @@ HeightMapArray Chunk::get_heightmap() const {
|
|||||||
return m_heightmap;
|
return m_heightmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Chunk::get_index(int x, int y, int z) {
|
int Chunk::index(int x, int y, int z) {
|
||||||
ASSERT(!(x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
ASSERT(!(x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
||||||
z >= CHUNK_SIZE));
|
z >= CHUNK_SIZE));
|
||||||
if ((x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z < 0 ||
|
if ((x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z < 0 ||
|
||||||
@@ -71,12 +104,12 @@ int Chunk::get_index(int x, int y, int z) {
|
|||||||
return (x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z;
|
return (x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Chunk::get_index(const glm::vec3& pos) {
|
int Chunk::index(const glm::vec3& pos) {
|
||||||
return Chunk::get_index(pos.x, pos.y, pos.z);
|
return Chunk::index(pos.x, pos.y, pos.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chunk::gen_vertex_data(
|
void Chunk::gen_vertex_data(
|
||||||
const std::array<const std::vector<uint8_t>*, 4>& neighbor_block) {
|
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;
|
||||||
}
|
}
|
||||||
@@ -93,7 +126,7 @@ void Chunk::gen_vertex_data(
|
|||||||
int world_x = x + m_chunk_pos.x * CHUNK_SIZE;
|
int world_x = x + m_chunk_pos.x * CHUNK_SIZE;
|
||||||
int world_z = z + m_chunk_pos.z * CHUNK_SIZE;
|
int world_z = z + m_chunk_pos.z * CHUNK_SIZE;
|
||||||
int world_y = y;
|
int world_y = y;
|
||||||
int cur_id = m_blocks[get_index(x, y, z)];
|
int cur_id = m_blocks[index(x, y, z)];
|
||||||
// air
|
// air
|
||||||
if (cur_id == 0) {
|
if (cur_id == 0) {
|
||||||
continue;
|
continue;
|
||||||
@@ -116,7 +149,7 @@ void Chunk::gen_vertex_data(
|
|||||||
World::chunk_pos(world_nx, world_nz);
|
World::chunk_pos(world_nx, world_nz);
|
||||||
|
|
||||||
auto is_cull =
|
auto is_cull =
|
||||||
[&](const std::vector<uint8_t>* chunk_blocks) {
|
[&](const std::vector<BlockType>* chunk_blocks) {
|
||||||
if (chunk_blocks == nullptr) {
|
if (chunk_blocks == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -130,12 +163,12 @@ void Chunk::gen_vertex_data(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = Chunk::get_index(x, y, z);
|
int idx = Chunk::index(x, y, z);
|
||||||
// not init
|
// not init
|
||||||
if (static_cast<size_t>(idx) >=
|
if (static_cast<size_t>(idx) >=
|
||||||
chunk_blocks->size()) {
|
chunk_blocks->size()) {
|
||||||
Logger::warn("not init");
|
// Logger::warn("not init");
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
auto id = (*chunk_blocks)[idx];
|
auto id = (*chunk_blocks)[idx];
|
||||||
if (is_in_transparent_map(id)) {
|
if (is_in_transparent_map(id)) {
|
||||||
@@ -162,7 +195,7 @@ void Chunk::gen_vertex_data(
|
|||||||
// neighbor_cull = m_world.is_block(glm::ivec3(world_x,
|
// neighbor_cull = m_world.is_block(glm::ivec3(world_x,
|
||||||
// world_y, world_z) + DIR[face]);
|
// world_y, world_z) + DIR[face]);
|
||||||
} else {
|
} else {
|
||||||
auto id = m_blocks[get_index(nx, ny, nz)];
|
auto id = m_blocks[index(nx, ny, nz)];
|
||||||
if (!is_in_transparent_map(id)) {
|
if (!is_in_transparent_map(id)) {
|
||||||
neighbor_cull = true;
|
neighbor_cull = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -222,7 +255,7 @@ void Chunk::gen_phase_two(const std::array<const Chunk*, 8>& adj_chunks) {
|
|||||||
Logger::error("ChunkGenerator is Nullptr");
|
Logger::error("ChunkGenerator is Nullptr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_generator->resolve_biome_adjacency_conflict(adj_chunks);
|
// m_generator->resolve_biome_adjacency_conflict(adj_chunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chunk::gen_phase_three() {
|
void Chunk::gen_phase_three() {
|
||||||
@@ -240,7 +273,8 @@ void Chunk::gen_phase_four(
|
|||||||
Logger::error("ChunkGenerator is Nullptr");
|
Logger::error("ChunkGenerator is Nullptr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_generator->blend_heightmap_boundaries(neighbor_heightmap, neighbor_biome);
|
// m_generator->blend_heightmap_boundaries(neighbor_heightmap,
|
||||||
|
// neighbor_biome);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chunk::gen_phase_five() {
|
void Chunk::gen_phase_five() {
|
||||||
@@ -252,12 +286,14 @@ void Chunk::gen_phase_five() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Chunk::gen_phase_six(
|
void Chunk::gen_phase_six(
|
||||||
const std::array<std::optional<std::vector<uint8_t>>, 4>& neighbor_block) {
|
const std::array<std::optional<std::vector<BlockType>>, 4>&
|
||||||
|
neighbor_block) {
|
||||||
if (!m_generator) {
|
if (!m_generator) {
|
||||||
Logger::error("ChunkGenerator is Nullptr");
|
Logger::error("ChunkGenerator is Nullptr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// m_generator->blend_surface_blocks_borders(neighbor_block);
|
m_generator->blend_surface_blocks_borders(neighbor_block);
|
||||||
|
m_generator->generate_cave();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chunk::gen_phase_seven() {
|
void Chunk::gen_phase_seven() {
|
||||||
@@ -308,7 +344,7 @@ BiomeType Chunk::biome() const { return m_biome; }
|
|||||||
void Chunk::biome(BiomeType b) { m_biome = b; }
|
void Chunk::biome(BiomeType b) { m_biome = b; }
|
||||||
|
|
||||||
HeightMapArray& Chunk::heightmap() { return m_heightmap; }
|
HeightMapArray& Chunk::heightmap() { return m_heightmap; }
|
||||||
std::vector<uint8_t>& Chunk::blocks() { return m_blocks; }
|
std::vector<BlockType>& Chunk::blocks() { return m_blocks; }
|
||||||
World& Chunk::world() { return m_world; }
|
World& Chunk::world() { return m_world; }
|
||||||
unsigned Chunk::seed() const {
|
unsigned Chunk::seed() const {
|
||||||
if (m_seed == 0) {
|
if (m_seed == 0) {
|
||||||
@@ -316,4 +352,7 @@ unsigned Chunk::seed() const {
|
|||||||
}
|
}
|
||||||
return m_seed;
|
return m_seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BiomeConditions& Chunk::conditions() { return m_conditions; }
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
#include "Cubed/gameplay/builders/mountain_builder.hpp"
|
#include "Cubed/gameplay/builders/mountain_builder.hpp"
|
||||||
#include "Cubed/gameplay/builders/plain_builder.hpp"
|
#include "Cubed/gameplay/builders/plain_builder.hpp"
|
||||||
#include "Cubed/gameplay/builders/river_builder.hpp"
|
#include "Cubed/gameplay/builders/river_builder.hpp"
|
||||||
|
#include "Cubed/gameplay/builders/snowy_plain_builder.hpp"
|
||||||
#include "Cubed/gameplay/chunk.hpp"
|
#include "Cubed/gameplay/chunk.hpp"
|
||||||
#include "Cubed/gameplay/tree.hpp"
|
#include "Cubed/gameplay/tree.hpp"
|
||||||
#include "Cubed/gameplay/world.hpp"
|
#include "Cubed/gameplay/world.hpp"
|
||||||
#include "Cubed/tools/cubed_hash.hpp"
|
#include "Cubed/tools/cubed_hash.hpp"
|
||||||
|
#include "Cubed/tools/math_tools.hpp"
|
||||||
#include "Cubed/tools/perlin_noise.hpp"
|
#include "Cubed/tools/perlin_noise.hpp"
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
@@ -27,7 +29,8 @@ void ChunkGenerator::init() {
|
|||||||
std::random_device d;
|
std::random_device d;
|
||||||
m_generator_seed = d();
|
m_generator_seed = d();
|
||||||
Logger::info("Chunk Generator Seed {}", m_generator_seed);
|
Logger::info("Chunk Generator Seed {}", m_generator_seed);
|
||||||
PerlinNoise::init(m_generator_seed);
|
PerlinNoise3D::init(m_generator_seed);
|
||||||
|
PerlinNoise2D::init(m_generator_seed);
|
||||||
is_init = true;
|
is_init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +38,7 @@ void ChunkGenerator::reload() {
|
|||||||
if (!is_seed_change) {
|
if (!is_seed_change) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PerlinNoise::reload(m_generator_seed);
|
PerlinNoise3D::reload(m_generator_seed);
|
||||||
is_seed_change = false;
|
is_seed_change = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,11 +57,20 @@ void ChunkGenerator::assign_chunk_biome() {
|
|||||||
auto m_chunk_pos = m_chunk.chunk_pos();
|
auto m_chunk_pos = m_chunk.chunk_pos();
|
||||||
float x = static_cast<float>(m_chunk_pos.x);
|
float x = static_cast<float>(m_chunk_pos.x);
|
||||||
float z = static_cast<float>(m_chunk_pos.z);
|
float z = static_cast<float>(m_chunk_pos.z);
|
||||||
float temp = PerlinNoise::noise(x * BIOME_NOISE_FREQUENCY, 0.0f,
|
float temp = PerlinNoise3D::noise(x * BIOME_NOISE_FREQUENCY, 0.0f,
|
||||||
z * BIOME_NOISE_FREQUENCY);
|
z * BIOME_NOISE_FREQUENCY);
|
||||||
float humid = PerlinNoise::noise(x * BIOME_NOISE_FREQUENCY, 1.0f,
|
float humid = PerlinNoise3D::noise(x * BIOME_NOISE_FREQUENCY, 1.0f,
|
||||||
z * BIOME_NOISE_FREQUENCY);
|
z * BIOME_NOISE_FREQUENCY);
|
||||||
auto biome = get_biome_from_noise(temp, humid);
|
float center_x = static_cast<float>(SIZE_X / 2) + x * CHUNK_SIZE + 0.5f;
|
||||||
|
float center_z = static_cast<float>(SIZE_Z / 2) + z * CHUNK_SIZE + 0.5f;
|
||||||
|
float mountainous =
|
||||||
|
PerlinNoise2D::noise(center_x * MOUNTAINOUS_NOISE_FREQUENCY,
|
||||||
|
center_z * MOUNTAINOUS_NOISE_FREQUENCY);
|
||||||
|
auto& conditions = m_chunk.conditions();
|
||||||
|
conditions.mountainous = mountainous;
|
||||||
|
conditions.humid = humid;
|
||||||
|
conditions.temp = temp;
|
||||||
|
auto biome = determine_biome(conditions);
|
||||||
m_chunk.biome(biome);
|
m_chunk.biome(biome);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +98,7 @@ void ChunkGenerator::resolve_biome_adjacency_conflict(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
void ChunkGenerator::generate_heightmap() {
|
void ChunkGenerator::generate_heightmap() {
|
||||||
|
|
||||||
auto m_chunk_pos = m_chunk.chunk_pos();
|
auto m_chunk_pos = m_chunk.chunk_pos();
|
||||||
@@ -114,6 +127,63 @@ void ChunkGenerator::generate_heightmap() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ChunkGenerator::generate_heightmap() {
|
||||||
|
auto chunk_pos = m_chunk.chunk_pos();
|
||||||
|
auto& heightmap = m_chunk.heightmap();
|
||||||
|
|
||||||
|
for (int x = 0; x < CHUNK_SIZE; ++x) {
|
||||||
|
for (int z = 0; z < CHUNK_SIZE; ++z) {
|
||||||
|
float world_x = static_cast<float>(x + chunk_pos.x * CHUNK_SIZE);
|
||||||
|
float world_z = static_cast<float>(z + chunk_pos.z * CHUNK_SIZE);
|
||||||
|
|
||||||
|
auto fbm_height = [](float x, float y, int octaves,
|
||||||
|
float lacunarity, float gain, float amplitude,
|
||||||
|
float frequency) -> float {
|
||||||
|
float value = 0.0f;
|
||||||
|
for (int i = 0; i < octaves; i++) {
|
||||||
|
value += amplitude *
|
||||||
|
PerlinNoise2D::noise(x * frequency, y * frequency);
|
||||||
|
frequency *= lacunarity;
|
||||||
|
amplitude *= gain;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
int octaves = 4;
|
||||||
|
float lacunarity = 2.0f;
|
||||||
|
float gain = 0.5f;
|
||||||
|
float base_y = 64;
|
||||||
|
float amplitude = 40.0f;
|
||||||
|
float mountainous =
|
||||||
|
PerlinNoise2D::noise(world_x * MOUNTAINOUS_NOISE_FREQUENCY,
|
||||||
|
world_z * MOUNTAINOUS_NOISE_FREQUENCY);
|
||||||
|
/*
|
||||||
|
float t = Math::smootherstep(0.6, 0.7, mountainous);
|
||||||
|
base_y = std::lerp(64, 85, t);
|
||||||
|
amplitude = std::lerp(10, 40, t);
|
||||||
|
*/
|
||||||
|
float t;
|
||||||
|
if (mountainous >= 0.7f) {
|
||||||
|
t = Math::smootherstep(0.7f, 0.75, mountainous);
|
||||||
|
base_y = std::lerp(70, 88, t);
|
||||||
|
amplitude = std::lerp(28, 48, t);
|
||||||
|
} else if (mountainous >= 0.65f) {
|
||||||
|
t = Math::smootherstep(0.65f, 0.7f, mountainous);
|
||||||
|
base_y = std::lerp(66, 70, t);
|
||||||
|
amplitude = std::lerp(18, 28, t);
|
||||||
|
} else {
|
||||||
|
t = Math::smootherstep(0.55, 0.65, mountainous);
|
||||||
|
base_y = std::lerp(58, 66, t);
|
||||||
|
amplitude = std::lerp(8, 18, t);
|
||||||
|
}
|
||||||
|
heightmap[x][z] =
|
||||||
|
base_y + fbm_height(world_x, world_z, octaves, lacunarity, gain,
|
||||||
|
amplitude, 0.005f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ChunkGenerator::blend_heightmap_boundaries(
|
void ChunkGenerator::blend_heightmap_boundaries(
|
||||||
const std::array<std::optional<HeightMapArray>, 8>& neighbor_heightmap,
|
const std::array<std::optional<HeightMapArray>, 8>& neighbor_heightmap,
|
||||||
@@ -362,11 +432,11 @@ void ChunkGenerator::generate_terrain_blocks() {
|
|||||||
}
|
}
|
||||||
m_chunk.blocks().assign(CHUNK_SIZE * CHUNK_SIZE * WORLD_SIZE_Y, 0);
|
m_chunk.blocks().assign(CHUNK_SIZE * CHUNK_SIZE * WORLD_SIZE_Y, 0);
|
||||||
m_biome_builder->build_biome();
|
m_biome_builder->build_biome();
|
||||||
generate_cave();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkGenerator::blend_surface_blocks_borders(
|
void ChunkGenerator::blend_surface_blocks_borders(
|
||||||
const std::array<std::optional<std::vector<uint8_t>>, 4>& neighbor_block) {
|
const std::array<std::optional<std::vector<BlockType>>, 4>&
|
||||||
|
neighbor_block) {
|
||||||
auto& m_blocks = m_chunk.blocks();
|
auto& m_blocks = m_chunk.blocks();
|
||||||
auto& m_heightmap = m_chunk.heightmap();
|
auto& m_heightmap = m_chunk.heightmap();
|
||||||
|
|
||||||
@@ -374,12 +444,12 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
|
|
||||||
// Helper lambda: get top block type from a neighbor's block data at (nx,
|
// Helper lambda: get top block type from a neighbor's block data at (nx,
|
||||||
// nz)
|
// nz)
|
||||||
auto get_top_block_from_neighbor = [&](const std::vector<uint8_t>& blocks,
|
auto get_top_block_from_neighbor = [&](const std::vector<BlockType>& blocks,
|
||||||
int nx, int nz) -> uint8_t {
|
int nx, int nz) -> BlockType {
|
||||||
// Search from topmost y downwards for the first non-zero block
|
// Search from topmost y downwards for the first non-zero block
|
||||||
for (int y = WORLD_HEIGHT - 1; y >= 0; --y) {
|
for (int y = WORLD_HEIGHT - 1; y >= 0; --y) {
|
||||||
int idx = Chunk::get_index(
|
int idx = Chunk::index(nx, y,
|
||||||
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()) &&
|
||||||
blocks[idx] != 0) {
|
blocks[idx] != 0) {
|
||||||
return blocks[idx];
|
return blocks[idx];
|
||||||
@@ -392,16 +462,16 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
for (int x = 0; x < CHUNK_SIZE; ++x) {
|
for (int x = 0; x < CHUNK_SIZE; ++x) {
|
||||||
for (int z = 0; z < CHUNK_SIZE; ++z) {
|
for (int z = 0; z < CHUNK_SIZE; ++z) {
|
||||||
// Get the current top block type of this column from m_blocks
|
// Get the current top block type of this column from m_blocks
|
||||||
uint8_t type_self = 0;
|
BlockType type_self = 0;
|
||||||
int top_y = -1;
|
int top_y = -1;
|
||||||
top_y = m_heightmap[x][z];
|
top_y = m_heightmap[x][z];
|
||||||
type_self = m_blocks[Chunk::get_index(x, top_y, z)];
|
type_self = m_blocks[Chunk::index(x, top_y, z)];
|
||||||
|
|
||||||
if (top_y == -1)
|
if (top_y == -1)
|
||||||
continue; // no block? skip
|
continue; // no block? skip
|
||||||
|
|
||||||
// Weight map: type -> total weight
|
// Weight map: type -> total weight
|
||||||
std::unordered_map<uint8_t, float> weights;
|
std::unordered_map<BlockType, float> weights;
|
||||||
weights[type_self] = 1.0f; // self weight
|
weights[type_self] = 1.0f; // self weight
|
||||||
|
|
||||||
// --- Right neighbor (index 0) ---
|
// --- Right neighbor (index 0) ---
|
||||||
@@ -410,7 +480,7 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS;
|
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS;
|
||||||
t = t * t * (3.0f - 2.0f * t); // smoothstep
|
t = t * t * (3.0f - 2.0f * t); // smoothstep
|
||||||
if (t > 0.0f) {
|
if (t > 0.0f) {
|
||||||
uint8_t type_neighbor =
|
BlockType type_neighbor =
|
||||||
get_top_block_from_neighbor(*neighbor_block[0], 0, z);
|
get_top_block_from_neighbor(*neighbor_block[0], 0, z);
|
||||||
weights[type_neighbor] += t;
|
weights[type_neighbor] += t;
|
||||||
}
|
}
|
||||||
@@ -422,7 +492,7 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS;
|
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS;
|
||||||
t = t * t * (3.0f - 2.0f * t);
|
t = t * t * (3.0f - 2.0f * t);
|
||||||
if (t > 0.0f) {
|
if (t > 0.0f) {
|
||||||
uint8_t type_neighbor = get_top_block_from_neighbor(
|
BlockType type_neighbor = get_top_block_from_neighbor(
|
||||||
*neighbor_block[1], CHUNK_SIZE - 1, z);
|
*neighbor_block[1], CHUNK_SIZE - 1, z);
|
||||||
weights[type_neighbor] += t;
|
weights[type_neighbor] += t;
|
||||||
}
|
}
|
||||||
@@ -434,7 +504,7 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS;
|
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS;
|
||||||
t = t * t * (3.0f - 2.0f * t);
|
t = t * t * (3.0f - 2.0f * t);
|
||||||
if (t > 0.0f) {
|
if (t > 0.0f) {
|
||||||
uint8_t type_neighbor =
|
BlockType type_neighbor =
|
||||||
get_top_block_from_neighbor(*neighbor_block[2], x, 0);
|
get_top_block_from_neighbor(*neighbor_block[2], x, 0);
|
||||||
weights[type_neighbor] += t;
|
weights[type_neighbor] += t;
|
||||||
}
|
}
|
||||||
@@ -446,14 +516,14 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS;
|
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS;
|
||||||
t = t * t * (3.0f - 2.0f * t);
|
t = t * t * (3.0f - 2.0f * t);
|
||||||
if (t > 0.0f) {
|
if (t > 0.0f) {
|
||||||
uint8_t type_neighbor = get_top_block_from_neighbor(
|
BlockType type_neighbor = get_top_block_from_neighbor(
|
||||||
*neighbor_block[3], x, CHUNK_SIZE - 1);
|
*neighbor_block[3], x, CHUNK_SIZE - 1);
|
||||||
weights[type_neighbor] += t;
|
weights[type_neighbor] += t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find type with maximum total weight
|
// Find type with maximum total weight
|
||||||
uint8_t 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) {
|
||||||
@@ -462,6 +532,10 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (final_type == 0) {
|
||||||
|
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
|
||||||
@@ -469,7 +543,7 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
final_type = 2;
|
final_type = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_blocks[Chunk::get_index(x, top_y, z)] = final_type;
|
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) {
|
if (final_type == 1) {
|
||||||
@@ -478,7 +552,7 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
|||||||
fill_type = 4;
|
fill_type = 4;
|
||||||
}
|
}
|
||||||
for (int y = top_y - 5; y < top_y; y++) {
|
for (int y = top_y - 5; y < top_y; y++) {
|
||||||
m_blocks[Chunk::get_index(x, y, z)] = fill_type;
|
m_blocks[Chunk::index(x, y, z)] = fill_type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -512,6 +586,9 @@ void ChunkGenerator::make_biome_builder() {
|
|||||||
case RIVER:
|
case RIVER:
|
||||||
m_biome_builder = std::make_unique<RiverBuilder>(*this);
|
m_biome_builder = std::make_unique<RiverBuilder>(*this);
|
||||||
break;
|
break;
|
||||||
|
case SNOWY_PLAIN:
|
||||||
|
m_biome_builder = std::make_unique<SnowyPlainBuilder>(*this);
|
||||||
|
break;
|
||||||
case NONE:
|
case NONE:
|
||||||
m_biome_builder = nullptr;
|
m_biome_builder = nullptr;
|
||||||
break;
|
break;
|
||||||
@@ -563,7 +640,7 @@ void ChunkGenerator::generate_cave() {
|
|||||||
if (y == 0) {
|
if (y == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
blocks[Chunk::get_index(x, y, z)] = 0;
|
blocks[Chunk::index(x, y, z)] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ static constexpr std::array<TreeStructNode, 62> TREE{{
|
|||||||
bool build_tree(Chunk& chunk, const glm::ivec3& pos) {
|
bool build_tree(Chunk& chunk, const glm::ivec3& pos) {
|
||||||
auto& block = chunk.get_chunk_blocks();
|
auto& block = chunk.get_chunk_blocks();
|
||||||
|
|
||||||
if (block[Chunk::get_index(pos)] != 1) {
|
if (block[Chunk::index(pos)] != 1) {
|
||||||
Logger::info("Root is not Grass Block");
|
Logger::info("Root is not Grass Block");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -43,13 +43,13 @@ bool build_tree(Chunk& chunk, const glm::ivec3& pos) {
|
|||||||
z >= CHUNK_SIZE) {
|
z >= CHUNK_SIZE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (block[Chunk::get_index(tree_node)] != 0) {
|
if (block[Chunk::index(tree_node)] != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto& d : TREE) {
|
for (const auto& d : TREE) {
|
||||||
auto tree_node = pos + d.offset;
|
auto tree_node = pos + d.offset;
|
||||||
chunk.set_chunk_block(Chunk::get_index(tree_node), d.id);
|
chunk.set_chunk_block(Chunk::index(tree_node), d.id);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
struct ChunkRenderData {
|
struct ChunkRenderData {
|
||||||
std::array<const std::vector<uint8_t>*, 4> neighbor_block;
|
std::array<const std::vector<BlockType>*, 4> neighbor_block;
|
||||||
Chunk* chunk;
|
Chunk* chunk;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,6 +86,7 @@ void World::init_chunks() {
|
|||||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
void World::init_chunks() {
|
void World::init_chunks() {
|
||||||
|
|
||||||
@@ -230,7 +231,7 @@ void World::init_chunks() {
|
|||||||
for (auto& [pos, chunks] : temp_neighbor) {
|
for (auto& [pos, chunks] : temp_neighbor) {
|
||||||
chunks.gen_phase_five();
|
chunks.gen_phase_five();
|
||||||
}
|
}
|
||||||
std::array<std::optional<std::vector<uint8_t>>, 4> neighbor_block;
|
std::array<std::optional<std::vector<BlockType>>, 4> neighbor_block;
|
||||||
for (auto& [pos, chunks] : m_chunks) {
|
for (auto& [pos, chunks] : m_chunks) {
|
||||||
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];
|
||||||
@@ -332,6 +333,8 @@ ChunkPos World::chunk_pos(int world_x, int world_z) {
|
|||||||
return {chunk_x, chunk_z};
|
return {chunk_x, chunk_z};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma region ChunkGenerate
|
||||||
|
|
||||||
void World::gen_chunks_internal() {
|
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;
|
||||||
@@ -344,35 +347,43 @@ void World::gen_chunks_internal() {
|
|||||||
sync_and_collect_missing_chunks(need_gen_chunks_pos, required_chunks);
|
sync_and_collect_missing_chunks(need_gen_chunks_pos, required_chunks);
|
||||||
|
|
||||||
Logger::info("New Gen Chunks Sum: {}", need_gen_chunks_pos.size());
|
Logger::info("New Gen Chunks Sum: {}", need_gen_chunks_pos.size());
|
||||||
|
|
||||||
if (need_gen_chunks_pos.empty()) {
|
if (need_gen_chunks_pos.empty()) {
|
||||||
m_could_gen = true;
|
m_could_gen = true;
|
||||||
m_chunk_gen_fraction = 1.0f;
|
m_chunk_gen_fraction = 1.0f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_chunk_gen_fraction = 0.1f;
|
m_chunk_gen_fraction = 0.1f;
|
||||||
|
|
||||||
ChunkUpdateList new_chunks;
|
ChunkUpdateList new_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)});
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstChunkMap new_chunks_neighbor;
|
ConstChunkMap new_chunks_neighbor;
|
||||||
// affected neighbor
|
// affected neighbor
|
||||||
ChunkPtrUpdateList affected_neighbor;
|
ChunkPtrUpdateList affected_neighbor;
|
||||||
ChunkHashMap temp_neighbor;
|
ChunkHashMap temp_neighbor;
|
||||||
|
|
||||||
build_neighbor_context_for_new_chunks(
|
build_neighbor_context_for_new_chunks(
|
||||||
new_chunks_neighbor, affected_neighbor, new_chunks, temp_neighbor);
|
new_chunks_neighbor, affected_neighbor, new_chunks, temp_neighbor);
|
||||||
Logger::info("Temp neighbor sum {}", temp_neighbor.size());
|
|
||||||
// build new chunk, but the neighbor in m_chunks also need to re-build
|
// Logger::info("Temp neighbor sum {}", temp_neighbor.size());
|
||||||
|
// build new chunk, but the neighbor in m_chunks also need to re-build
|
||||||
|
|
||||||
for (auto& [pos, chunk] : new_chunks) {
|
for (auto& [pos, chunk] : new_chunks) {
|
||||||
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());
|
||||||
}
|
}
|
||||||
for (auto& [pos, chunk] : temp_neighbor) {
|
|
||||||
chunk.gen_phase_one();
|
// for (auto& [pos, chunk] : temp_neighbor) {
|
||||||
m_cave_carcer.try_to_add_path(pos, chunk.seed());
|
// chunk.gen_phase_one();
|
||||||
}
|
// m_cave_carcer.try_to_add_path(pos, chunk.seed());
|
||||||
|
// }
|
||||||
|
|
||||||
m_chunk_gen_fraction = 0.2f;
|
m_chunk_gen_fraction = 0.2f;
|
||||||
|
|
||||||
std::array<const Chunk*, 8> neighbor_chunks;
|
std::array<const Chunk*, 8> neighbor_chunks;
|
||||||
for (auto& [pos, chunks] : new_chunks) {
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
@@ -387,6 +398,8 @@ void World::gen_chunks_internal() {
|
|||||||
}
|
}
|
||||||
chunks.gen_phase_two(neighbor_chunks);
|
chunks.gen_phase_two(neighbor_chunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
for (auto& [pos, chunks] : temp_neighbor) {
|
for (auto& [pos, chunks] : temp_neighbor) {
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
auto neighbor_pos = pos + CHUNK_DIR[i];
|
auto neighbor_pos = pos + CHUNK_DIR[i];
|
||||||
@@ -399,14 +412,20 @@ void World::gen_chunks_internal() {
|
|||||||
}
|
}
|
||||||
chunks.gen_phase_two(neighbor_chunks);
|
chunks.gen_phase_two(neighbor_chunks);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
m_chunk_gen_fraction = 0.3f;
|
m_chunk_gen_fraction = 0.3f;
|
||||||
|
|
||||||
for (auto& [pos, chunks] : new_chunks) {
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
chunks.gen_phase_three();
|
chunks.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;
|
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) {
|
||||||
std::array<std::optional<HeightMapArray>, 8>
|
std::array<std::optional<HeightMapArray>, 8>
|
||||||
@@ -448,15 +467,20 @@ void World::gen_chunks_internal() {
|
|||||||
chunks.gen_phase_four(neighbor_chunk_heightmap, neighbor_biome);
|
chunks.gen_phase_four(neighbor_chunk_heightmap, neighbor_biome);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
m_chunk_gen_fraction = 0.5f;
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
for (auto& [pos, chunks] : temp_neighbor) {
|
for (auto& [pos, chunks] : temp_neighbor) {
|
||||||
chunks.gen_phase_five();
|
chunks.gen_phase_five();
|
||||||
}
|
}
|
||||||
std::array<std::optional<std::vector<uint8_t>>, 4> neighbor_blocks_data;
|
*/
|
||||||
|
|
||||||
|
std::array<std::optional<std::vector<BlockType>>, 4> neighbor_blocks_data;
|
||||||
for (auto& [pos, chunks] : new_chunks) {
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
{
|
{
|
||||||
// std::lock_guard lk(m_chunks_mutex);
|
// std::lock_guard lk(m_chunks_mutex);
|
||||||
@@ -472,12 +496,14 @@ void World::gen_chunks_internal() {
|
|||||||
}
|
}
|
||||||
chunks.gen_phase_six(neighbor_blocks_data);
|
chunks.gen_phase_six(neighbor_blocks_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& [pos, chunks] : new_chunks) {
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
chunks.gen_phase_seven();
|
chunks.gen_phase_seven();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_chunk_gen_fraction = 0.6f;
|
m_chunk_gen_fraction = 0.6f;
|
||||||
std::array<const std::vector<uint8_t>*, 4> neighbor_block;
|
|
||||||
|
std::array<const std::vector<BlockType>*, 4> neighbor_block;
|
||||||
for (auto& [pos, chunk] : new_chunks) {
|
for (auto& [pos, chunk] : new_chunks) {
|
||||||
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]);
|
||||||
@@ -489,10 +515,14 @@ void World::gen_chunks_internal() {
|
|||||||
}
|
}
|
||||||
chunk.gen_vertex_data(neighbor_block);
|
chunk.gen_vertex_data(neighbor_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
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]);
|
||||||
@@ -505,7 +535,9 @@ void World::gen_chunks_internal() {
|
|||||||
chunk->gen_vertex_data(neighbor_block);
|
chunk->gen_vertex_data(neighbor_block);
|
||||||
chunk->need_upload();
|
chunk->need_upload();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_chunk_gen_fraction = 0.9f;
|
m_chunk_gen_fraction = 0.9f;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard lk(m_new_chunk_queue_mutex);
|
std::lock_guard lk(m_new_chunk_queue_mutex);
|
||||||
for (auto& x : new_chunks) {
|
for (auto& x : new_chunks) {
|
||||||
@@ -597,6 +629,8 @@ void World::build_neighbor_context_for_affected_neighbors(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
void World::start_gen_thread() {
|
void World::start_gen_thread() {
|
||||||
m_gen_running = true;
|
m_gen_running = true;
|
||||||
Logger::info("Gen Thread Started");
|
Logger::info("Gen Thread Started");
|
||||||
@@ -667,15 +701,12 @@ int World::get_block(const glm::ivec3& block_pos) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto& chunk_blocks = it->second.get_chunk_blocks();
|
const auto& chunk_blocks = it->second.get_chunk_blocks();
|
||||||
int x, y, z;
|
auto [x, y, z] = Chunk::world_to_block(block_pos, {chunk_x, chunk_z});
|
||||||
y = block_pos.y;
|
|
||||||
x = block_pos.x - chunk_x * CHUNK_SIZE;
|
|
||||||
z = block_pos.z - chunk_z * CHUNK_SIZE;
|
|
||||||
if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
||||||
z >= CHUNK_SIZE) {
|
z >= CHUNK_SIZE) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return chunk_blocks[Chunk::get_index(x, y, z)];
|
return chunk_blocks[Chunk::index(x, y, z)];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::is_block(const glm::ivec3& block_pos) const {
|
bool World::is_block(const glm::ivec3& block_pos) const {
|
||||||
@@ -687,15 +718,12 @@ bool World::is_block(const glm::ivec3& block_pos) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto& chunk_blocks = it->second.get_chunk_blocks();
|
const auto& chunk_blocks = it->second.get_chunk_blocks();
|
||||||
int x, y, z;
|
auto [x, y, z] = Chunk::world_to_block(block_pos, {chunk_x, chunk_z});
|
||||||
y = block_pos.y;
|
|
||||||
x = block_pos.x - chunk_x * CHUNK_SIZE;
|
|
||||||
z = block_pos.z - chunk_z * CHUNK_SIZE;
|
|
||||||
if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
||||||
z >= CHUNK_SIZE) {
|
z >= CHUNK_SIZE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto id = chunk_blocks[Chunk::get_index(x, y, z)];
|
auto id = chunk_blocks[Chunk::index(x, y, z)];
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@@ -718,16 +746,14 @@ void World::set_block(const glm::ivec3& block_pos, unsigned id) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x, y, z;
|
auto [x, y, z] =
|
||||||
y = world_y;
|
Chunk::world_to_block(world_x, world_y, world_z, chunk_x, chunk_z);
|
||||||
x = world_x - chunk_x * CHUNK_SIZE;
|
|
||||||
z = world_z - chunk_z * CHUNK_SIZE;
|
|
||||||
if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
||||||
z >= CHUNK_SIZE) {
|
z >= CHUNK_SIZE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
it->second.set_chunk_block(Chunk::get_index(x, y, z), id);
|
it->second.set_chunk_block(Chunk::index(x, y, z), id);
|
||||||
|
|
||||||
static const glm::ivec3 NEIGHBOR_DIRS[] = {
|
static const glm::ivec3 NEIGHBOR_DIRS[] = {
|
||||||
{1, 0, 0}, {-1, 0, 0}, {0, 0, -1}, {0, 0, 1}};
|
{1, 0, 0}, {-1, 0, 0}, {0, 0, -1}, {0, 0, 1}};
|
||||||
@@ -784,7 +810,7 @@ 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
|
||||||
std::array<const std::vector<uint8_t>*, 4> 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()) {
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#include "Cubed/tools/perlin_noise.hpp"
|
#include "Cubed/tools/perlin_noise.hpp"
|
||||||
|
|
||||||
#include "Cubed/config.hpp"
|
|
||||||
#include "Cubed/tools/cubed_assert.hpp"
|
#include "Cubed/tools/cubed_assert.hpp"
|
||||||
#include "Cubed/tools/cubed_random.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
@@ -10,7 +8,7 @@
|
|||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
void PerlinNoise::init(unsigned seed) {
|
void PerlinNoise3D::init(unsigned seed) {
|
||||||
p.resize(256);
|
p.resize(256);
|
||||||
std::iota(p.begin(), p.end(), 0);
|
std::iota(p.begin(), p.end(), 0);
|
||||||
Logger::info("Init Perlin Noise With Seed {}", seed);
|
Logger::info("Init Perlin Noise With Seed {}", seed);
|
||||||
@@ -20,7 +18,7 @@ void PerlinNoise::init(unsigned seed) {
|
|||||||
is_init = true;
|
is_init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
float PerlinNoise::noise(float x, float y, float z) {
|
float PerlinNoise3D::noise(float x, float y, float z) {
|
||||||
ASSERT_MSG(is_init, "The PerlinNoise don't init!");
|
ASSERT_MSG(is_init, "The PerlinNoise don't init!");
|
||||||
int ix = static_cast<int>(std::floor(x)) & 255;
|
int ix = static_cast<int>(std::floor(x)) & 255;
|
||||||
int iy = static_cast<int>(std::floor(y)) & 255;
|
int iy = static_cast<int>(std::floor(y)) & 255;
|
||||||
@@ -55,11 +53,13 @@ float PerlinNoise::noise(float x, float y, float z) {
|
|||||||
return (res + 1.0f) / 2.0f;
|
return (res + 1.0f) / 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float PerlinNoise::fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); }
|
float PerlinNoise3D::fade(float t) {
|
||||||
|
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||||
|
}
|
||||||
|
|
||||||
float PerlinNoise::lerp(float t, float a, float b) { return a + t * (b - a); }
|
float PerlinNoise3D::lerp(float t, float a, float b) { return a + t * (b - a); }
|
||||||
|
|
||||||
float PerlinNoise::grad(int hash, float x, float y, float z) {
|
float PerlinNoise3D::grad(int hash, float x, float y, float z) {
|
||||||
int h = hash & 15;
|
int h = hash & 15;
|
||||||
|
|
||||||
float u = h < 8 ? x : y;
|
float u = h < 8 ? x : y;
|
||||||
@@ -68,7 +68,7 @@ float PerlinNoise::grad(int hash, float x, float y, float z) {
|
|||||||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PerlinNoise::reload(unsigned seed) {
|
void PerlinNoise3D::reload(unsigned seed) {
|
||||||
is_init = false;
|
is_init = false;
|
||||||
p.resize(256);
|
p.resize(256);
|
||||||
std::iota(p.begin(), p.end(), 0);
|
std::iota(p.begin(), p.end(), 0);
|
||||||
@@ -79,4 +79,59 @@ void PerlinNoise::reload(unsigned seed) {
|
|||||||
is_init = true;
|
is_init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PerlinNoise2D::init(unsigned seed) {
|
||||||
|
p.resize(256);
|
||||||
|
std::iota(p.begin(), p.end(), 0);
|
||||||
|
Logger::info("Init Perlin Noise With Seed {}", seed);
|
||||||
|
std::shuffle(p.begin(), p.end(), std::mt19937(seed));
|
||||||
|
|
||||||
|
p.insert(p.end(), p.begin(), p.end()); // 扩展到 512,方便索引
|
||||||
|
is_init = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float PerlinNoise2D::noise(float x, float y) {
|
||||||
|
ASSERT_MSG(is_init, "The PerlinNoise2D don't init!");
|
||||||
|
|
||||||
|
int ix = static_cast<int>(std::floor(x)) & 255;
|
||||||
|
int iy = static_cast<int>(std::floor(y)) & 255;
|
||||||
|
|
||||||
|
x -= std::floor(x);
|
||||||
|
y -= std::floor(y);
|
||||||
|
|
||||||
|
float u = fade(x);
|
||||||
|
float v = fade(y);
|
||||||
|
|
||||||
|
int a = p[ix] + iy;
|
||||||
|
int b = p[ix + 1] + iy;
|
||||||
|
|
||||||
|
float res =
|
||||||
|
lerp(v, lerp(u, grad(p[a], x, y), grad(p[b], x - 1, y)),
|
||||||
|
lerp(u, grad(p[a + 1], x, y - 1), grad(p[b + 1], x - 1, y - 1)));
|
||||||
|
|
||||||
|
return (res + 1.0f) / 2.0f; // 映射到 [0, 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
float PerlinNoise2D::fade(float t) {
|
||||||
|
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
float PerlinNoise2D::lerp(float t, float a, float b) { return a + t * (b - a); }
|
||||||
|
|
||||||
|
float PerlinNoise2D::grad(int hash, float x, float y) {
|
||||||
|
int h = hash & 3; // 使用低 2 位选择 4 个梯度方向
|
||||||
|
float u = (h & 1) ? -x : x;
|
||||||
|
float v = (h & 2) ? -y : y;
|
||||||
|
return u + v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PerlinNoise2D::reload(unsigned seed) {
|
||||||
|
is_init = false;
|
||||||
|
p.resize(256);
|
||||||
|
std::iota(p.begin(), p.end(), 0);
|
||||||
|
Logger::info("Reload Perlin Noise With Seed {}", seed);
|
||||||
|
std::shuffle(p.begin(), p.end(), std::mt19937(seed));
|
||||||
|
|
||||||
|
p.insert(p.end(), p.begin(), p.end());
|
||||||
|
is_init = true;
|
||||||
|
}
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||