3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>,
4 2012-2013 RealBadAngel, Maciej Kasatkin <mk@realbadangel.pl>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "util/pointer.h"
23 #include "util/numeric.h"
26 #include "serverenvironment.h"
29 #include "voxelalgorithms.h"
34 void make_tree(MMVManip &vmanip, v3s16 p0,
35 bool is_apple_tree, INodeDefManager *ndef, s32 seed)
38 NOTE: Tree-placing code is currently duplicated in the engine
39 and in games that have saplings; both are deprecated but not
42 MapNode treenode(ndef->getId("mapgen_tree"));
43 MapNode leavesnode(ndef->getId("mapgen_leaves"));
44 MapNode applenode(ndef->getId("mapgen_apple"));
46 PseudoRandom pr(seed);
47 s16 trunk_h = pr.range(4, 5);
49 for (s16 ii = 0; ii < trunk_h; ii++) {
50 if (vmanip.m_area.contains(p1)) {
51 u32 vi = vmanip.m_area.index(p1);
52 vmanip.m_data[vi] = treenode;
57 // p1 is now the last piece of the trunk
60 VoxelArea leaves_a(v3s16(-2, -1, -2), v3s16(2, 2, 2));
61 Buffer<u8> leaves_d(leaves_a.getVolume());
62 for (s32 i = 0; i < leaves_a.getVolume(); i++)
65 // Force leaves at near the end of the trunk
67 for (s16 z = -d; z <= d; z++)
68 for (s16 y = -d; y <= d; y++)
69 for (s16 x = -d; x <= d; x++) {
70 leaves_d[leaves_a.index(v3s16(x, y, z))] = 1;
73 // Add leaves randomly
74 for (u32 iii = 0; iii < 7; iii++) {
76 pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d),
77 pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d),
78 pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d)
81 for (s16 z = 0; z <= d; z++)
82 for (s16 y = 0; y <= d; y++)
83 for (s16 x = 0; x <= d; x++) {
84 leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1;
88 // Blit leaves to vmanip
89 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
90 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
91 v3s16 pmin(leaves_a.MinEdge.X, y, z);
92 u32 i = leaves_a.index(pmin);
93 u32 vi = vmanip.m_area.index(pmin + p1);
94 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
96 if (vmanip.m_area.contains(p + p1) &&
97 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
98 vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) {
99 if (leaves_d[i] == 1) {
100 bool is_apple = pr.range(0, 99) < 10;
101 if (is_apple_tree && is_apple)
102 vmanip.m_data[vi] = applenode;
104 vmanip.m_data[vi] = leavesnode;
114 // L-System tree LUA spawner
115 treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0,
116 INodeDefManager *ndef, const TreeDef &tree_definition)
118 ServerMap *map = &env->getServerMap();
119 std::map<v3s16, MapBlock*> modified_blocks;
120 MMVManip vmanip(map);
121 v3s16 tree_blockp = getNodeBlockPos(p0);
124 vmanip.initialEmerge(tree_blockp - v3s16(1, 1, 1), tree_blockp + v3s16(1, 3, 1));
125 e = make_ltree(vmanip, p0, ndef, tree_definition);
129 voxalgo::blit_back_with_light(map, &vmanip, &modified_blocks);
131 // Send a MEET_OTHER event
133 event.type = MEET_OTHER;
134 for (auto &modified_block : modified_blocks)
135 event.modified_blocks.insert(modified_block.first);
136 map->dispatchEvent(&event);
141 //L-System tree generator
142 treegen::error make_ltree(MMVManip &vmanip, v3s16 p0,
143 INodeDefManager *ndef, TreeDef tree_definition)
145 MapNode dirtnode(ndef->getId("mapgen_dirt"));
147 if (tree_definition.explicit_seed)
148 seed = tree_definition.seed + 14002;
150 seed = p0.X * 2 + p0.Y * 4 + p0.Z; // use the tree position to seed PRNG
151 PseudoRandom ps(seed);
153 // chance of inserting abcd rules
159 //randomize tree growth level, minimum=2
160 s16 iterations = tree_definition.iterations;
161 if (tree_definition.iterations_random_level > 0)
162 iterations -= ps.range(0, tree_definition.iterations_random_level);
166 s16 MAX_ANGLE_OFFSET = 5;
167 double angle_in_radians = (double)tree_definition.angle * M_PI / 180;
168 double angleOffset_in_radians = (s16)(ps.range(0, 1) % MAX_ANGLE_OFFSET) * M_PI / 180;
170 //initialize rotation matrix, position and stacks for branches
171 core::matrix4 rotation;
172 rotation = setRotationAxisRadians(rotation, M_PI / 2, v3f(0, 0, 1));
177 std::stack <core::matrix4> stack_orientation;
178 std::stack <v3f> stack_position;
181 std::string axiom = tree_definition.initial_axiom;
182 for (s16 i = 0; i < iterations; i++) {
184 for (s16 j = 0; j < (s16)axiom.size(); j++) {
185 char axiom_char = axiom.at(j);
186 switch (axiom_char) {
188 temp += tree_definition.rules_a;
191 temp += tree_definition.rules_b;
194 temp += tree_definition.rules_c;
197 temp += tree_definition.rules_d;
200 if (prop_a >= ps.range(1, 10))
201 temp += tree_definition.rules_a;
204 if (prop_b >= ps.range(1, 10))
205 temp += tree_definition.rules_b;
208 if (prop_c >= ps.range(1, 10))
209 temp += tree_definition.rules_c;
212 if (prop_d >= ps.range(1, 10))
213 temp += tree_definition.rules_d;
223 //make sure tree is not floating in the air
224 if (tree_definition.trunk_type == "double") {
227 v3f(position.X + 1, position.Y - 1, position.Z),
232 v3f(position.X, position.Y - 1, position.Z + 1),
237 v3f(position.X + 1, position.Y - 1, position.Z + 1),
240 } else if (tree_definition.trunk_type == "crossed") {
243 v3f(position.X + 1, position.Y - 1, position.Z),
248 v3f(position.X - 1, position.Y - 1, position.Z),
253 v3f(position.X, position.Y - 1, position.Z + 1),
258 v3f(position.X, position.Y - 1, position.Z - 1),
263 /* build tree out of generated axiom
265 Key for Special L-System Symbols used in Axioms
267 G - move forward one unit with the pen up
268 F - move forward one unit with the pen down drawing trunks and branches
269 f - move forward one unit with the pen down drawing leaves (100% chance)
270 T - move forward one unit with the pen down drawing trunks only
271 R - move forward one unit with the pen down placing fruit
272 A - replace with rules set A
273 B - replace with rules set B
274 C - replace with rules set C
275 D - replace with rules set D
276 a - replace with rules set A, chance 90%
277 b - replace with rules set B, chance 80%
278 c - replace with rules set C, chance 70%
279 d - replace with rules set D, chance 60%
280 + - yaw the turtle right by angle degrees
281 - - yaw the turtle left by angle degrees
282 & - pitch the turtle down by angle degrees
283 ^ - pitch the turtle up by angle degrees
284 / - roll the turtle to the right by angle degrees
285 * - roll the turtle to the left by angle degrees
286 [ - save in stack current state info
287 ] - recover from stack state info
292 for (s16 i = 0; i < (s16)axiom.size(); i++) {
293 char axiom_char = axiom.at(i);
294 core::matrix4 temp_rotation;
295 temp_rotation.makeIdentity();
297 switch (axiom_char) {
300 dir = transposeMatrix(rotation, dir);
304 tree_trunk_placement(
306 v3f(position.X, position.Y, position.Z),
309 if (tree_definition.trunk_type == "double" &&
310 !tree_definition.thin_branches) {
311 tree_trunk_placement(
313 v3f(position.X + 1, position.Y, position.Z),
316 tree_trunk_placement(
318 v3f(position.X, position.Y, position.Z + 1),
321 tree_trunk_placement(
323 v3f(position.X + 1, position.Y, position.Z + 1),
326 } else if (tree_definition.trunk_type == "crossed" &&
327 !tree_definition.thin_branches) {
328 tree_trunk_placement(
330 v3f(position.X + 1, position.Y, position.Z),
333 tree_trunk_placement(
335 v3f(position.X - 1, position.Y, position.Z),
338 tree_trunk_placement(
340 v3f(position.X, position.Y, position.Z + 1),
343 tree_trunk_placement(
345 v3f(position.X, position.Y, position.Z - 1),
350 dir = transposeMatrix(rotation, dir);
354 tree_trunk_placement(
356 v3f(position.X, position.Y, position.Z),
359 if ((stack_orientation.empty() &&
360 tree_definition.trunk_type == "double") ||
361 (!stack_orientation.empty() &&
362 tree_definition.trunk_type == "double" &&
363 !tree_definition.thin_branches)) {
364 tree_trunk_placement(
366 v3f(position.X +1 , position.Y, position.Z),
369 tree_trunk_placement(
371 v3f(position.X, position.Y, position.Z + 1),
374 tree_trunk_placement(
376 v3f(position.X + 1, position.Y, position.Z + 1),
379 } else if ((stack_orientation.empty() &&
380 tree_definition.trunk_type == "crossed") ||
381 (!stack_orientation.empty() &&
382 tree_definition.trunk_type == "crossed" &&
383 !tree_definition.thin_branches)) {
384 tree_trunk_placement(
386 v3f(position.X + 1, position.Y, position.Z),
389 tree_trunk_placement(
391 v3f(position.X - 1, position.Y, position.Z),
394 tree_trunk_placement(
396 v3f(position.X, position.Y, position.Z + 1),
399 tree_trunk_placement(
401 v3f(position.X, position.Y, position.Z - 1),
404 } if (!stack_orientation.empty()) {
406 for (x = -size; x <= size; x++)
407 for (y = -size; y <= size; y++)
408 for (z = -size; z <= size; z++) {
409 if (abs(x) == size &&
412 tree_leaves_placement(
414 v3f(position.X + x + 1, position.Y + y,
419 tree_leaves_placement(
421 v3f(position.X + x - 1, position.Y + y,
426 tree_leaves_placement(
427 vmanip,v3f(position.X + x, position.Y + y,
432 tree_leaves_placement(
433 vmanip,v3f(position.X + x, position.Y + y,
442 dir = transposeMatrix(rotation, dir);
446 tree_single_leaves_placement(
448 v3f(position.X, position.Y, position.Z),
453 dir = transposeMatrix(rotation, dir);
457 tree_fruit_placement(
459 v3f(position.X, position.Y, position.Z),
463 dir = transposeMatrix(rotation, dir);
467 // turtle orientation commands
469 stack_orientation.push(rotation);
470 stack_position.push(position);
473 if (stack_orientation.empty())
474 return UNBALANCED_BRACKETS;
475 rotation = stack_orientation.top();
476 stack_orientation.pop();
477 position = stack_position.top();
478 stack_position.pop();
481 temp_rotation.makeIdentity();
482 temp_rotation = setRotationAxisRadians(temp_rotation,
483 angle_in_radians + angleOffset_in_radians, v3f(0, 0, 1));
484 rotation *= temp_rotation;
487 temp_rotation.makeIdentity();
488 temp_rotation = setRotationAxisRadians(temp_rotation,
489 angle_in_radians + angleOffset_in_radians, v3f(0, 0, -1));
490 rotation *= temp_rotation;
493 temp_rotation.makeIdentity();
494 temp_rotation = setRotationAxisRadians(temp_rotation,
495 angle_in_radians + angleOffset_in_radians, v3f(0, 1, 0));
496 rotation *= temp_rotation;
499 temp_rotation.makeIdentity();
500 temp_rotation = setRotationAxisRadians(temp_rotation,
501 angle_in_radians + angleOffset_in_radians, v3f(0, -1, 0));
502 rotation *= temp_rotation;
505 temp_rotation.makeIdentity();
506 temp_rotation = setRotationAxisRadians(temp_rotation,
507 angle_in_radians, v3f(1, 0, 0));
508 rotation *= temp_rotation;
511 temp_rotation.makeIdentity();
512 temp_rotation = setRotationAxisRadians(temp_rotation,
513 angle_in_radians, v3f(-1, 0, 0));
514 rotation *= temp_rotation;
525 void tree_node_placement(MMVManip &vmanip, v3f p0, MapNode node)
527 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
528 if (!vmanip.m_area.contains(p1))
530 u32 vi = vmanip.m_area.index(p1);
531 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
532 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
534 vmanip.m_data[vmanip.m_area.index(p1)] = node;
538 void tree_trunk_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition)
540 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
541 if (!vmanip.m_area.contains(p1))
543 u32 vi = vmanip.m_area.index(p1);
544 content_t current_node = vmanip.m_data[vi].getContent();
545 if (current_node != CONTENT_AIR && current_node != CONTENT_IGNORE
546 && current_node != tree_definition.leavesnode.getContent()
547 && current_node != tree_definition.leaves2node.getContent()
548 && current_node != tree_definition.fruitnode.getContent())
550 vmanip.m_data[vi] = tree_definition.trunknode;
554 void tree_leaves_placement(MMVManip &vmanip, v3f p0,
555 PseudoRandom ps, TreeDef &tree_definition)
557 MapNode leavesnode = tree_definition.leavesnode;
558 if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance)
559 leavesnode = tree_definition.leaves2node;
560 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
561 if (!vmanip.m_area.contains(p1))
563 u32 vi = vmanip.m_area.index(p1);
564 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
565 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
567 if (tree_definition.fruit_chance > 0) {
568 if (ps.range(1, 100) > 100 - tree_definition.fruit_chance)
569 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
571 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
572 } else if (ps.range(1, 100) > 20) {
573 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
578 void tree_single_leaves_placement(MMVManip &vmanip, v3f p0,
579 PseudoRandom ps, TreeDef &tree_definition)
581 MapNode leavesnode = tree_definition.leavesnode;
582 if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance)
583 leavesnode = tree_definition.leaves2node;
584 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
585 if (!vmanip.m_area.contains(p1))
587 u32 vi = vmanip.m_area.index(p1);
588 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
589 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
591 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
595 void tree_fruit_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition)
597 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
598 if (!vmanip.m_area.contains(p1))
600 u32 vi = vmanip.m_area.index(p1);
601 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
602 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
604 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
608 irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis)
610 double c = cos(angle);
611 double s = sin(angle);
614 double tx = t * axis.X;
615 double ty = t * axis.Y;
616 double tz = t * axis.Z;
617 double sx = s * axis.X;
618 double sy = s * axis.Y;
619 double sz = s * axis.Z;
621 M[0] = tx * axis.X + c;
622 M[1] = tx * axis.Y + sz;
623 M[2] = tx * axis.Z - sy;
625 M[4] = ty * axis.X - sz;
626 M[5] = ty * axis.Y + c;
627 M[6] = ty * axis.Z + sx;
629 M[8] = tz * axis.X + sy;
630 M[9] = tz * axis.Y - sx;
631 M[10] = tz * axis.Z + c;
636 v3f transposeMatrix(irr::core::matrix4 M, v3f v)
639 double x = M[0] * v.X + M[4] * v.Y + M[8] * v.Z +M[12];
640 double y = M[1] * v.X + M[5] * v.Y + M[9] * v.Z +M[13];
641 double z = M[2] * v.X + M[6] * v.Y + M[10] * v.Z +M[14];
649 void make_jungletree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, s32 seed)
652 NOTE: Tree-placing code is currently duplicated in the engine
653 and in games that have saplings; both are deprecated but not
656 content_t c_tree = ndef->getId("mapgen_jungletree");
657 content_t c_leaves = ndef->getId("mapgen_jungleleaves");
658 if (c_tree == CONTENT_IGNORE)
659 c_tree = ndef->getId("mapgen_tree");
660 if (c_leaves == CONTENT_IGNORE)
661 c_leaves = ndef->getId("mapgen_leaves");
663 MapNode treenode(c_tree);
664 MapNode leavesnode(c_leaves);
666 PseudoRandom pr(seed);
667 for (s16 x= -1; x <= 1; x++)
668 for (s16 z= -1; z <= 1; z++) {
669 if (pr.range(0, 2) == 0)
671 v3s16 p1 = p0 + v3s16(x, 0, z);
672 v3s16 p2 = p0 + v3s16(x, -1, z);
673 u32 vi1 = vmanip.m_area.index(p1);
674 u32 vi2 = vmanip.m_area.index(p2);
676 if (vmanip.m_area.contains(p2) &&
677 vmanip.m_data[vi2].getContent() == CONTENT_AIR)
678 vmanip.m_data[vi2] = treenode;
679 else if (vmanip.m_area.contains(p1) &&
680 vmanip.m_data[vi1].getContent() == CONTENT_AIR)
681 vmanip.m_data[vi1] = treenode;
683 vmanip.m_data[vmanip.m_area.index(p0)] = treenode;
685 s16 trunk_h = pr.range(8, 12);
687 for (s16 ii = 0; ii < trunk_h; ii++) {
688 if (vmanip.m_area.contains(p1)) {
689 u32 vi = vmanip.m_area.index(p1);
690 vmanip.m_data[vi] = treenode;
695 // p1 is now the last piece of the trunk
698 VoxelArea leaves_a(v3s16(-3, -2, -3), v3s16(3, 2, 3));
699 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
700 Buffer<u8> leaves_d(leaves_a.getVolume());
701 for (s32 i = 0; i < leaves_a.getVolume(); i++)
704 // Force leaves at near the end of the trunk
706 for (s16 z = -d; z <= d; z++)
707 for (s16 y = -d; y <= d; y++)
708 for (s16 x = -d; x <= d; x++) {
709 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
712 // Add leaves randomly
713 for (u32 iii = 0; iii < 30; iii++) {
715 pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d),
716 pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d),
717 pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d)
720 for (s16 z = 0; z <= d; z++)
721 for (s16 y = 0; y <= d; y++)
722 for (s16 x = 0; x <= d; x++) {
723 leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1;
727 // Blit leaves to vmanip
728 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
729 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
730 v3s16 pmin(leaves_a.MinEdge.X, y, z);
731 u32 i = leaves_a.index(pmin);
732 u32 vi = vmanip.m_area.index(pmin + p1);
733 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
735 if (vmanip.m_area.contains(p + p1) &&
736 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
737 vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) {
738 if (leaves_d[i] == 1)
739 vmanip.m_data[vi] = leavesnode;
748 void make_pine_tree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, s32 seed)
751 NOTE: Tree-placing code is currently duplicated in the engine
752 and in games that have saplings; both are deprecated but not
755 content_t c_tree = ndef->getId("mapgen_pine_tree");
756 content_t c_leaves = ndef->getId("mapgen_pine_needles");
757 content_t c_snow = ndef->getId("mapgen_snow");
758 if (c_tree == CONTENT_IGNORE)
759 c_tree = ndef->getId("mapgen_tree");
760 if (c_leaves == CONTENT_IGNORE)
761 c_leaves = ndef->getId("mapgen_leaves");
762 if (c_snow == CONTENT_IGNORE)
763 c_snow = CONTENT_AIR;
765 MapNode treenode(c_tree);
766 MapNode leavesnode(c_leaves);
767 MapNode snownode(c_snow);
769 PseudoRandom pr(seed);
770 u16 trunk_h = pr.range(9, 13);
772 for (u16 ii = 0; ii < trunk_h; ii++) {
773 if (vmanip.m_area.contains(p1)) {
774 u32 vi = vmanip.m_area.index(p1);
775 vmanip.m_data[vi] = treenode;
780 // Make p1 the top node of the trunk
783 VoxelArea leaves_a(v3s16(-3, -6, -3), v3s16(3, 3, 3));
784 Buffer<u8> leaves_d(leaves_a.getVolume());
785 for (s32 i = 0; i < leaves_a.getVolume(); i++)
790 for (s16 yy = -1; yy <= 1; yy++) {
791 for (s16 zz = -dev; zz <= dev; zz++) {
792 u32 i = leaves_a.index(v3s16(-dev, yy, zz));
793 u32 ia = leaves_a.index(v3s16(-dev, yy+1, zz));
794 for (s16 xx = -dev; xx <= dev; xx++) {
795 if (pr.range(0, 20) <= 19 - dev) {
807 leaves_d[leaves_a.index(v3s16(0, 1, 0))] = 1;
808 leaves_d[leaves_a.index(v3s16(0, 2, 0))] = 1;
809 leaves_d[leaves_a.index(v3s16(0, 3, 0))] = 2;
813 for (u32 iii = 0; iii < 20; iii++) {
814 s16 xi = pr.range(-3, 2);
815 s16 yy = pr.range(-6, -5);
816 s16 zi = pr.range(-3, 2);
819 for (s16 zz = zi; zz <= zi + 1; zz++) {
820 u32 i = leaves_a.index(v3s16(xi, yy, zz));
821 u32 ia = leaves_a.index(v3s16(xi, yy + 1, zz));
822 for (s32 xx = xi; xx <= xi + 1; xx++) {
824 if (leaves_d[ia] == 0)
833 for (s16 yy = my + 1; yy <= my + 2; yy++) {
834 for (s16 zz = -dev; zz <= dev; zz++) {
835 u32 i = leaves_a.index(v3s16(-dev, yy, zz));
836 u32 ia = leaves_a.index(v3s16(-dev, yy + 1, zz));
837 for (s16 xx = -dev; xx <= dev; xx++) {
838 if (pr.range(0, 20) <= 19 - dev) {
849 // Blit leaves to vmanip
850 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
851 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
852 v3s16 pmin(leaves_a.MinEdge.X, y, z);
853 u32 i = leaves_a.index(pmin);
854 u32 vi = vmanip.m_area.index(pmin + p1);
855 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
857 if (vmanip.m_area.contains(p + p1) &&
858 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
859 vmanip.m_data[vi].getContent() == CONTENT_IGNORE ||
860 vmanip.m_data[vi] == snownode)) {
861 if (leaves_d[i] == 1)
862 vmanip.m_data[vi] = leavesnode;
863 else if (leaves_d[i] == 2)
864 vmanip.m_data[vi] = snownode;
872 }; // namespace treegen