diff options
author | Vitaliy <silverunicorn2011@yandex.ru> | 2017-11-09 01:56:20 +0300 |
---|---|---|
committer | Loïc Blot <nerzhul@users.noreply.github.com> | 2017-11-08 23:56:20 +0100 |
commit | 20a85d76d94c9c5c7fbe198c3d0e1fbee97a485f (patch) | |
tree | 67378802190117d8271b3b6d489a92bcb16203b7 /src/mapgen/treegen.cpp | |
parent | fc9747eb4b7f75e59a28957bc50f7a78256b3d66 (diff) | |
download | minetest-20a85d76d94c9c5c7fbe198c3d0e1fbee97a485f.tar.gz minetest-20a85d76d94c9c5c7fbe198c3d0e1fbee97a485f.tar.bz2 minetest-20a85d76d94c9c5c7fbe198c3d0e1fbee97a485f.zip |
Move files to subdirectories (#6599)
* Move files around
Diffstat (limited to 'src/mapgen/treegen.cpp')
-rw-r--r-- | src/mapgen/treegen.cpp | 872 |
1 files changed, 872 insertions, 0 deletions
diff --git a/src/mapgen/treegen.cpp b/src/mapgen/treegen.cpp new file mode 100644 index 000000000..9e11b1a06 --- /dev/null +++ b/src/mapgen/treegen.cpp @@ -0,0 +1,872 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>, + 2012-2013 RealBadAngel, Maciej Kasatkin <mk@realbadangel.pl> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "irr_v3d.h" +#include <stack> +#include "util/pointer.h" +#include "util/numeric.h" +#include "map.h" +#include "mapblock.h" +#include "serverenvironment.h" +#include "nodedef.h" +#include "treegen.h" +#include "voxelalgorithms.h" + +namespace treegen +{ + +void make_tree(MMVManip &vmanip, v3s16 p0, + bool is_apple_tree, INodeDefManager *ndef, s32 seed) +{ + /* + NOTE: Tree-placing code is currently duplicated in the engine + and in games that have saplings; both are deprecated but not + replaced yet + */ + MapNode treenode(ndef->getId("mapgen_tree")); + MapNode leavesnode(ndef->getId("mapgen_leaves")); + MapNode applenode(ndef->getId("mapgen_apple")); + + PseudoRandom pr(seed); + s16 trunk_h = pr.range(4, 5); + v3s16 p1 = p0; + for (s16 ii = 0; ii < trunk_h; ii++) { + if (vmanip.m_area.contains(p1)) { + u32 vi = vmanip.m_area.index(p1); + vmanip.m_data[vi] = treenode; + } + p1.Y++; + } + + // p1 is now the last piece of the trunk + p1.Y -= 1; + + VoxelArea leaves_a(v3s16(-2, -1, -2), v3s16(2, 2, 2)); + Buffer<u8> leaves_d(leaves_a.getVolume()); + for (s32 i = 0; i < leaves_a.getVolume(); i++) + leaves_d[i] = 0; + + // Force leaves at near the end of the trunk + s16 d = 1; + for (s16 z = -d; z <= d; z++) + for (s16 y = -d; y <= d; y++) + for (s16 x = -d; x <= d; x++) { + leaves_d[leaves_a.index(v3s16(x, y, z))] = 1; + } + + // Add leaves randomly + for (u32 iii = 0; iii < 7; iii++) { + v3s16 p( + pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d), + pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d), + pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d) + ); + + for (s16 z = 0; z <= d; z++) + for (s16 y = 0; y <= d; y++) + for (s16 x = 0; x <= d; x++) { + leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1; + } + } + + // Blit leaves to vmanip + for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++) + for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) { + v3s16 pmin(leaves_a.MinEdge.X, y, z); + u32 i = leaves_a.index(pmin); + u32 vi = vmanip.m_area.index(pmin + p1); + for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) { + v3s16 p(x, y, z); + if (vmanip.m_area.contains(p + p1) && + (vmanip.m_data[vi].getContent() == CONTENT_AIR || + vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) { + if (leaves_d[i] == 1) { + bool is_apple = pr.range(0, 99) < 10; + if (is_apple_tree && is_apple) + vmanip.m_data[vi] = applenode; + else + vmanip.m_data[vi] = leavesnode; + } + } + vi++; + i++; + } + } +} + + +// L-System tree LUA spawner +treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0, + INodeDefManager *ndef, const TreeDef &tree_definition) +{ + ServerMap *map = &env->getServerMap(); + std::map<v3s16, MapBlock*> modified_blocks; + MMVManip vmanip(map); + v3s16 tree_blockp = getNodeBlockPos(p0); + treegen::error e; + + vmanip.initialEmerge(tree_blockp - v3s16(1, 1, 1), tree_blockp + v3s16(1, 3, 1)); + e = make_ltree(vmanip, p0, ndef, tree_definition); + if (e != SUCCESS) + return e; + + voxalgo::blit_back_with_light(map, &vmanip, &modified_blocks); + + // Send a MEET_OTHER event + MapEditEvent event; + event.type = MEET_OTHER; + for (auto &modified_block : modified_blocks) + event.modified_blocks.insert(modified_block.first); + map->dispatchEvent(&event); + return SUCCESS; +} + + +//L-System tree generator +treegen::error make_ltree(MMVManip &vmanip, v3s16 p0, + INodeDefManager *ndef, TreeDef tree_definition) +{ + MapNode dirtnode(ndef->getId("mapgen_dirt")); + s32 seed; + if (tree_definition.explicit_seed) + seed = tree_definition.seed + 14002; + else + seed = p0.X * 2 + p0.Y * 4 + p0.Z; // use the tree position to seed PRNG + PseudoRandom ps(seed); + + // chance of inserting abcd rules + double prop_a = 9; + double prop_b = 8; + double prop_c = 7; + double prop_d = 6; + + //randomize tree growth level, minimum=2 + s16 iterations = tree_definition.iterations; + if (tree_definition.iterations_random_level > 0) + iterations -= ps.range(0, tree_definition.iterations_random_level); + if (iterations < 2) + iterations = 2; + + s16 MAX_ANGLE_OFFSET = 5; + double angle_in_radians = (double)tree_definition.angle * M_PI / 180; + double angleOffset_in_radians = (s16)(ps.range(0, 1) % MAX_ANGLE_OFFSET) * M_PI / 180; + + //initialize rotation matrix, position and stacks for branches + core::matrix4 rotation; + rotation = setRotationAxisRadians(rotation, M_PI / 2, v3f(0, 0, 1)); + v3f position; + position.X = p0.X; + position.Y = p0.Y; + position.Z = p0.Z; + std::stack <core::matrix4> stack_orientation; + std::stack <v3f> stack_position; + + //generate axiom + std::string axiom = tree_definition.initial_axiom; + for (s16 i = 0; i < iterations; i++) { + std::string temp; + for (s16 j = 0; j < (s16)axiom.size(); j++) { + char axiom_char = axiom.at(j); + switch (axiom_char) { + case 'A': + temp += tree_definition.rules_a; + break; + case 'B': + temp += tree_definition.rules_b; + break; + case 'C': + temp += tree_definition.rules_c; + break; + case 'D': + temp += tree_definition.rules_d; + break; + case 'a': + if (prop_a >= ps.range(1, 10)) + temp += tree_definition.rules_a; + break; + case 'b': + if (prop_b >= ps.range(1, 10)) + temp += tree_definition.rules_b; + break; + case 'c': + if (prop_c >= ps.range(1, 10)) + temp += tree_definition.rules_c; + break; + case 'd': + if (prop_d >= ps.range(1, 10)) + temp += tree_definition.rules_d; + break; + default: + temp += axiom_char; + break; + } + } + axiom = temp; + } + + //make sure tree is not floating in the air + if (tree_definition.trunk_type == "double") { + tree_node_placement( + vmanip, + v3f(position.X + 1, position.Y - 1, position.Z), + dirtnode + ); + tree_node_placement( + vmanip, + v3f(position.X, position.Y - 1, position.Z + 1), + dirtnode + ); + tree_node_placement( + vmanip, + v3f(position.X + 1, position.Y - 1, position.Z + 1), + dirtnode + ); + } else if (tree_definition.trunk_type == "crossed") { + tree_node_placement( + vmanip, + v3f(position.X + 1, position.Y - 1, position.Z), + dirtnode + ); + tree_node_placement( + vmanip, + v3f(position.X - 1, position.Y - 1, position.Z), + dirtnode + ); + tree_node_placement( + vmanip, + v3f(position.X, position.Y - 1, position.Z + 1), + dirtnode + ); + tree_node_placement( + vmanip, + v3f(position.X, position.Y - 1, position.Z - 1), + dirtnode + ); + } + + /* build tree out of generated axiom + + Key for Special L-System Symbols used in Axioms + + G - move forward one unit with the pen up + F - move forward one unit with the pen down drawing trunks and branches + f - move forward one unit with the pen down drawing leaves (100% chance) + T - move forward one unit with the pen down drawing trunks only + R - move forward one unit with the pen down placing fruit + A - replace with rules set A + B - replace with rules set B + C - replace with rules set C + D - replace with rules set D + a - replace with rules set A, chance 90% + b - replace with rules set B, chance 80% + c - replace with rules set C, chance 70% + d - replace with rules set D, chance 60% + + - yaw the turtle right by angle degrees + - - yaw the turtle left by angle degrees + & - pitch the turtle down by angle degrees + ^ - pitch the turtle up by angle degrees + / - roll the turtle to the right by angle degrees + * - roll the turtle to the left by angle degrees + [ - save in stack current state info + ] - recover from stack state info + + */ + + s16 x,y,z; + for (s16 i = 0; i < (s16)axiom.size(); i++) { + char axiom_char = axiom.at(i); + core::matrix4 temp_rotation; + temp_rotation.makeIdentity(); + v3f dir; + switch (axiom_char) { + case 'G': + dir = v3f(1, 0, 0); + dir = transposeMatrix(rotation, dir); + position += dir; + break; + case 'T': + tree_trunk_placement( + vmanip, + v3f(position.X, position.Y, position.Z), + tree_definition + ); + if (tree_definition.trunk_type == "double" && + !tree_definition.thin_branches) { + tree_trunk_placement( + vmanip, + v3f(position.X + 1, position.Y, position.Z), + tree_definition + ); + tree_trunk_placement( + vmanip, + v3f(position.X, position.Y, position.Z + 1), + tree_definition + ); + tree_trunk_placement( + vmanip, + v3f(position.X + 1, position.Y, position.Z + 1), + tree_definition + ); + } else if (tree_definition.trunk_type == "crossed" && + !tree_definition.thin_branches) { + tree_trunk_placement( + vmanip, + v3f(position.X + 1, position.Y, position.Z), + tree_definition + ); + tree_trunk_placement( + vmanip, + v3f(position.X - 1, position.Y, position.Z), + tree_definition + ); + tree_trunk_placement( + vmanip, + v3f(position.X, position.Y, position.Z + 1), + tree_definition + ); + tree_trunk_placement( + vmanip, + v3f(position.X, position.Y, position.Z - 1), + tree_definition + ); + } + dir = v3f(1, 0, 0); + dir = transposeMatrix(rotation, dir); + position += dir; + break; + case 'F': + tree_trunk_placement( + vmanip, + v3f(position.X, position.Y, position.Z), + tree_definition + ); + if ((stack_orientation.empty() && + tree_definition.trunk_type == "double") || + (!stack_orientation.empty() && + tree_definition.trunk_type == "double" && + !tree_definition.thin_branches)) { + tree_trunk_placement( + vmanip, + v3f(position.X +1 , position.Y, position.Z), + tree_definition + ); + tree_trunk_placement( + vmanip, + v3f(position.X, position.Y, position.Z + 1), + tree_definition + ); + tree_trunk_placement( + vmanip, + v3f(position.X + 1, position.Y, position.Z + 1), + tree_definition + ); + } else if ((stack_orientation.empty() && + tree_definition.trunk_type == "crossed") || + (!stack_orientation.empty() && + tree_definition.trunk_type == "crossed" && + !tree_definition.thin_branches)) { + tree_trunk_placement( + vmanip, + v3f(position.X + 1, position.Y, position.Z), + tree_definition + ); + tree_trunk_placement( + vmanip, + v3f(position.X - 1, position.Y, position.Z), + tree_definition + ); + tree_trunk_placement( + vmanip, + v3f(position.X, position.Y, position.Z + 1), + tree_definition + ); + tree_trunk_placement( + vmanip, + v3f(position.X, position.Y, position.Z - 1), + tree_definition + ); + } if (!stack_orientation.empty()) { + s16 size = 1; + for (x = -size; x <= size; x++) + for (y = -size; y <= size; y++) + for (z = -size; z <= size; z++) { + if (abs(x) == size && + abs(y) == size && + abs(z) == size) { + tree_leaves_placement( + vmanip, + v3f(position.X + x + 1, position.Y + y, + position.Z + z), + ps.next(), + tree_definition + ); + tree_leaves_placement( + vmanip, + v3f(position.X + x - 1, position.Y + y, + position.Z + z), + ps.next(), + tree_definition + ); + tree_leaves_placement( + vmanip,v3f(position.X + x, position.Y + y, + position.Z + z + 1), + ps.next(), + tree_definition + ); + tree_leaves_placement( + vmanip,v3f(position.X + x, position.Y + y, + position.Z + z - 1), + ps.next(), + tree_definition + ); + } + } + } + dir = v3f(1, 0, 0); + dir = transposeMatrix(rotation, dir); + position += dir; + break; + case 'f': + tree_single_leaves_placement( + vmanip, + v3f(position.X, position.Y, position.Z), + ps.next(), + tree_definition + ); + dir = v3f(1, 0, 0); + dir = transposeMatrix(rotation, dir); + position += dir; + break; + case 'R': + tree_fruit_placement( + vmanip, + v3f(position.X, position.Y, position.Z), + tree_definition + ); + dir = v3f(1, 0, 0); + dir = transposeMatrix(rotation, dir); + position += dir; + break; + + // turtle orientation commands + case '[': + stack_orientation.push(rotation); + stack_position.push(position); + break; + case ']': + if (stack_orientation.empty()) + return UNBALANCED_BRACKETS; + rotation = stack_orientation.top(); + stack_orientation.pop(); + position = stack_position.top(); + stack_position.pop(); + break; + case '+': + temp_rotation.makeIdentity(); + temp_rotation = setRotationAxisRadians(temp_rotation, + angle_in_radians + angleOffset_in_radians, v3f(0, 0, 1)); + rotation *= temp_rotation; + break; + case '-': + temp_rotation.makeIdentity(); + temp_rotation = setRotationAxisRadians(temp_rotation, + angle_in_radians + angleOffset_in_radians, v3f(0, 0, -1)); + rotation *= temp_rotation; + break; + case '&': + temp_rotation.makeIdentity(); + temp_rotation = setRotationAxisRadians(temp_rotation, + angle_in_radians + angleOffset_in_radians, v3f(0, 1, 0)); + rotation *= temp_rotation; + break; + case '^': + temp_rotation.makeIdentity(); + temp_rotation = setRotationAxisRadians(temp_rotation, + angle_in_radians + angleOffset_in_radians, v3f(0, -1, 0)); + rotation *= temp_rotation; + break; + case '*': + temp_rotation.makeIdentity(); + temp_rotation = setRotationAxisRadians(temp_rotation, + angle_in_radians, v3f(1, 0, 0)); + rotation *= temp_rotation; + break; + case '/': + temp_rotation.makeIdentity(); + temp_rotation = setRotationAxisRadians(temp_rotation, + angle_in_radians, v3f(-1, 0, 0)); + rotation *= temp_rotation; + break; + default: + break; + } + } + + return SUCCESS; +} + + +void tree_node_placement(MMVManip &vmanip, v3f p0, MapNode node) +{ + v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z)); + if (!vmanip.m_area.contains(p1)) + return; + u32 vi = vmanip.m_area.index(p1); + if (vmanip.m_data[vi].getContent() != CONTENT_AIR + && vmanip.m_data[vi].getContent() != CONTENT_IGNORE) + return; + vmanip.m_data[vmanip.m_area.index(p1)] = node; +} + + +void tree_trunk_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition) +{ + v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z)); + if (!vmanip.m_area.contains(p1)) + return; + u32 vi = vmanip.m_area.index(p1); + content_t current_node = vmanip.m_data[vi].getContent(); + if (current_node != CONTENT_AIR && current_node != CONTENT_IGNORE + && current_node != tree_definition.leavesnode.getContent() + && current_node != tree_definition.leaves2node.getContent() + && current_node != tree_definition.fruitnode.getContent()) + return; + vmanip.m_data[vi] = tree_definition.trunknode; +} + + +void tree_leaves_placement(MMVManip &vmanip, v3f p0, + PseudoRandom ps, TreeDef &tree_definition) +{ + MapNode leavesnode = tree_definition.leavesnode; + if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance) + leavesnode = tree_definition.leaves2node; + v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z)); + if (!vmanip.m_area.contains(p1)) + return; + u32 vi = vmanip.m_area.index(p1); + if (vmanip.m_data[vi].getContent() != CONTENT_AIR + && vmanip.m_data[vi].getContent() != CONTENT_IGNORE) + return; + if (tree_definition.fruit_chance > 0) { + if (ps.range(1, 100) > 100 - tree_definition.fruit_chance) + vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode; + else + vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode; + } else if (ps.range(1, 100) > 20) { + vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode; + } +} + + +void tree_single_leaves_placement(MMVManip &vmanip, v3f p0, + PseudoRandom ps, TreeDef &tree_definition) +{ + MapNode leavesnode = tree_definition.leavesnode; + if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance) + leavesnode = tree_definition.leaves2node; + v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z)); + if (!vmanip.m_area.contains(p1)) + return; + u32 vi = vmanip.m_area.index(p1); + if (vmanip.m_data[vi].getContent() != CONTENT_AIR + && vmanip.m_data[vi].getContent() != CONTENT_IGNORE) + return; + vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode; +} + + +void tree_fruit_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition) +{ + v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z)); + if (!vmanip.m_area.contains(p1)) + return; + u32 vi = vmanip.m_area.index(p1); + if (vmanip.m_data[vi].getContent() != CONTENT_AIR + && vmanip.m_data[vi].getContent() != CONTENT_IGNORE) + return; + vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode; +} + + +irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis) +{ + double c = cos(angle); + double s = sin(angle); + double t = 1.0 - c; + + double tx = t * axis.X; + double ty = t * axis.Y; + double tz = t * axis.Z; + double sx = s * axis.X; + double sy = s * axis.Y; + double sz = s * axis.Z; + + M[0] = tx * axis.X + c; + M[1] = tx * axis.Y + sz; + M[2] = tx * axis.Z - sy; + + M[4] = ty * axis.X - sz; + M[5] = ty * axis.Y + c; + M[6] = ty * axis.Z + sx; + + M[8] = tz * axis.X + sy; + M[9] = tz * axis.Y - sx; + M[10] = tz * axis.Z + c; + return M; +} + + +v3f transposeMatrix(irr::core::matrix4 M, v3f v) +{ + v3f translated; + double x = M[0] * v.X + M[4] * v.Y + M[8] * v.Z +M[12]; + double y = M[1] * v.X + M[5] * v.Y + M[9] * v.Z +M[13]; + double z = M[2] * v.X + M[6] * v.Y + M[10] * v.Z +M[14]; + translated.X = x; + translated.Y = y; + translated.Z = z; + return translated; +} + + +void make_jungletree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, s32 seed) +{ + /* + NOTE: Tree-placing code is currently duplicated in the engine + and in games that have saplings; both are deprecated but not + replaced yet + */ + content_t c_tree = ndef->getId("mapgen_jungletree"); + content_t c_leaves = ndef->getId("mapgen_jungleleaves"); + if (c_tree == CONTENT_IGNORE) + c_tree = ndef->getId("mapgen_tree"); + if (c_leaves == CONTENT_IGNORE) + c_leaves = ndef->getId("mapgen_leaves"); + + MapNode treenode(c_tree); + MapNode leavesnode(c_leaves); + + PseudoRandom pr(seed); + for (s16 x= -1; x <= 1; x++) + for (s16 z= -1; z <= 1; z++) { + if (pr.range(0, 2) == 0) + continue; + v3s16 p1 = p0 + v3s16(x, 0, z); + v3s16 p2 = p0 + v3s16(x, -1, z); + u32 vi1 = vmanip.m_area.index(p1); + u32 vi2 = vmanip.m_area.index(p2); + + if (vmanip.m_area.contains(p2) && + vmanip.m_data[vi2].getContent() == CONTENT_AIR) + vmanip.m_data[vi2] = treenode; + else if (vmanip.m_area.contains(p1) && + vmanip.m_data[vi1].getContent() == CONTENT_AIR) + vmanip.m_data[vi1] = treenode; + } + vmanip.m_data[vmanip.m_area.index(p0)] = treenode; + + s16 trunk_h = pr.range(8, 12); + v3s16 p1 = p0; + for (s16 ii = 0; ii < trunk_h; ii++) { + if (vmanip.m_area.contains(p1)) { + u32 vi = vmanip.m_area.index(p1); + vmanip.m_data[vi] = treenode; + } + p1.Y++; + } + + // p1 is now the last piece of the trunk + p1.Y -= 1; + + VoxelArea leaves_a(v3s16(-3, -2, -3), v3s16(3, 2, 3)); + //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]); + Buffer<u8> leaves_d(leaves_a.getVolume()); + for (s32 i = 0; i < leaves_a.getVolume(); i++) + leaves_d[i] = 0; + + // Force leaves at near the end of the trunk + s16 d = 1; + for (s16 z = -d; z <= d; z++) + for (s16 y = -d; y <= d; y++) + for (s16 x = -d; x <= d; x++) { + leaves_d[leaves_a.index(v3s16(x,y,z))] = 1; + } + + // Add leaves randomly + for (u32 iii = 0; iii < 30; iii++) { + v3s16 p( + pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d), + pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d), + pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d) + ); + + for (s16 z = 0; z <= d; z++) + for (s16 y = 0; y <= d; y++) + for (s16 x = 0; x <= d; x++) { + leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1; + } + } + + // Blit leaves to vmanip + for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++) + for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) { + v3s16 pmin(leaves_a.MinEdge.X, y, z); + u32 i = leaves_a.index(pmin); + u32 vi = vmanip.m_area.index(pmin + p1); + for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) { + v3s16 p(x, y, z); + if (vmanip.m_area.contains(p + p1) && + (vmanip.m_data[vi].getContent() == CONTENT_AIR || + vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) { + if (leaves_d[i] == 1) + vmanip.m_data[vi] = leavesnode; + } + vi++; + i++; + } + } +} + + +void make_pine_tree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, s32 seed) +{ + /* + NOTE: Tree-placing code is currently duplicated in the engine + and in games that have saplings; both are deprecated but not + replaced yet + */ + content_t c_tree = ndef->getId("mapgen_pine_tree"); + content_t c_leaves = ndef->getId("mapgen_pine_needles"); + content_t c_snow = ndef->getId("mapgen_snow"); + if (c_tree == CONTENT_IGNORE) + c_tree = ndef->getId("mapgen_tree"); + if (c_leaves == CONTENT_IGNORE) + c_leaves = ndef->getId("mapgen_leaves"); + if (c_snow == CONTENT_IGNORE) + c_snow = CONTENT_AIR; + + MapNode treenode(c_tree); + MapNode leavesnode(c_leaves); + MapNode snownode(c_snow); + + PseudoRandom pr(seed); + u16 trunk_h = pr.range(9, 13); + v3s16 p1 = p0; + for (u16 ii = 0; ii < trunk_h; ii++) { + if (vmanip.m_area.contains(p1)) { + u32 vi = vmanip.m_area.index(p1); + vmanip.m_data[vi] = treenode; + } + p1.Y++; + } + + // Make p1 the top node of the trunk + p1.Y -= 1; + + VoxelArea leaves_a(v3s16(-3, -6, -3), v3s16(3, 3, 3)); + Buffer<u8> leaves_d(leaves_a.getVolume()); + for (s32 i = 0; i < leaves_a.getVolume(); i++) + leaves_d[i] = 0; + + // Upper branches + u16 dev = 3; + for (s16 yy = -1; yy <= 1; yy++) { + for (s16 zz = -dev; zz <= dev; zz++) { + u32 i = leaves_a.index(v3s16(-dev, yy, zz)); + u32 ia = leaves_a.index(v3s16(-dev, yy+1, zz)); + for (s16 xx = -dev; xx <= dev; xx++) { + if (pr.range(0, 20) <= 19 - dev) { + leaves_d[i] = 1; + leaves_d[ia] = 2; + } + i++; + ia++; + } + } + dev--; + } + + // Centre top nodes + leaves_d[leaves_a.index(v3s16(0, 1, 0))] = 1; + leaves_d[leaves_a.index(v3s16(0, 2, 0))] = 1; + leaves_d[leaves_a.index(v3s16(0, 3, 0))] = 2; + + // Lower branches + s16 my = -6; + for (u32 iii = 0; iii < 20; iii++) { + s16 xi = pr.range(-3, 2); + s16 yy = pr.range(-6, -5); + s16 zi = pr.range(-3, 2); + if (yy > my) + my = yy; + for (s16 zz = zi; zz <= zi + 1; zz++) { + u32 i = leaves_a.index(v3s16(xi, yy, zz)); + u32 ia = leaves_a.index(v3s16(xi, yy + 1, zz)); + for (s32 xx = xi; xx <= xi + 1; xx++) { + leaves_d[i] = 1; + if (leaves_d[ia] == 0) + leaves_d[ia] = 2; + i++; + ia++; + } + } + } + + dev = 2; + for (s16 yy = my + 1; yy <= my + 2; yy++) { + for (s16 zz = -dev; zz <= dev; zz++) { + u32 i = leaves_a.index(v3s16(-dev, yy, zz)); + u32 ia = leaves_a.index(v3s16(-dev, yy + 1, zz)); + for (s16 xx = -dev; xx <= dev; xx++) { + if (pr.range(0, 20) <= 19 - dev) { + leaves_d[i] = 1; + leaves_d[ia] = 2; + } + i++; + ia++; + } + } + dev--; + } + + // Blit leaves to vmanip + for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++) + for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) { + v3s16 pmin(leaves_a.MinEdge.X, y, z); + u32 i = leaves_a.index(pmin); + u32 vi = vmanip.m_area.index(pmin + p1); + for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) { + v3s16 p(x, y, z); + if (vmanip.m_area.contains(p + p1) && + (vmanip.m_data[vi].getContent() == CONTENT_AIR || + vmanip.m_data[vi].getContent() == CONTENT_IGNORE || + vmanip.m_data[vi] == snownode)) { + if (leaves_d[i] == 1) + vmanip.m_data[vi] = leavesnode; + else if (leaves_d[i] == 2) + vmanip.m_data[vi] = snownode; + } + vi++; + i++; + } + } +} + +}; // namespace treegen |