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"
30 #include "voxelalgorithms.h"
35 void make_tree(MMVManip &vmanip, v3s16 p0, bool is_apple_tree,
36 const NodeDefManager *ndef, s32 seed)
39 NOTE: Tree-placing code is currently duplicated in the engine
40 and in games that have saplings; both are deprecated but not
43 MapNode treenode(ndef->getId("mapgen_tree"));
44 MapNode leavesnode(ndef->getId("mapgen_leaves"));
45 MapNode applenode(ndef->getId("mapgen_apple"));
46 if (treenode == CONTENT_IGNORE)
47 errorstream << "Treegen: Mapgen alias 'mapgen_tree' is invalid!" << std::endl;
48 if (leavesnode == CONTENT_IGNORE)
49 errorstream << "Treegen: Mapgen alias 'mapgen_leaves' is invalid!" << std::endl;
50 if (applenode == CONTENT_IGNORE)
51 errorstream << "Treegen: Mapgen alias 'mapgen_apple' is invalid!" << std::endl;
53 PseudoRandom pr(seed);
54 s16 trunk_h = pr.range(4, 5);
56 for (s16 ii = 0; ii < trunk_h; ii++) {
57 if (vmanip.m_area.contains(p1)) {
58 u32 vi = vmanip.m_area.index(p1);
59 vmanip.m_data[vi] = treenode;
64 // p1 is now the last piece of the trunk
67 VoxelArea leaves_a(v3s16(-2, -1, -2), v3s16(2, 2, 2));
68 Buffer<u8> leaves_d(leaves_a.getVolume());
69 for (s32 i = 0; i < leaves_a.getVolume(); i++)
72 // Force leaves at near the end of the trunk
74 for (s16 z = -d; z <= d; z++)
75 for (s16 y = -d; y <= d; y++)
76 for (s16 x = -d; x <= d; x++) {
77 leaves_d[leaves_a.index(v3s16(x, y, z))] = 1;
80 // Add leaves randomly
81 for (u32 iii = 0; iii < 7; iii++) {
83 pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d),
84 pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d),
85 pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d)
88 for (s16 z = 0; z <= d; z++)
89 for (s16 y = 0; y <= d; y++)
90 for (s16 x = 0; x <= d; x++) {
91 leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1;
95 // Blit leaves to vmanip
96 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
97 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
98 v3s16 pmin(leaves_a.MinEdge.X, y, z);
99 u32 i = leaves_a.index(pmin);
100 u32 vi = vmanip.m_area.index(pmin + p1);
101 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
103 if (vmanip.m_area.contains(p + p1) &&
104 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
105 vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) {
106 if (leaves_d[i] == 1) {
107 bool is_apple = pr.range(0, 99) < 10;
108 if (is_apple_tree && is_apple)
109 vmanip.m_data[vi] = applenode;
111 vmanip.m_data[vi] = leavesnode;
121 // L-System tree LUA spawner
122 treegen::error spawn_ltree(ServerMap *map, v3s16 p0,
123 const NodeDefManager *ndef, const TreeDef &tree_definition)
125 std::map<v3s16, MapBlock*> modified_blocks;
126 MMVManip vmanip(map);
127 v3s16 tree_blockp = getNodeBlockPos(p0);
130 vmanip.initialEmerge(tree_blockp - v3s16(1, 1, 1), tree_blockp + v3s16(1, 3, 1));
131 e = make_ltree(vmanip, p0, ndef, tree_definition);
135 voxalgo::blit_back_with_light(map, &vmanip, &modified_blocks);
137 // Send a MEET_OTHER event
139 event.type = MEET_OTHER;
140 for (auto &modified_block : modified_blocks)
141 event.modified_blocks.insert(modified_block.first);
142 map->dispatchEvent(event);
147 //L-System tree generator
148 treegen::error make_ltree(MMVManip &vmanip, v3s16 p0,
149 const NodeDefManager *ndef, TreeDef tree_definition)
152 if (tree_definition.explicit_seed)
153 seed = tree_definition.seed + 14002;
155 seed = p0.X * 2 + p0.Y * 4 + p0.Z; // use the tree position to seed PRNG
156 PseudoRandom ps(seed);
158 // chance of inserting abcd rules
164 //randomize tree growth level, minimum=2
165 s16 iterations = tree_definition.iterations;
166 if (tree_definition.iterations_random_level > 0)
167 iterations -= ps.range(0, tree_definition.iterations_random_level);
171 s16 MAX_ANGLE_OFFSET = 5;
172 double angle_in_radians = (double)tree_definition.angle * M_PI / 180;
173 double angleOffset_in_radians = (s16)(ps.range(0, 1) % MAX_ANGLE_OFFSET) * M_PI / 180;
175 //initialize rotation matrix, position and stacks for branches
176 core::matrix4 rotation;
177 rotation = setRotationAxisRadians(rotation, M_PI / 2, v3f(0, 0, 1));
182 std::stack <core::matrix4> stack_orientation;
183 std::stack <v3f> stack_position;
186 std::string axiom = tree_definition.initial_axiom;
187 for (s16 i = 0; i < iterations; i++) {
189 for (s16 j = 0; j < (s16)axiom.size(); j++) {
190 char axiom_char = axiom.at(j);
191 switch (axiom_char) {
193 temp += tree_definition.rules_a;
196 temp += tree_definition.rules_b;
199 temp += tree_definition.rules_c;
202 temp += tree_definition.rules_d;
205 if (prop_a >= ps.range(1, 10))
206 temp += tree_definition.rules_a;
209 if (prop_b >= ps.range(1, 10))
210 temp += tree_definition.rules_b;
213 if (prop_c >= ps.range(1, 10))
214 temp += tree_definition.rules_c;
217 if (prop_d >= ps.range(1, 10))
218 temp += tree_definition.rules_d;
228 // Add trunk nodes below a wide trunk to avoid gaps when tree is on sloping ground
229 if (tree_definition.trunk_type == "double") {
230 tree_trunk_placement(
232 v3f(position.X + 1, position.Y - 1, position.Z),
235 tree_trunk_placement(
237 v3f(position.X, position.Y - 1, position.Z + 1),
240 tree_trunk_placement(
242 v3f(position.X + 1, position.Y - 1, position.Z + 1),
245 } else if (tree_definition.trunk_type == "crossed") {
246 tree_trunk_placement(
248 v3f(position.X + 1, position.Y - 1, position.Z),
251 tree_trunk_placement(
253 v3f(position.X - 1, position.Y - 1, position.Z),
256 tree_trunk_placement(
258 v3f(position.X, position.Y - 1, position.Z + 1),
261 tree_trunk_placement(
263 v3f(position.X, position.Y - 1, position.Z - 1),
268 /* build tree out of generated axiom
270 Key for Special L-System Symbols used in Axioms
272 G - move forward one unit with the pen up
273 F - move forward one unit with the pen down drawing trunks and branches
274 f - move forward one unit with the pen down drawing leaves (100% chance)
275 T - move forward one unit with the pen down drawing trunks only
276 R - move forward one unit with the pen down placing fruit
277 A - replace with rules set A
278 B - replace with rules set B
279 C - replace with rules set C
280 D - replace with rules set D
281 a - replace with rules set A, chance 90%
282 b - replace with rules set B, chance 80%
283 c - replace with rules set C, chance 70%
284 d - replace with rules set D, chance 60%
285 + - yaw the turtle right by angle degrees
286 - - yaw the turtle left by angle degrees
287 & - pitch the turtle down by angle degrees
288 ^ - pitch the turtle up by angle degrees
289 / - roll the turtle to the right by angle degrees
290 * - roll the turtle to the left by angle degrees
291 [ - save in stack current state info
292 ] - recover from stack state info
297 for (s16 i = 0; i < (s16)axiom.size(); i++) {
298 char axiom_char = axiom.at(i);
299 core::matrix4 temp_rotation;
300 temp_rotation.makeIdentity();
302 switch (axiom_char) {
305 dir = transposeMatrix(rotation, dir);
309 tree_trunk_placement(
311 v3f(position.X, position.Y, position.Z),
314 if (tree_definition.trunk_type == "double" &&
315 !tree_definition.thin_branches) {
316 tree_trunk_placement(
318 v3f(position.X + 1, position.Y, position.Z),
321 tree_trunk_placement(
323 v3f(position.X, position.Y, position.Z + 1),
326 tree_trunk_placement(
328 v3f(position.X + 1, position.Y, position.Z + 1),
331 } else if (tree_definition.trunk_type == "crossed" &&
332 !tree_definition.thin_branches) {
333 tree_trunk_placement(
335 v3f(position.X + 1, position.Y, position.Z),
338 tree_trunk_placement(
340 v3f(position.X - 1, position.Y, position.Z),
343 tree_trunk_placement(
345 v3f(position.X, position.Y, position.Z + 1),
348 tree_trunk_placement(
350 v3f(position.X, position.Y, position.Z - 1),
355 dir = transposeMatrix(rotation, dir);
359 tree_trunk_placement(
361 v3f(position.X, position.Y, position.Z),
364 if ((stack_orientation.empty() &&
365 tree_definition.trunk_type == "double") ||
366 (!stack_orientation.empty() &&
367 tree_definition.trunk_type == "double" &&
368 !tree_definition.thin_branches)) {
369 tree_trunk_placement(
371 v3f(position.X + 1, position.Y, position.Z),
374 tree_trunk_placement(
376 v3f(position.X, position.Y, position.Z + 1),
379 tree_trunk_placement(
381 v3f(position.X + 1, position.Y, position.Z + 1),
384 } else if ((stack_orientation.empty() &&
385 tree_definition.trunk_type == "crossed") ||
386 (!stack_orientation.empty() &&
387 tree_definition.trunk_type == "crossed" &&
388 !tree_definition.thin_branches)) {
389 tree_trunk_placement(
391 v3f(position.X + 1, position.Y, position.Z),
394 tree_trunk_placement(
396 v3f(position.X - 1, position.Y, position.Z),
399 tree_trunk_placement(
401 v3f(position.X, position.Y, position.Z + 1),
404 tree_trunk_placement(
406 v3f(position.X, position.Y, position.Z - 1),
410 if (!stack_orientation.empty()) {
412 for (x = -size; x <= size; x++)
413 for (y = -size; y <= size; y++)
414 for (z = -size; z <= size; z++) {
415 if (abs(x) == size &&
418 tree_leaves_placement(
420 v3f(position.X + x + 1, position.Y + y,
425 tree_leaves_placement(
427 v3f(position.X + x - 1, position.Y + y,
432 tree_leaves_placement(
433 vmanip,v3f(position.X + x, position.Y + y,
438 tree_leaves_placement(
439 vmanip,v3f(position.X + x, position.Y + y,
448 dir = transposeMatrix(rotation, dir);
452 tree_single_leaves_placement(
454 v3f(position.X, position.Y, position.Z),
459 dir = transposeMatrix(rotation, dir);
463 tree_fruit_placement(
465 v3f(position.X, position.Y, position.Z),
469 dir = transposeMatrix(rotation, dir);
473 // turtle orientation commands
475 stack_orientation.push(rotation);
476 stack_position.push(position);
479 if (stack_orientation.empty())
480 return UNBALANCED_BRACKETS;
481 rotation = stack_orientation.top();
482 stack_orientation.pop();
483 position = stack_position.top();
484 stack_position.pop();
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, 0, -1));
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 + angleOffset_in_radians, v3f(0, -1, 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;
517 temp_rotation.makeIdentity();
518 temp_rotation = setRotationAxisRadians(temp_rotation,
519 angle_in_radians, v3f(-1, 0, 0));
520 rotation *= temp_rotation;
531 void tree_trunk_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition)
533 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
534 if (!vmanip.m_area.contains(p1))
536 u32 vi = vmanip.m_area.index(p1);
537 content_t current_node = vmanip.m_data[vi].getContent();
538 if (current_node != CONTENT_AIR && current_node != CONTENT_IGNORE
539 && current_node != tree_definition.leavesnode.getContent()
540 && current_node != tree_definition.leaves2node.getContent()
541 && current_node != tree_definition.fruitnode.getContent())
543 vmanip.m_data[vi] = tree_definition.trunknode;
547 void tree_leaves_placement(MMVManip &vmanip, v3f p0,
548 PseudoRandom ps, TreeDef &tree_definition)
550 MapNode leavesnode = tree_definition.leavesnode;
551 if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance)
552 leavesnode = tree_definition.leaves2node;
553 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
554 if (!vmanip.m_area.contains(p1))
556 u32 vi = vmanip.m_area.index(p1);
557 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
558 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
560 if (tree_definition.fruit_chance > 0) {
561 if (ps.range(1, 100) > 100 - tree_definition.fruit_chance)
562 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
564 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
565 } else if (ps.range(1, 100) > 20) {
566 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
571 void tree_single_leaves_placement(MMVManip &vmanip, v3f p0,
572 PseudoRandom ps, TreeDef &tree_definition)
574 MapNode leavesnode = tree_definition.leavesnode;
575 if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance)
576 leavesnode = tree_definition.leaves2node;
577 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
578 if (!vmanip.m_area.contains(p1))
580 u32 vi = vmanip.m_area.index(p1);
581 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
582 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
584 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
588 void tree_fruit_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition)
590 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
591 if (!vmanip.m_area.contains(p1))
593 u32 vi = vmanip.m_area.index(p1);
594 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
595 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
597 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
601 irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis)
603 double c = cos(angle);
604 double s = sin(angle);
607 double tx = t * axis.X;
608 double ty = t * axis.Y;
609 double tz = t * axis.Z;
610 double sx = s * axis.X;
611 double sy = s * axis.Y;
612 double sz = s * axis.Z;
614 M[0] = tx * axis.X + c;
615 M[1] = tx * axis.Y + sz;
616 M[2] = tx * axis.Z - sy;
618 M[4] = ty * axis.X - sz;
619 M[5] = ty * axis.Y + c;
620 M[6] = ty * axis.Z + sx;
622 M[8] = tz * axis.X + sy;
623 M[9] = tz * axis.Y - sx;
624 M[10] = tz * axis.Z + c;
629 v3f transposeMatrix(irr::core::matrix4 M, v3f v)
632 double x = M[0] * v.X + M[4] * v.Y + M[8] * v.Z +M[12];
633 double y = M[1] * v.X + M[5] * v.Y + M[9] * v.Z +M[13];
634 double z = M[2] * v.X + M[6] * v.Y + M[10] * v.Z +M[14];
642 void make_jungletree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef,
646 NOTE: Tree-placing code is currently duplicated in the engine
647 and in games that have saplings; both are deprecated but not
650 content_t c_tree = ndef->getId("mapgen_jungletree");
651 content_t c_leaves = ndef->getId("mapgen_jungleleaves");
652 if (c_tree == CONTENT_IGNORE)
653 c_tree = ndef->getId("mapgen_tree");
654 if (c_leaves == CONTENT_IGNORE)
655 c_leaves = ndef->getId("mapgen_leaves");
656 if (c_tree == CONTENT_IGNORE)
657 errorstream << "Treegen: Mapgen alias 'mapgen_jungletree' is invalid!" << std::endl;
658 if (c_leaves == CONTENT_IGNORE)
659 errorstream << "Treegen: Mapgen alias 'mapgen_jungleleaves' is invalid!" << std::endl;
661 MapNode treenode(c_tree);
662 MapNode leavesnode(c_leaves);
664 PseudoRandom pr(seed);
665 for (s16 x= -1; x <= 1; x++)
666 for (s16 z= -1; z <= 1; z++) {
667 if (pr.range(0, 2) == 0)
669 v3s16 p1 = p0 + v3s16(x, 0, z);
670 v3s16 p2 = p0 + v3s16(x, -1, z);
671 u32 vi1 = vmanip.m_area.index(p1);
672 u32 vi2 = vmanip.m_area.index(p2);
674 if (vmanip.m_area.contains(p2) &&
675 vmanip.m_data[vi2].getContent() == CONTENT_AIR)
676 vmanip.m_data[vi2] = treenode;
677 else if (vmanip.m_area.contains(p1) &&
678 vmanip.m_data[vi1].getContent() == CONTENT_AIR)
679 vmanip.m_data[vi1] = treenode;
681 vmanip.m_data[vmanip.m_area.index(p0)] = treenode;
683 s16 trunk_h = pr.range(8, 12);
685 for (s16 ii = 0; ii < trunk_h; ii++) {
686 if (vmanip.m_area.contains(p1)) {
687 u32 vi = vmanip.m_area.index(p1);
688 vmanip.m_data[vi] = treenode;
693 // p1 is now the last piece of the trunk
696 VoxelArea leaves_a(v3s16(-3, -2, -3), v3s16(3, 2, 3));
697 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
698 Buffer<u8> leaves_d(leaves_a.getVolume());
699 for (s32 i = 0; i < leaves_a.getVolume(); i++)
702 // Force leaves at near the end of the trunk
704 for (s16 z = -d; z <= d; z++)
705 for (s16 y = -d; y <= d; y++)
706 for (s16 x = -d; x <= d; x++) {
707 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
710 // Add leaves randomly
711 for (u32 iii = 0; iii < 30; iii++) {
713 pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d),
714 pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d),
715 pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d)
718 for (s16 z = 0; z <= d; z++)
719 for (s16 y = 0; y <= d; y++)
720 for (s16 x = 0; x <= d; x++) {
721 leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1;
725 // Blit leaves to vmanip
726 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
727 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
728 v3s16 pmin(leaves_a.MinEdge.X, y, z);
729 u32 i = leaves_a.index(pmin);
730 u32 vi = vmanip.m_area.index(pmin + p1);
731 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
733 if (vmanip.m_area.contains(p + p1) &&
734 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
735 vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) {
736 if (leaves_d[i] == 1)
737 vmanip.m_data[vi] = leavesnode;
746 void make_pine_tree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef,
750 NOTE: Tree-placing code is currently duplicated in the engine
751 and in games that have saplings; both are deprecated but not
754 content_t c_tree = ndef->getId("mapgen_pine_tree");
755 content_t c_leaves = ndef->getId("mapgen_pine_needles");
756 content_t c_snow = ndef->getId("mapgen_snow");
757 if (c_tree == CONTENT_IGNORE)
758 c_tree = ndef->getId("mapgen_tree");
759 if (c_leaves == CONTENT_IGNORE)
760 c_leaves = ndef->getId("mapgen_leaves");
761 if (c_snow == CONTENT_IGNORE)
762 c_snow = CONTENT_AIR;
763 if (c_tree == CONTENT_IGNORE)
764 errorstream << "Treegen: Mapgen alias 'mapgen_pine_tree' is invalid!" << std::endl;
765 if (c_leaves == CONTENT_IGNORE)
766 errorstream << "Treegen: Mapgen alias 'mapgen_pine_needles' is invalid!" << std::endl;
768 MapNode treenode(c_tree);
769 MapNode leavesnode(c_leaves);
770 MapNode snownode(c_snow);
772 PseudoRandom pr(seed);
773 u16 trunk_h = pr.range(9, 13);
775 for (u16 ii = 0; ii < trunk_h; ii++) {
776 if (vmanip.m_area.contains(p1)) {
777 u32 vi = vmanip.m_area.index(p1);
778 vmanip.m_data[vi] = treenode;
783 // Make p1 the top node of the trunk
786 VoxelArea leaves_a(v3s16(-3, -6, -3), v3s16(3, 3, 3));
787 Buffer<u8> leaves_d(leaves_a.getVolume());
788 for (s32 i = 0; i < leaves_a.getVolume(); i++)
793 for (s16 yy = -1; yy <= 1; yy++) {
794 for (s16 zz = -dev; zz <= dev; zz++) {
795 u32 i = leaves_a.index(v3s16(-dev, yy, zz));
796 u32 ia = leaves_a.index(v3s16(-dev, yy+1, zz));
797 for (s16 xx = -dev; xx <= dev; xx++) {
798 if (pr.range(0, 20) <= 19 - dev) {
810 leaves_d[leaves_a.index(v3s16(0, 1, 0))] = 1;
811 leaves_d[leaves_a.index(v3s16(0, 2, 0))] = 1;
812 leaves_d[leaves_a.index(v3s16(0, 3, 0))] = 2;
816 for (u32 iii = 0; iii < 20; iii++) {
817 s16 xi = pr.range(-3, 2);
818 s16 yy = pr.range(-6, -5);
819 s16 zi = pr.range(-3, 2);
822 for (s16 zz = zi; zz <= zi + 1; zz++) {
823 u32 i = leaves_a.index(v3s16(xi, yy, zz));
824 u32 ia = leaves_a.index(v3s16(xi, yy + 1, zz));
825 for (s32 xx = xi; xx <= xi + 1; xx++) {
827 if (leaves_d[ia] == 0)
836 for (s16 yy = my + 1; yy <= my + 2; yy++) {
837 for (s16 zz = -dev; zz <= dev; zz++) {
838 u32 i = leaves_a.index(v3s16(-dev, yy, zz));
839 u32 ia = leaves_a.index(v3s16(-dev, yy + 1, zz));
840 for (s16 xx = -dev; xx <= dev; xx++) {
841 if (pr.range(0, 20) <= 19 - dev) {
852 // Blit leaves to vmanip
853 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
854 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
855 v3s16 pmin(leaves_a.MinEdge.X, y, z);
856 u32 i = leaves_a.index(pmin);
857 u32 vi = vmanip.m_area.index(pmin + p1);
858 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
860 if (vmanip.m_area.contains(p + p1) &&
861 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
862 vmanip.m_data[vi].getContent() == CONTENT_IGNORE ||
863 vmanip.m_data[vi] == snownode)) {
864 if (leaves_d[i] == 1)
865 vmanip.m_data[vi] = leavesnode;
866 else if (leaves_d[i] == 2)
867 vmanip.m_data[vi] = snownode;
875 }; // namespace treegen