summaryrefslogtreecommitdiff
path: root/src/World
diff options
context:
space:
mode:
Diffstat (limited to 'src/World')
-rw-r--r--src/World/BiomeType.hpp42
-rw-r--r--src/World/BlockType.hpp39
-rw-r--r--src/World/Chunk.cpp59
-rw-r--r--src/World/Chunk.hpp10
-rw-r--r--src/World/Generator.cpp178
-rw-r--r--src/World/Generator.hpp17
-rw-r--r--src/World/World.cpp4
7 files changed, 303 insertions, 46 deletions
diff --git a/src/World/BiomeType.hpp b/src/World/BiomeType.hpp
new file mode 100644
index 0000000..026b3ef
--- /dev/null
+++ b/src/World/BiomeType.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+namespace MC::World {
+
+class BiomeType {
+public:
+ enum Value : uint8_t {
+ Forest,
+ Plains,
+ Desert,
+ Ocean,
+ };
+
+ static constexpr const size_t Size = 4;
+
+ BiomeType() = default;
+ BiomeType(Value biome) : m_biome(biome) {}
+
+ operator Value() const { return m_biome; }
+
+ static std::vector<BiomeType> all() {
+ return {
+ Plains, Forest, Desert, Ocean
+ };
+ }
+
+ static std::vector<BiomeType> all_ground() {
+ return {
+ Plains, Forest, Desert
+ };
+ }
+
+private:
+
+
+ Value m_biome;
+};
+
+} \ No newline at end of file
diff --git a/src/World/BlockType.hpp b/src/World/BlockType.hpp
index 8d83be0..65afe0d 100644
--- a/src/World/BlockType.hpp
+++ b/src/World/BlockType.hpp
@@ -1,11 +1,40 @@
-#pragma
+#pragma once
+
+#include <cstdint>
+#include <vector>
namespace MC::World {
-enum class BlockType : uint8_t {
- Air,
- Dirt,
- Grass,
+class BlockType {
+public:
+ enum Value : uint8_t {
+ Air,
+ Dirt,
+ Grass,
+ Stone,
+ Sand,
+ Water,
+ };
+
+ static constexpr const size_t Size = 6;
+
+ BlockType() = default;
+ BlockType(Value block) : m_block(block) {}
+
+ operator Value() const { return m_block; }
+
+ static std::vector<BlockType> all() {
+ return {
+ Air,
+ Dirt,
+ Grass,
+ Stone,
+ Sand,
+ Water,
+ };
+ }
+private:
+ Value m_block;
};
} \ No newline at end of file
diff --git a/src/World/Chunk.cpp b/src/World/Chunk.cpp
index cd6d4f6..08f08bc 100644
--- a/src/World/Chunk.cpp
+++ b/src/World/Chunk.cpp
@@ -13,9 +13,9 @@ GFX::Mesh Chunk::mesh() {
std::vector<Vector<2>> tex_coords{};
std::vector<uint32_t> indices{};
- for (int x = 0; x < CHUNK_WIDTH; x++) {
- for (int y = 0; y < CHUNK_HEIGHT; y++) {
- for (int z = 0; z < CHUNK_WIDTH; z++) {
+ for (int x = 0; x < Chunk::Width; x++) {
+ for (int y = 0; y < Chunk::Height; y++) {
+ for (int z = 0; z < Chunk::Width; z++) {
auto type = m_blocks[x][y][z].type;
if (type == BlockType::Air) {
continue;
@@ -83,9 +83,9 @@ bool Chunk::is_face_visible(uint32_t x, uint32_t y, uint32_t z, BlockSide side)
};
if (
- neighbor_pos.x() >= CHUNK_WIDTH || neighbor_pos.x() < 0 ||
- neighbor_pos.y() >= CHUNK_HEIGHT || neighbor_pos.y() < 0 ||
- neighbor_pos.z() >= CHUNK_WIDTH || neighbor_pos.z() < 0
+ neighbor_pos.x() >= Chunk::Width || neighbor_pos.x() < 0 ||
+ neighbor_pos.y() >= Chunk::Height || neighbor_pos.y() < 0 ||
+ neighbor_pos.z() >= Chunk::Width || neighbor_pos.z() < 0
) {
return true;
}
@@ -99,30 +99,45 @@ bool Chunk::is_face_visible(uint32_t x, uint32_t y, uint32_t z, BlockSide side)
}
std::array<Vector<2>, 4> Chunk::face_tex_coords(BlockType type, BlockSide side) {
+ uint8_t atlas_width = 2;
+ uint8_t atlas_height = 3;
+
+ float width_step = 1.0f / atlas_width;
+ float height_step = 1.0f / atlas_height;
+
+ auto block_coords = [=](uint8_t x, uint8_t y) {
+ auto t = y * height_step;
+ auto l = x * width_step;
+ auto b = t + height_step;
+ auto r = l + width_step;
+
+ return std::array<Vector<2>, 4>{{
+ {l, b}, {r, b}, {r, t}, {l, t},
+ }};
+ };
+
switch (type) {
case BlockType::Dirt:
- return {{
- {0.5f, 0.0f}, {1.0f, 0.0f}, {1.0f, 0.5f}, {0.5f, 0.5f},
- }};
+ return block_coords(1, 0);
case BlockType::Grass:
switch (side) {
case BlockSide::Front:
case BlockSide::Back:
case BlockSide::Left:
case BlockSide::Right:
- return {{
- {0.5f, 1.0f}, {0.0f, 1.0f}, {0.0f, 0.5f}, {0.5f, 0.5f},
- }};
+ return block_coords(0, 1);
case BlockSide::Top:
- return {{
- {0.0f, 0.0f}, {0.5f, 0.0f}, {0.5f, 0.5f}, {0.0f, 0.5f},
- }};
+ return block_coords(0, 0);
case BlockSide::Bottom:
- return {{
- {0.5f, 0.0f}, {1.0f, 0.0f}, {1.0f, 0.5f}, {0.5f, 0.5f},
- }};
+ return block_coords(1, 0);
}
- default:
+ case BlockType::Stone:
+ return block_coords(1, 1);
+ case BlockType::Sand:
+ return block_coords(0, 2);
+ case BlockType::Water:
+ return block_coords(1, 2);
+ case BlockType::Air:
return {};
}
}
@@ -131,9 +146,9 @@ std::array<Vector<3>, 4> Chunk::face_normals(BlockSide side) {
auto is_side = [=](BlockSide s) -> float { return s == side; };
Vector<3> normal = {
- is_side(BlockSide::Right) - is_side(BlockSide::Left),
- is_side(BlockSide::Top) - is_side(BlockSide::Bottom),
- is_side(BlockSide::Front) - is_side(BlockSide::Back),
+ is_side(BlockSide::Right) - is_side(BlockSide::Left),
+ is_side(BlockSide::Top) - is_side(BlockSide::Bottom),
+ is_side(BlockSide::Front) - is_side(BlockSide::Back),
};
return {normal, normal, normal, normal};
diff --git a/src/World/Chunk.hpp b/src/World/Chunk.hpp
index 7415d7c..cb4f7e1 100644
--- a/src/World/Chunk.hpp
+++ b/src/World/Chunk.hpp
@@ -7,15 +7,15 @@
#include "BlockSide.hpp"
#include "../GFX/Binder.hpp"
-#define CHUNK_WIDTH 16
-#define CHUNK_HEIGHT 64
-
namespace MC::World {
class Chunk {
public:
+ static constexpr const uint32_t Width = 16;
+ static constexpr const uint32_t Height = 64;
+
Chunk(int64_t x, int64_t y)
- : m_blocks{}, m_position{(float)x * CHUNK_WIDTH, 0.0f, (float)y * CHUNK_WIDTH} {};
+ : m_blocks{}, m_position{(float)x * Chunk::Width, 0.0f, (float)y * Chunk::Width} {};
void set(uint32_t x, uint32_t y, uint32_t z, BlockType type);
@@ -32,7 +32,7 @@ private:
};
Vector<3> m_position;
- BlockData m_blocks[CHUNK_WIDTH][CHUNK_HEIGHT][CHUNK_WIDTH];
+ BlockData m_blocks[Chunk::Width][Chunk::Height][Chunk::Width];
};
}
diff --git a/src/World/Generator.cpp b/src/World/Generator.cpp
index ee7ece9..875a79b 100644
--- a/src/World/Generator.cpp
+++ b/src/World/Generator.cpp
@@ -6,23 +6,46 @@ namespace MC::World {
Chunk Generator::generate(int64_t chunk_x, int64_t chunk_y) {
Chunk chunk(chunk_x, chunk_y);
- uint8_t extent = 60;
- uint8_t base = 4;
+ auto ocean_weights = ocean_weights_pass(chunk_x, chunk_y);
+ auto biome_weights = biome_weights_pass(chunk_x, chunk_y, ocean_weights);
+ auto heights = height_pass(chunk_x, chunk_y, biome_weights);
+ auto biomes = flat_biome_pass(biome_weights);
- for (int x = 0; x < CHUNK_WIDTH; x++) {
- for (int z = 0; z < CHUNK_WIDTH; z++) {
- float noise = Math::noise2d(
- {(float)chunk_x * CHUNK_WIDTH + x, (float)chunk_y * CHUNK_WIDTH + z}
- ) * extent + base;
+ float extent = 60.0f;
+ float base = 4.0f;
- uint height = std::round(noise);
+ for (int x = 0; x < Chunk::Width; x++) {
+ for (int z = 0; z < Chunk::Width; z++) {
+ uint32_t height = std::round(heights(x, z) * extent + base);
- for (int y = 0; y < CHUNK_HEIGHT; y++) {
+ auto biome = biomes(x, z);
+
+ BlockType top_block{};
+ BlockType fill_block{};
+ switch (biome) {
+ case BiomeType::Forest:
+ case BiomeType::Plains:
+ top_block = BlockType::Grass;
+ fill_block = BlockType::Dirt;
+ break;
+ case BiomeType::Desert:
+ top_block = BlockType::Sand;
+ fill_block = BlockType::Sand;
+ break;
+ case BiomeType::Ocean:
+ top_block = BlockType::Water;
+ fill_block = BlockType::Dirt;
+ break;
+ }
+
+ for (int y = 0; y < Chunk::Height; y++) {
BlockType type = BlockType::Air;
- if (y < height) {
- type = BlockType::Dirt;
+ if (y < (int32_t)height - 10) {
+ type = BlockType::Stone;
+ } else if (y < height) {
+ type = fill_block;
} else if (y == height) {
- type = BlockType::Grass;
+ type = top_block;
}
chunk.set(x, y, z, type);
@@ -33,4 +56,135 @@ Chunk Generator::generate(int64_t chunk_x, int64_t chunk_y) {
return chunk;
}
+Matrix<Chunk::Width, Chunk::Width> Generator::ocean_weights_pass(int64_t chunk_x, int64_t chunk_y) {
+ auto ocean_offset = 1125.0f;
+ auto ocean_scale = 0.05f;
+
+ Matrix<Chunk::Width, Chunk::Width> ocean_weights{};
+ for (int x = 0; x < Chunk::Width; x++) {
+ for (int y = 0; y < Chunk::Width; y++) {
+ float ocean_weight = Math::noise2d({
+ (chunk_x * Chunk::Width + x) * ocean_scale + ocean_offset,
+ (chunk_y * Chunk::Width + y) * ocean_scale + ocean_offset
+ });
+
+ ocean_weights(x, y) = ocean_weight;
+ }
+ }
+
+ return ocean_weights;
+}
+
+Matrix<Chunk::Width, Chunk::Width, Vector<BiomeType::Size>> Generator::biome_weights_pass(
+ int64_t chunk_x,
+ int64_t chunk_y,
+ Matrix<Chunk::Width, Chunk::Width, float> ocean_weights
+) {
+ auto ocean_threshold = 0.4f;
+
+ std::vector<float> biome_offsets = {110.0f, 2450.0f, 5042.0f};
+ auto biome_scale = 0.15f;
+
+ Matrix<Chunk::Width, Chunk::Width, Vector<BiomeType::Size>> biome_weights{};
+ for (int x = 0; x < Chunk::Width; x++) {
+ for (int y = 0; y < Chunk::Width; y++) {
+ Vector<BiomeType::Size> weights{};
+ for (auto biome : MC::World::BiomeType::all_ground()) {
+ float biome_noise = Math::noise2d({
+ (chunk_x * Chunk::Width + x) * biome_scale + biome_offsets[biome],
+ (chunk_y * Chunk::Width + y) * biome_scale + biome_offsets[biome]
+ });
+
+ weights[biome] = biome_noise;
+ }
+
+ bool ocean_weight = ocean_weights(x, y) < ocean_threshold;
+ weights[MC::World::BiomeType::Ocean] = ocean_weight;
+
+ biome_weights(x,y) = weights;
+ }
+ }
+
+ return biome_weights;
+}
+
+Matrix<Chunk::Width, Chunk::Width> Generator::height_pass(
+ int64_t chunk_x,
+ int64_t chunk_y,
+ Matrix<Chunk::Width, Chunk::Width, Vector<BiomeType::Size>> biome_weights
+) {
+ auto height_offset = 6050.0f;
+ auto height_scale = 0.7f;
+
+ Matrix<Chunk::Width, Chunk::Width> heights{};
+ for (int x = 0; x < Chunk::Width; x++) {
+ for (int y = 0; y < Chunk::Width; y++) {
+ auto weights = biome_weights(x, y);
+
+ auto total_weight = 0.0f;
+ for (auto biome : MC::World::BiomeType::all()) {
+ total_weight += weights[biome];
+ }
+
+ std::pair<float, float> total_effect{};
+ for (auto biome : MC::World::BiomeType::all()) {
+ auto weight = weights[biome];
+
+ std::pair<float, float> effect{};
+ switch (biome) {
+ case MC::World::BiomeType::Forest:
+ effect = {0.5f, 0.45f};
+ break;
+ case MC::World::BiomeType::Plains:
+ effect = {0.4f, 0.4f};
+ break;
+ case MC::World::BiomeType::Desert:
+ effect = {0.6f, 0.35f};
+ break;
+ case MC::World::BiomeType::Ocean:
+ effect = {0.0f, 0.0f};
+ break;
+ }
+
+ total_effect = {
+ total_effect.first + effect.first * (weight / total_weight),
+ total_effect.second + effect.second * (weight / total_weight),
+ };
+ }
+
+ float height = Math::noise2d({
+ (chunk_x * Chunk::Width + x) * height_scale + height_offset,
+ (chunk_y * Chunk::Width + y) * height_scale + height_offset
+ }) * total_effect.first + total_effect.second;
+
+ heights(x, y) = height;
+ }
+ }
+
+ return heights;
+}
+
+Matrix<Chunk::Width, Chunk::Width, BiomeType> Generator::flat_biome_pass(
+ Matrix<Chunk::Width, Chunk::Width, Vector<BiomeType::Size>> biome_weights
+) {
+ Matrix<Chunk::Width, Chunk::Width, BiomeType> biomes{};
+ for (int x = 0; x < Chunk::Width; x++) {
+ for (int y = 0; y < Chunk::Width; y++) {
+ auto weights = biome_weights(x, y);
+
+ std::pair<MC::World::BiomeType, float> max_biome{MC::World::BiomeType::Plains, 0.0f};
+ for (auto biome : MC::World::BiomeType::all()) {
+ auto weight = weights[biome];
+ if (weight > max_biome.second) {
+ max_biome = {biome, weight};
+ }
+ }
+
+ biomes(x, y) = max_biome.first;
+ }
+ }
+
+ return biomes;
+}
+
} \ No newline at end of file
diff --git a/src/World/Generator.hpp b/src/World/Generator.hpp
index 479089f..f184ff9 100644
--- a/src/World/Generator.hpp
+++ b/src/World/Generator.hpp
@@ -2,6 +2,7 @@
#include <cstdint>
#include "Chunk.hpp"
+#include "BiomeType.hpp"
namespace MC::World {
@@ -10,6 +11,22 @@ public:
Generator() = default;
Chunk generate(int64_t chunk_x, int64_t chunk_y);
+
+private:
+ Matrix<Chunk::Width, Chunk::Width> ocean_weights_pass(
+ int64_t chunk_x, int64_t chunk_y
+ );
+ Matrix<Chunk::Width, Chunk::Width, Vector<BiomeType::Size>> biome_weights_pass(
+ int64_t chunk_x, int64_t chunk_y,
+ Matrix<Chunk::Width, Chunk::Width> ocean_weight
+ );
+ Matrix<Chunk::Width, Chunk::Width> height_pass(
+ int64_t chunk_x, int64_t chunk_y,
+ Matrix<Chunk::Width, Chunk::Width, Vector<BiomeType::Size>> biome_weights
+ );
+ Matrix<Chunk::Width, Chunk::Width, BiomeType> flat_biome_pass(
+ Matrix<Chunk::Width, Chunk::Width, Vector<BiomeType::Size>> biome_weights
+ );
};
}
diff --git a/src/World/World.cpp b/src/World/World.cpp
index 732e1b9..7d1b4ee 100644
--- a/src/World/World.cpp
+++ b/src/World/World.cpp
@@ -31,8 +31,8 @@ std::vector<World::ChunkData> World::get_visible_chunks(Vector<3> position) {
}
std::unordered_set<ChunkIndex> World::get_visible_chunk_indices(Vector<3> position) const {
- int32_t center_x = std::round(position.x() / CHUNK_WIDTH);
- int32_t center_y = std::round(position.z() / CHUNK_WIDTH);
+ int32_t center_x = std::round(position.x() / Chunk::Width);
+ int32_t center_y = std::round(position.z() / Chunk::Width);
std::unordered_set<ChunkIndex> indices{};
indices.reserve(m_view_distance_radius * m_view_distance_radius * 4);