#include "Decoration.hpp" #include namespace MC::World::Generation { void Decorator::put_block(Chunk& chunk, Pos pos, BlockType block) { if (!Chunk::is_valid_position(pos)) { return; } auto& place = chunk.at(pos); if (place.empty()) { place = {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, Real radius, BlockType block) { auto normalized_axis = axis.normalize(); auto ortho1 = normalized_axis.any_orthogonal(); auto ortho2 = normalized_axis.cross(ortho1); auto r = [](const Real x) { return static_cast(std::round(x)); }; Int radius_round = std::round(radius); for (I32 d1 = -radius_round; d1 <= radius_round; d1++) { Real height = std::sqrt(radius * radius - d1 * d1); for (I32 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(); chunk.for_each_by_column([&](Pos pos, Chunk::BlockData& block) { auto pos_above = pos + Pos::up(); if (!is_valid_position(pos_above)) return Chunk::ColumnIteration::Continue; if (block.empty()) return Chunk::ColumnIteration::Continue; auto type = block.type; if (type != BlockType::Snow && type != BlockType::Grass && type != BlockType::Dirt) return Chunk::ColumnIteration::SkipColumn; auto noise = m_tree_noise.at({TO(Real, pos.x()), TO(Real, pos.z())}); if (noise < 0.8f) return Chunk::ColumnIteration::Continue; if (last_tree.distance(pos_above) < s_tree_radius * 3) return Chunk::ColumnIteration::Continue; draw_tree(chunk, pos_above); block = {BlockType::Dirt}; last_tree = pos_above; return Chunk::ColumnIteration::SkipColumn; }); } void TreeDecorator::draw_tree(Chunk& chunk, Pos pos) const { auto noise = m_tree_noise.at({(Real)pos.x(), (Real)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()}; Real 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(Pos 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; } void DefaultLightDecorator::decorate_chunk(Chunk& chunk) { chunk.for_each_by_column([&](Pos pos, Chunk::BlockData& block) { if (!block.type.is_translucent()) return Chunk::ColumnIteration::Break; block.light = 200; return Chunk::ColumnIteration::Continue; }); } }