summary refs log tree commit diff
path: root/src/World/Generation/Decoration.cpp
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2023-07-07 21:39:42 +0200
committerMel <einebeere@gmail.com>2023-07-07 21:39:42 +0200
commitf1fc192ddc4c739fa8b4b376c759b7d3218a34eb (patch)
tree9e9afb9a21ba3ca27d1f25d46230aa9d27f8be39 /src/World/Generation/Decoration.cpp
parent24b8124469350d1c80d0553cf3f4bf58cdb1489b (diff)
downloadmeowcraft-f1fc192ddc4c739fa8b4b376c759b7d3218a34eb.tar.zst
meowcraft-f1fc192ddc4c739fa8b4b376c759b7d3218a34eb.zip
Chunk-bound tree decoration
Diffstat (limited to 'src/World/Generation/Decoration.cpp')
-rw-r--r--src/World/Generation/Decoration.cpp97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/World/Generation/Decoration.cpp b/src/World/Generation/Decoration.cpp
new file mode 100644
index 0000000..26eb397
--- /dev/null
+++ b/src/World/Generation/Decoration.cpp
@@ -0,0 +1,97 @@
+#include "Decoration.hpp"
+
+#include <iostream>
+
+namespace MC::World::Generation {
+void Decorator::put_block(Chunk& chunk, Pos pos, BlockType block) {
+    if (!Chunk::is_valid_position(pos.x(), pos.y(), pos.z())) {
+        return;
+    }
+    if (chunk.is_empty(pos.x(), pos.y(), pos.z())) {
+        chunk.set(pos.x(), pos.y(), pos.z(), {block});
+    }
+}
+
+void Decorator::draw_column(Chunk& chunk, Pos pos, uint height, BlockType block) {
+    Pos current_pos = pos;
+    for (uint i = 0; i < height; i++) {
+        put_block(chunk, current_pos, block);
+        current_pos += Pos::up();
+    }
+}
+
+void Decorator::draw_circle(Chunk& chunk, Pos pos, Vector<3> axis, float radius, BlockType block) {
+    auto normalized_axis = axis.normalize();
+
+    auto ortho1 = normalized_axis.any_orthogonal();
+    auto ortho2 = normalized_axis.cross(ortho1);
+
+    auto r = [](const float x) { return static_cast<uint>(std::round(x)); };
+
+    int radius_round = std::round(radius);
+    for (int32_t d1 = -radius_round; d1 <= radius_round; d1++) {
+        float height = std::sqrt(radius * radius - d1 * d1);
+        for (int32_t d2 = -height; d2 <= (int)height; d2++) {
+            auto p = ortho1 * d1 + ortho2 * d2;
+            Pos block_pos = pos + Pos{r(p.x()), r(p.y()), r(p.z())};
+            put_block(chunk, block_pos, block);
+        }
+    }
+}
+
+void TreeDecorator::decorate_chunk(Chunk& chunk) {
+    Pos last_tree = Pos::max();
+    for (uint x = 0; x < Chunk::Width; x++) {
+        for (uint z = 0; z < Chunk::Width; z++) {
+            for (uint y = Chunk::Height; y > 1; y--) {
+                Pos pos{x, y, z};
+                if (!is_valid_position(pos))
+                    continue;
+
+                auto block_below = chunk.get(x, y-1, z);
+                if (block_below.empty())
+                    continue;
+
+                auto type = block_below.type;
+                if (type != BlockType::Snow && type != BlockType::Grass && type != BlockType::Dirt)
+                    break;
+
+                auto noise = m_tree_noise.at({(float)x, (float)z});
+                if (noise < 0.8f)
+                    continue;
+
+                if (last_tree.distance(pos) < s_tree_radius * 3)
+                    continue;
+
+                draw_tree(chunk, pos);
+                chunk.set(x, y-1, z, {BlockType::Dirt});
+                last_tree = pos;
+                break;
+            }
+        }
+    }
+}
+
+void TreeDecorator::draw_tree(Chunk& chunk, Pos pos) const {
+    auto noise = m_tree_noise.at({(float)pos.x(), (float)pos.z()});
+    uint height = std::round(10 * noise - 4.75f);
+
+    draw_column(chunk, pos, height, BlockType::Wood);
+
+    uint max_leaf_height = 4;
+    for (int x = 0; x < max_leaf_height; x++) {
+        Pos p{pos.x(), pos.y() + height + x - 2, pos.z()};
+        float radius = s_tree_radius - 0.5f + x * ((0.3f * x - 1.45f) * x + 1.25f);
+        draw_circle(chunk, p, Vector<3>::up(), radius, BlockType::Leaves);
+    }
+}
+
+bool TreeDecorator::is_valid_position(Vector<3, uint> pos) {
+    int tree_radius = s_tree_radius;
+    return (int)pos.x() - tree_radius >= 0
+        && pos.x() + tree_radius <= Chunk::Width
+        && (int)pos.z() - tree_radius >= 0
+        && pos.z() + tree_radius <= Chunk::Width;
+}
+
+}