3 Copyright (C) 2010-2018 celeron55, Perttu Ahola <celeron55@gmail.com>,
4 Copyright (C) 2012-2018 RealBadAngel, Maciej Kasatkin
5 Copyright (C) 2015-2018 paramat
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "util/pointer.h"
25 #include "util/numeric.h"
28 #include "serverenvironment.h"
31 #include "voxelalgorithms.h"
36 void make_tree(MMVManip &vmanip, v3s16 p0, bool is_apple_tree,
37 const NodeDefManager *ndef, s32 seed)
40 NOTE: Tree-placing code is currently duplicated in the engine
41 and in games that have saplings; both are deprecated but not
44 MapNode treenode(ndef->getId("mapgen_tree"));
45 MapNode leavesnode(ndef->getId("mapgen_leaves"));
46 MapNode applenode(ndef->getId("mapgen_apple"));
48 PseudoRandom pr(seed);
49 s16 trunk_h = pr.range(4, 5);
51 for (s16 ii = 0; ii < trunk_h; ii++) {
52 if (vmanip.m_area.contains(p1)) {
53 u32 vi = vmanip.m_area.index(p1);
54 vmanip.m_data[vi] = treenode;
59 // p1 is now the last piece of the trunk
62 VoxelArea leaves_a(v3s16(-2, -1, -2), v3s16(2, 2, 2));
63 Buffer<u8> leaves_d(leaves_a.getVolume());
64 for (s32 i = 0; i < leaves_a.getVolume(); i++)
67 // Force leaves at near the end of the trunk
69 for (s16 z = -d; z <= d; z++)
70 for (s16 y = -d; y <= d; y++)
71 for (s16 x = -d; x <= d; x++) {
72 leaves_d[leaves_a.index(v3s16(x, y, z))] = 1;
75 // Add leaves randomly
76 for (u32 iii = 0; iii < 7; iii++) {
78 pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d),
79 pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d),
80 pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d)
83 for (s16 z = 0; z <= d; z++)
84 for (s16 y = 0; y <= d; y++)
85 for (s16 x = 0; x <= d; x++) {
86 leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1;
90 // Blit leaves to vmanip
91 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
92 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
93 v3s16 pmin(leaves_a.MinEdge.X, y, z);
94 u32 i = leaves_a.index(pmin);
95 u32 vi = vmanip.m_area.index(pmin + p1);
96 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
98 if (vmanip.m_area.contains(p + p1) &&
99 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
100 vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) {
101 if (leaves_d[i] == 1) {
102 bool is_apple = pr.range(0, 99) < 10;
103 if (is_apple_tree && is_apple)
104 vmanip.m_data[vi] = applenode;
106 vmanip.m_data[vi] = leavesnode;
116 // L-System tree LUA spawner
117 treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0,
118 const NodeDefManager *ndef, const TreeDef &tree_definition)
120 ServerMap *map = &env->getServerMap();
121 std::map<v3s16, MapBlock*> modified_blocks;
122 MMVManip vmanip(map);
123 v3s16 tree_blockp = getNodeBlockPos(p0);
126 vmanip.initialEmerge(tree_blockp - v3s16(1, 1, 1), tree_blockp + v3s16(1, 3, 1));
127 e = make_ltree(vmanip, p0, ndef, tree_definition);
131 voxalgo::blit_back_with_light(map, &vmanip, &modified_blocks);
133 // Send a MEET_OTHER event
135 event.type = MEET_OTHER;
136 for (auto &modified_block : modified_blocks)
137 event.modified_blocks.insert(modified_block.first);
138 map->dispatchEvent(event);
143 //L-System tree generator
144 treegen::error make_ltree(MMVManip &vmanip, v3s16 p0,
145 const NodeDefManager *ndef, TreeDef tree_definition)
147 MapNode dirtnode(ndef->getId("mapgen_dirt"));
149 if (tree_definition.explicit_seed)
150 seed = tree_definition.seed + 14002;
152 seed = p0.X * 2 + p0.Y * 4 + p0.Z; // use the tree position to seed PRNG
153 PseudoRandom ps(seed);
155 // chance of inserting abcd rules
161 //randomize tree growth level, minimum=2
162 s16 iterations = tree_definition.iterations;
163 if (tree_definition.iterations_random_level > 0)
164 iterations -= ps.range(0, tree_definition.iterations_random_level);
168 s16 MAX_ANGLE_OFFSET = 5;
169 double angle_in_radians = (double)tree_definition.angle * M_PI / 180;
170 double angleOffset_in_radians = (s16)(ps.range(0, 1) % MAX_ANGLE_OFFSET) * M_PI / 180;
172 //initialize rotation matrix, position and stacks for branches
173 core::matrix4 rotation;
174 rotation = setRotationAxisRadians(rotation, M_PI / 2, v3f(0, 0, 1));
179 std::stack <core::matrix4> stack_orientation;
180 std::stack <v3f> stack_position;
183 std::string axiom = tree_definition.initial_axiom;
184 for (s16 i = 0; i < iterations; i++) {
186 for (s16 j = 0; j < (s16)axiom.size(); j++) {
187 char axiom_char = axiom.at(j);
188 switch (axiom_char) {
190 temp += tree_definition.rules_a;
193 temp += tree_definition.rules_b;
196 temp += tree_definition.rules_c;
199 temp += tree_definition.rules_d;
202 if (prop_a >= ps.range(1, 10))
203 temp += tree_definition.rules_a;
206 if (prop_b >= ps.range(1, 10))
207 temp += tree_definition.rules_b;
210 if (prop_c >= ps.range(1, 10))
211 temp += tree_definition.rules_c;
214 if (prop_d >= ps.range(1, 10))
215 temp += tree_definition.rules_d;
225 //make sure tree is not floating in the air
226 if (tree_definition.trunk_type == "double") {
229 v3f(position.X + 1, position.Y - 1, position.Z),
234 v3f(position.X, position.Y - 1, position.Z + 1),
239 v3f(position.X + 1, position.Y - 1, position.Z + 1),
242 } else if (tree_definition.trunk_type == "crossed") {
245 v3f(position.X + 1, position.Y - 1, position.Z),
250 v3f(position.X - 1, position.Y - 1, position.Z),
255 v3f(position.X, position.Y - 1, position.Z + 1),
260 v3f(position.X, position.Y - 1, position.Z - 1),
265 /* build tree out of generated axiom
267 Key for Special L-System Symbols used in Axioms
269 G - move forward one unit with the pen up
270 F - move forward one unit with the pen down drawing trunks and branches
271 f - move forward one unit with the pen down drawing leaves (100% chance)
272 T - move forward one unit with the pen down drawing trunks only
273 R - move forward one unit with the pen down placing fruit
274 A - replace with rules set A
275 B - replace with rules set B
276 C - replace with rules set C
277 D - replace with rules set D
278 a - replace with rules set A, chance 90%
279 b - replace with rules set B, chance 80%
280 c - replace with rules set C, chance 70%
281 d - replace with rules set D, chance 60%
282 + - yaw the turtle right by angle degrees
283 - - yaw the turtle left by angle degrees
284 & - pitch the turtle down by angle degrees
285 ^ - pitch the turtle up by angle degrees
286 / - roll the turtle to the right by angle degrees
287 * - roll the turtle to the left by angle degrees
288 [ - save in stack current state info
289 ] - recover from stack state info
294 for (s16 i = 0; i < (s16)axiom.size(); i++) {
295 char axiom_char = axiom.at(i);
296 core::matrix4 temp_rotation;
297 temp_rotation.makeIdentity();
299 switch (axiom_char) {
302 dir = transposeMatrix(rotation, dir);
306 tree_trunk_placement(
308 v3f(position.X, position.Y, position.Z),
311 if (tree_definition.trunk_type == "double" &&
312 !tree_definition.thin_branches) {
313 tree_trunk_placement(
315 v3f(position.X + 1, position.Y, position.Z),
318 tree_trunk_placement(
320 v3f(position.X, position.Y, position.Z + 1),
323 tree_trunk_placement(
325 v3f(position.X + 1, position.Y, position.Z + 1),
328 } else if (tree_definition.trunk_type == "crossed" &&
329 !tree_definition.thin_branches) {
330 tree_trunk_placement(
332 v3f(position.X + 1, position.Y, position.Z),
335 tree_trunk_placement(
337 v3f(position.X - 1, position.Y, position.Z),
340 tree_trunk_placement(
342 v3f(position.X, position.Y, position.Z + 1),
345 tree_trunk_placement(
347 v3f(position.X, position.Y, position.Z - 1),
352 dir = transposeMatrix(rotation, dir);
356 tree_trunk_placement(
358 v3f(position.X, position.Y, position.Z),
361 if ((stack_orientation.empty() &&
362 tree_definition.trunk_type == "double") ||
363 (!stack_orientation.empty() &&
364 tree_definition.trunk_type == "double" &&
365 !tree_definition.thin_branches)) {
366 tree_trunk_placement(
368 v3f(position.X +1 , position.Y, position.Z),
371 tree_trunk_placement(
373 v3f(position.X, position.Y, position.Z + 1),
376 tree_trunk_placement(
378 v3f(position.X + 1, position.Y, position.Z + 1),
381 } else if ((stack_orientation.empty() &&
382 tree_definition.trunk_type == "crossed") ||
383 (!stack_orientation.empty() &&
384 tree_definition.trunk_type == "crossed" &&
385 !tree_definition.thin_branches)) {
386 tree_trunk_placement(
388 v3f(position.X + 1, position.Y, position.Z),
391 tree_trunk_placement(
393 v3f(position.X - 1, position.Y, position.Z),
396 tree_trunk_placement(
398 v3f(position.X, position.Y, position.Z + 1),
401 tree_trunk_placement(
403 v3f(position.X, position.Y, position.Z - 1),
406 } if (!stack_orientation.empty()) {
408 for (x = -size; x <= size; x++)
409 for (y = -size; y <= size; y++)
410 for (z = -size; z <= size; z++) {
411 if (abs(x) == size &&
414 tree_leaves_placement(
416 v3f(position.X + x + 1, position.Y + y,
421 tree_leaves_placement(
423 v3f(position.X + x - 1, position.Y + y,
428 tree_leaves_placement(
429 vmanip,v3f(position.X + x, position.Y + y,
434 tree_leaves_placement(
435 vmanip,v3f(position.X + x, position.Y + y,
444 dir = transposeMatrix(rotation, dir);
448 tree_single_leaves_placement(
450 v3f(position.X, position.Y, position.Z),
455 dir = transposeMatrix(rotation, dir);
459 tree_fruit_placement(
461 v3f(position.X, position.Y, position.Z),
465 dir = transposeMatrix(rotation, dir);
469 // turtle orientation commands
471 stack_orientation.push(rotation);
472 stack_position.push(position);
475 if (stack_orientation.empty())
476 return UNBALANCED_BRACKETS;
477 rotation = stack_orientation.top();
478 stack_orientation.pop();
479 position = stack_position.top();
480 stack_position.pop();
483 temp_rotation.makeIdentity();
484 temp_rotation = setRotationAxisRadians(temp_rotation,
485 angle_in_radians + angleOffset_in_radians, v3f(0, 0, 1));
486 rotation *= temp_rotation;
489 temp_rotation.makeIdentity();
490 temp_rotation = setRotationAxisRadians(temp_rotation,
491 angle_in_radians + angleOffset_in_radians, v3f(0, 0, -1));
492 rotation *= temp_rotation;
495 temp_rotation.makeIdentity();
496 temp_rotation = setRotationAxisRadians(temp_rotation,
497 angle_in_radians + angleOffset_in_radians, v3f(0, 1, 0));
498 rotation *= temp_rotation;
501 temp_rotation.makeIdentity();
502 temp_rotation = setRotationAxisRadians(temp_rotation,
503 angle_in_radians + angleOffset_in_radians, v3f(0, -1, 0));
504 rotation *= temp_rotation;
507 temp_rotation.makeIdentity();
508 temp_rotation = setRotationAxisRadians(temp_rotation,
509 angle_in_radians, v3f(1, 0, 0));
510 rotation *= temp_rotation;
513 temp_rotation.makeIdentity();
514 temp_rotation = setRotationAxisRadians(temp_rotation,
515 angle_in_radians, v3f(-1, 0, 0));
516 rotation *= temp_rotation;
527 void tree_node_placement(MMVManip &vmanip, v3f p0, MapNode node)
529 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
530 if (!vmanip.m_area.contains(p1))
532 u32 vi = vmanip.m_area.index(p1);
533 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
534 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
536 vmanip.m_data[vmanip.m_area.index(p1)] = node;
540 void tree_trunk_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition)
542 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
543 if (!vmanip.m_area.contains(p1))
545 u32 vi = vmanip.m_area.index(p1);
546 content_t current_node = vmanip.m_data[vi].getContent();
547 if (current_node != CONTENT_AIR && current_node != CONTENT_IGNORE
548 && current_node != tree_definition.leavesnode.getContent()
549 && current_node != tree_definition.leaves2node.getContent()
550 && current_node != tree_definition.fruitnode.getContent())
552 vmanip.m_data[vi] = tree_definition.trunknode;
556 void tree_leaves_placement(MMVManip &vmanip, v3f p0,
557 PseudoRandom ps, TreeDef &tree_definition)
559 MapNode leavesnode = tree_definition.leavesnode;
560 if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance)
561 leavesnode = tree_definition.leaves2node;
562 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
563 if (!vmanip.m_area.contains(p1))
565 u32 vi = vmanip.m_area.index(p1);
566 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
567 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
569 if (tree_definition.fruit_chance > 0) {
570 if (ps.range(1, 100) > 100 - tree_definition.fruit_chance)
571 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
573 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
574 } else if (ps.range(1, 100) > 20) {
575 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
580 void tree_single_leaves_placement(MMVManip &vmanip, v3f p0,
581 PseudoRandom ps, TreeDef &tree_definition)
583 MapNode leavesnode = tree_definition.leavesnode;
584 if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance)
585 leavesnode = tree_definition.leaves2node;
586 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
587 if (!vmanip.m_area.contains(p1))
589 u32 vi = vmanip.m_area.index(p1);
590 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
591 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
593 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
597 void tree_fruit_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition)
599 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
600 if (!vmanip.m_area.contains(p1))
602 u32 vi = vmanip.m_area.index(p1);
603 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
604 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
606 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
610 irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis)
612 double c = cos(angle);
613 double s = sin(angle);
616 double tx = t * axis.X;
617 double ty = t * axis.Y;
618 double tz = t * axis.Z;
619 double sx = s * axis.X;
620 double sy = s * axis.Y;
621 double sz = s * axis.Z;
623 M[0] = tx * axis.X + c;
624 M[1] = tx * axis.Y + sz;
625 M[2] = tx * axis.Z - sy;
627 M[4] = ty * axis.X - sz;
628 M[5] = ty * axis.Y + c;
629 M[6] = ty * axis.Z + sx;
631 M[8] = tz * axis.X + sy;
632 M[9] = tz * axis.Y - sx;
633 M[10] = tz * axis.Z + c;
638 v3f transposeMatrix(irr::core::matrix4 M, v3f v)
641 double x = M[0] * v.X + M[4] * v.Y + M[8] * v.Z +M[12];
642 double y = M[1] * v.X + M[5] * v.Y + M[9] * v.Z +M[13];
643 double z = M[2] * v.X + M[6] * v.Y + M[10] * v.Z +M[14];
651 void make_jungletree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef,
655 NOTE: Tree-placing code is currently duplicated in the engine
656 and in games that have saplings; both are deprecated but not
659 content_t c_tree = ndef->getId("mapgen_jungletree");
660 content_t c_leaves = ndef->getId("mapgen_jungleleaves");
661 if (c_tree == CONTENT_IGNORE)
662 c_tree = ndef->getId("mapgen_tree");
663 if (c_leaves == CONTENT_IGNORE)
664 c_leaves = ndef->getId("mapgen_leaves");
666 MapNode treenode(c_tree);
667 MapNode leavesnode(c_leaves);
669 PseudoRandom pr(seed);
670 for (s16 x= -1; x <= 1; x++)
671 for (s16 z= -1; z <= 1; z++) {
672 if (pr.range(0, 2) == 0)
674 v3s16 p1 = p0 + v3s16(x, 0, z);
675 v3s16 p2 = p0 + v3s16(x, -1, z);
676 u32 vi1 = vmanip.m_area.index(p1);
677 u32 vi2 = vmanip.m_area.index(p2);
679 if (vmanip.m_area.contains(p2) &&
680 vmanip.m_data[vi2].getContent() == CONTENT_AIR)
681 vmanip.m_data[vi2] = treenode;
682 else if (vmanip.m_area.contains(p1) &&
683 vmanip.m_data[vi1].getContent() == CONTENT_AIR)
684 vmanip.m_data[vi1] = treenode;
686 vmanip.m_data[vmanip.m_area.index(p0)] = treenode;
688 s16 trunk_h = pr.range(8, 12);
690 for (s16 ii = 0; ii < trunk_h; ii++) {
691 if (vmanip.m_area.contains(p1)) {
692 u32 vi = vmanip.m_area.index(p1);
693 vmanip.m_data[vi] = treenode;
698 // p1 is now the last piece of the trunk
701 VoxelArea leaves_a(v3s16(-3, -2, -3), v3s16(3, 2, 3));
702 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
703 Buffer<u8> leaves_d(leaves_a.getVolume());
704 for (s32 i = 0; i < leaves_a.getVolume(); i++)
707 // Force leaves at near the end of the trunk
709 for (s16 z = -d; z <= d; z++)
710 for (s16 y = -d; y <= d; y++)
711 for (s16 x = -d; x <= d; x++) {
712 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
715 // Add leaves randomly
716 for (u32 iii = 0; iii < 30; iii++) {
718 pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d),
719 pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d),
720 pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d)
723 for (s16 z = 0; z <= d; z++)
724 for (s16 y = 0; y <= d; y++)
725 for (s16 x = 0; x <= d; x++) {
726 leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1;
730 // Blit leaves to vmanip
731 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
732 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
733 v3s16 pmin(leaves_a.MinEdge.X, y, z);
734 u32 i = leaves_a.index(pmin);
735 u32 vi = vmanip.m_area.index(pmin + p1);
736 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
738 if (vmanip.m_area.contains(p + p1) &&
739 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
740 vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) {
741 if (leaves_d[i] == 1)
742 vmanip.m_data[vi] = leavesnode;
751 void make_pine_tree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef,
755 NOTE: Tree-placing code is currently duplicated in the engine
756 and in games that have saplings; both are deprecated but not
759 content_t c_tree = ndef->getId("mapgen_pine_tree");
760 content_t c_leaves = ndef->getId("mapgen_pine_needles");
761 content_t c_snow = ndef->getId("mapgen_snow");
762 if (c_tree == CONTENT_IGNORE)
763 c_tree = ndef->getId("mapgen_tree");
764 if (c_leaves == CONTENT_IGNORE)
765 c_leaves = ndef->getId("mapgen_leaves");
766 if (c_snow == CONTENT_IGNORE)
767 c_snow = CONTENT_AIR;
769 MapNode treenode(c_tree);
770 MapNode leavesnode(c_leaves);
771 MapNode snownode(c_snow);
773 PseudoRandom pr(seed);
774 u16 trunk_h = pr.range(9, 13);
776 for (u16 ii = 0; ii < trunk_h; ii++) {
777 if (vmanip.m_area.contains(p1)) {
778 u32 vi = vmanip.m_area.index(p1);
779 vmanip.m_data[vi] = treenode;
784 // Make p1 the top node of the trunk
787 VoxelArea leaves_a(v3s16(-3, -6, -3), v3s16(3, 3, 3));
788 Buffer<u8> leaves_d(leaves_a.getVolume());
789 for (s32 i = 0; i < leaves_a.getVolume(); i++)
794 for (s16 yy = -1; yy <= 1; yy++) {
795 for (s16 zz = -dev; zz <= dev; zz++) {
796 u32 i = leaves_a.index(v3s16(-dev, yy, zz));
797 u32 ia = leaves_a.index(v3s16(-dev, yy+1, zz));
798 for (s16 xx = -dev; xx <= dev; xx++) {
799 if (pr.range(0, 20) <= 19 - dev) {
811 leaves_d[leaves_a.index(v3s16(0, 1, 0))] = 1;
812 leaves_d[leaves_a.index(v3s16(0, 2, 0))] = 1;
813 leaves_d[leaves_a.index(v3s16(0, 3, 0))] = 2;
817 for (u32 iii = 0; iii < 20; iii++) {
818 s16 xi = pr.range(-3, 2);
819 s16 yy = pr.range(-6, -5);
820 s16 zi = pr.range(-3, 2);
823 for (s16 zz = zi; zz <= zi + 1; zz++) {
824 u32 i = leaves_a.index(v3s16(xi, yy, zz));
825 u32 ia = leaves_a.index(v3s16(xi, yy + 1, zz));
826 for (s32 xx = xi; xx <= xi + 1; xx++) {
828 if (leaves_d[ia] == 0)
837 for (s16 yy = my + 1; yy <= my + 2; yy++) {
838 for (s16 zz = -dev; zz <= dev; zz++) {
839 u32 i = leaves_a.index(v3s16(-dev, yy, zz));
840 u32 ia = leaves_a.index(v3s16(-dev, yy + 1, zz));
841 for (s16 xx = -dev; xx <= dev; xx++) {
842 if (pr.range(0, 20) <= 19 - dev) {
853 // Blit leaves to vmanip
854 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
855 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
856 v3s16 pmin(leaves_a.MinEdge.X, y, z);
857 u32 i = leaves_a.index(pmin);
858 u32 vi = vmanip.m_area.index(pmin + p1);
859 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
861 if (vmanip.m_area.contains(p + p1) &&
862 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
863 vmanip.m_data[vi].getContent() == CONTENT_IGNORE ||
864 vmanip.m_data[vi] == snownode)) {
865 if (leaves_d[i] == 1)
866 vmanip.m_data[vi] = leavesnode;
867 else if (leaves_d[i] == 2)
868 vmanip.m_data[vi] = snownode;
876 }; // namespace treegen