diff options
| author | Mel <einebeere@gmail.com> | 2022-10-31 06:24:34 +0100 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2022-10-31 06:24:34 +0100 |
| commit | 23b0bc4d1ddc9fad3c32e8257497ddd13ac6a155 (patch) | |
| tree | 16ac3e0fa2964f026c857daa4ff6f0ca11520d46 /src/World | |
| parent | 1b2b0069c9b7ad73c6cc6663b020d0fd894f4567 (diff) | |
| download | meowcraft-23b0bc4d1ddc9fad3c32e8257497ddd13ac6a155.tar.zst meowcraft-23b0bc4d1ddc9fad3c32e8257497ddd13ac6a155.zip | |
Proto biomes and new blocks
Diffstat (limited to 'src/World')
| -rw-r--r-- | src/World/BiomeType.hpp | 42 | ||||
| -rw-r--r-- | src/World/BlockType.hpp | 39 | ||||
| -rw-r--r-- | src/World/Chunk.cpp | 59 | ||||
| -rw-r--r-- | src/World/Chunk.hpp | 10 | ||||
| -rw-r--r-- | src/World/Generator.cpp | 178 | ||||
| -rw-r--r-- | src/World/Generator.hpp | 17 | ||||
| -rw-r--r-- | src/World/World.cpp | 4 |
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); |
