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"
25 #include "serverenvironment.h"
32 void make_tree(MMVManip &vmanip, v3s16 p0,
33 bool is_apple_tree, INodeDefManager *ndef, s32 seed)
36 NOTE: Tree-placing code is currently duplicated in the engine
37 and in games that have saplings; both are deprecated but not
40 MapNode treenode(ndef->getId("mapgen_tree"));
41 MapNode leavesnode(ndef->getId("mapgen_leaves"));
42 MapNode applenode(ndef->getId("mapgen_apple"));
44 PseudoRandom pr(seed);
45 s16 trunk_h = pr.range(4, 5);
47 for (s16 ii = 0; ii < trunk_h; ii++) {
48 if (vmanip.m_area.contains(p1)) {
49 u32 vi = vmanip.m_area.index(p1);
50 vmanip.m_data[vi] = treenode;
55 // p1 is now the last piece of the trunk
58 VoxelArea leaves_a(v3s16(-2, -1, -2), v3s16(2, 2, 2));
59 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
60 Buffer<u8> leaves_d(leaves_a.getVolume());
61 for (s32 i = 0; i < leaves_a.getVolume(); i++)
64 // Force leaves at near the end of the trunk
66 for (s16 z = -d; z <= d; z++)
67 for (s16 y = -d; y <= d; y++)
68 for (s16 x = -d; x <= d; x++) {
69 leaves_d[leaves_a.index(v3s16(x, y, z))] = 1;
72 // Add leaves randomly
73 for (u32 iii = 0; iii < 7; iii++) {
75 pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d),
76 pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d),
77 pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d)
80 for (s16 z = 0; z <= d; z++)
81 for (s16 y = 0; y <= d; y++)
82 for (s16 x = 0; x <= d; x++) {
83 leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1;
87 // Blit leaves to vmanip
88 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
89 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
90 v3s16 pmin(leaves_a.MinEdge.X, y, z);
91 u32 i = leaves_a.index(pmin);
92 u32 vi = vmanip.m_area.index(pmin + p1);
93 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
95 if (vmanip.m_area.contains(p + p1) == true &&
96 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
97 vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) {
98 if (leaves_d[i] == 1) {
99 bool is_apple = pr.range(0, 99) < 10;
100 if (is_apple_tree && is_apple)
101 vmanip.m_data[vi] = applenode;
103 vmanip.m_data[vi] = leavesnode;
113 // L-System tree LUA spawner
114 treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0,
115 INodeDefManager *ndef, TreeDef tree_definition)
117 ServerMap *map = &env->getServerMap();
118 std::map<v3s16, MapBlock*> modified_blocks;
119 MMVManip vmanip(map);
120 v3s16 tree_blockp = getNodeBlockPos(p0);
123 vmanip.initialEmerge(tree_blockp - v3s16(1, 1, 1), tree_blockp + v3s16(1, 3, 1));
124 e = make_ltree(vmanip, p0, ndef, tree_definition);
128 vmanip.blitBackAll(&modified_blocks);
131 std::map<v3s16, MapBlock*> lighting_modified_blocks;
132 lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
133 map->updateLighting(lighting_modified_blocks, modified_blocks);
134 // Send a MEET_OTHER event
136 event.type = MEET_OTHER;
137 for (std::map<v3s16, MapBlock*>::iterator
138 i = modified_blocks.begin();
139 i != modified_blocks.end(); ++i)
140 event.modified_blocks.insert(i->first);
141 map->dispatchEvent(&event);
146 //L-System tree generator
147 treegen::error make_ltree(MMVManip &vmanip, v3s16 p0,
148 INodeDefManager *ndef, TreeDef tree_definition)
150 MapNode dirtnode(ndef->getId("mapgen_dirt"));
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++) {
188 std::string temp = "";
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 //make sure tree is not floating in the air
229 if (tree_definition.trunk_type == "double") {
232 v3f(position.X + 1, position.Y - 1, position.Z),
237 v3f(position.X, position.Y - 1, position.Z + 1),
242 v3f(position.X + 1, position.Y - 1, position.Z + 1),
245 } else if (tree_definition.trunk_type == "crossed") {
248 v3f(position.X + 1, position.Y - 1, position.Z),
253 v3f(position.X - 1, position.Y - 1, position.Z),
258 v3f(position.X, position.Y - 1, position.Z + 1),
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),
409 } if (stack_orientation.empty() == false) {
411 for (x = -size; x <= size; x++)
412 for (y = -size; y <= size; y++)
413 for (z = -size; z <= size; z++) {
414 if (abs(x) == size &&
417 tree_leaves_placement(
419 v3f(position.X + x + 1, position.Y + y,
424 tree_leaves_placement(
426 v3f(position.X + x - 1, position.Y + y,
431 tree_leaves_placement(
432 vmanip,v3f(position.X + x, position.Y + y,
437 tree_leaves_placement(
438 vmanip,v3f(position.X + x, position.Y + y,
447 dir = transposeMatrix(rotation, dir);
451 tree_single_leaves_placement(
453 v3f(position.X, position.Y, position.Z),
458 dir = transposeMatrix(rotation, dir);
462 tree_fruit_placement(
464 v3f(position.X, position.Y, position.Z),
468 dir = transposeMatrix(rotation, dir);
472 // turtle orientation commands
474 stack_orientation.push(rotation);
475 stack_position.push(position);
478 if (stack_orientation.empty())
479 return UNBALANCED_BRACKETS;
480 rotation = stack_orientation.top();
481 stack_orientation.pop();
482 position = stack_position.top();
483 stack_position.pop();
486 temp_rotation.makeIdentity();
487 temp_rotation = setRotationAxisRadians(temp_rotation,
488 angle_in_radians + angleOffset_in_radians, v3f(0, 0, 1));
489 rotation *= temp_rotation;
492 temp_rotation.makeIdentity();
493 temp_rotation = setRotationAxisRadians(temp_rotation,
494 angle_in_radians + angleOffset_in_radians, v3f(0, 0, -1));
495 rotation *= temp_rotation;
498 temp_rotation.makeIdentity();
499 temp_rotation = setRotationAxisRadians(temp_rotation,
500 angle_in_radians + angleOffset_in_radians, v3f(0, 1, 0));
501 rotation *= temp_rotation;
504 temp_rotation.makeIdentity();
505 temp_rotation = setRotationAxisRadians(temp_rotation,
506 angle_in_radians + angleOffset_in_radians, v3f(0, -1, 0));
507 rotation *= temp_rotation;
510 temp_rotation.makeIdentity();
511 temp_rotation = setRotationAxisRadians(temp_rotation,
512 angle_in_radians, v3f(1, 0, 0));
513 rotation *= temp_rotation;
516 temp_rotation.makeIdentity();
517 temp_rotation = setRotationAxisRadians(temp_rotation,
518 angle_in_radians, v3f(-1, 0, 0));
519 rotation *= temp_rotation;
530 void tree_node_placement(MMVManip &vmanip, v3f p0, MapNode node)
532 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
533 if (vmanip.m_area.contains(p1) == false)
535 u32 vi = vmanip.m_area.index(p1);
536 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
537 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
539 vmanip.m_data[vmanip.m_area.index(p1)] = node;
543 void tree_trunk_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition)
545 v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
546 if (vmanip.m_area.contains(p1) == false)
548 u32 vi = vmanip.m_area.index(p1);
549 if (vmanip.m_data[vi].getContent() != CONTENT_AIR
550 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
552 vmanip.m_data[vmanip.m_area.index(p1)] = 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) == false)
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) == false)
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) == false)
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, INodeDefManager *ndef, s32 seed)
654 NOTE: Tree-placing code is currently duplicated in the engine
655 and in games that have saplings; both are deprecated but not
658 content_t c_tree = ndef->getId("mapgen_jungletree");
659 content_t c_leaves = ndef->getId("mapgen_jungleleaves");
660 if (c_tree == CONTENT_IGNORE)
661 c_tree = ndef->getId("mapgen_tree");
662 if (c_leaves == CONTENT_IGNORE)
663 c_leaves = ndef->getId("mapgen_leaves");
665 MapNode treenode(c_tree);
666 MapNode leavesnode(c_leaves);
668 PseudoRandom pr(seed);
669 for (s16 x= -1; x <= 1; x++)
670 for (s16 z= -1; z <= 1; z++) {
671 if (pr.range(0, 2) == 0)
673 v3s16 p1 = p0 + v3s16(x, 0, z);
674 v3s16 p2 = p0 + v3s16(x, -1, z);
675 u32 vi1 = vmanip.m_area.index(p1);
676 u32 vi2 = vmanip.m_area.index(p2);
678 if (vmanip.m_area.contains(p2) &&
679 vmanip.m_data[vi2].getContent() == CONTENT_AIR)
680 vmanip.m_data[vi2] = treenode;
681 else if (vmanip.m_area.contains(p1) &&
682 vmanip.m_data[vi1].getContent() == CONTENT_AIR)
683 vmanip.m_data[vi1] = treenode;
685 vmanip.m_data[vmanip.m_area.index(p0)] = treenode;
687 s16 trunk_h = pr.range(8, 12);
689 for (s16 ii = 0; ii < trunk_h; ii++) {
690 if (vmanip.m_area.contains(p1)) {
691 u32 vi = vmanip.m_area.index(p1);
692 vmanip.m_data[vi] = treenode;
697 // p1 is now the last piece of the trunk
700 VoxelArea leaves_a(v3s16(-3, -2, -3), v3s16(3, 2, 3));
701 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
702 Buffer<u8> leaves_d(leaves_a.getVolume());
703 for (s32 i = 0; i < leaves_a.getVolume(); i++)
706 // Force leaves at near the end of the trunk
708 for (s16 z = -d; z <= d; z++)
709 for (s16 y = -d; y <= d; y++)
710 for (s16 x = -d; x <= d; x++) {
711 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
714 // Add leaves randomly
715 for (u32 iii = 0; iii < 30; iii++) {
717 pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d),
718 pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d),
719 pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d)
722 for (s16 z = 0; z <= d; z++)
723 for (s16 y = 0; y <= d; y++)
724 for (s16 x = 0; x <= d; x++) {
725 leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1;
729 // Blit leaves to vmanip
730 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
731 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
732 v3s16 pmin(leaves_a.MinEdge.X, y, z);
733 u32 i = leaves_a.index(pmin);
734 u32 vi = vmanip.m_area.index(pmin + p1);
735 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
737 if (vmanip.m_area.contains(p + p1) == true &&
738 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
739 vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) {
740 if (leaves_d[i] == 1)
741 vmanip.m_data[vi] = leavesnode;
750 void make_pine_tree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, s32 seed)
753 NOTE: Tree-placing code is currently duplicated in the engine
754 and in games that have saplings; both are deprecated but not
757 content_t c_tree = ndef->getId("mapgen_pine_tree");
758 content_t c_leaves = ndef->getId("mapgen_pine_needles");
759 content_t c_snow = ndef->getId("mapgen_snow");
760 if (c_tree == CONTENT_IGNORE)
761 c_tree = ndef->getId("mapgen_tree");
762 if (c_leaves == CONTENT_IGNORE)
763 c_leaves = ndef->getId("mapgen_leaves");
764 if (c_snow == CONTENT_IGNORE)
765 c_snow = CONTENT_AIR;
767 MapNode treenode(c_tree);
768 MapNode leavesnode(c_leaves);
769 MapNode snownode(c_snow);
771 PseudoRandom pr(seed);
772 u16 trunk_h = pr.range(9, 13);
774 for (u16 ii = 0; ii < trunk_h; ii++) {
775 if (vmanip.m_area.contains(p1)) {
776 u32 vi = vmanip.m_area.index(p1);
777 vmanip.m_data[vi] = treenode;
782 // Make p1 the top node of the trunk
785 VoxelArea leaves_a(v3s16(-3, -6, -3), v3s16(3, 3, 3));
786 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
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 u32 i = leaves_a.index(v3s16(0, 1, 0));
812 i = leaves_a.index(v3s16(0, 2, 0));
814 i = leaves_a.index(v3s16(0, 3, 0));
819 for (u32 iii = 0; iii < 20; iii++) {
820 s16 xi = pr.range(-3, 2);
821 s16 yy = pr.range(-6, -5);
822 s16 zi = pr.range(-3, 2);
825 for (s16 zz = zi; zz <= zi + 1; zz++) {
826 u32 i = leaves_a.index(v3s16(xi, yy, zz));
827 u32 ia = leaves_a.index(v3s16(xi, yy + 1, zz));
828 for (s16 xx = xi; xx <= xi + 1; xx++) {
830 if (leaves_d[ia] == 0)
839 for (s16 yy = my + 1; yy <= my + 2; yy++) {
840 for (s16 zz = -dev; zz <= dev; zz++) {
841 u32 i = leaves_a.index(v3s16(-dev, yy, zz));
842 u32 ia = leaves_a.index(v3s16(-dev, yy + 1, zz));
843 for (s16 xx = -dev; xx <= dev; xx++) {
844 if (pr.range(0, 20) <= 19 - dev) {
855 // Blit leaves to vmanip
856 for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
857 for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
858 v3s16 pmin(leaves_a.MinEdge.X, y, z);
859 u32 i = leaves_a.index(pmin);
860 u32 vi = vmanip.m_area.index(pmin + p1);
861 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
863 if (vmanip.m_area.contains(p + p1) == true &&
864 (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
865 vmanip.m_data[vi].getContent() == CONTENT_IGNORE ||
866 vmanip.m_data[vi] == snownode)) {
867 if (leaves_d[i] == 1)
868 vmanip.m_data[vi] = leavesnode;
869 else if (leaves_d[i] == 2)
870 vmanip.m_data[vi] = snownode;
878 }; // namespace treegen