Noise: Prevent unittest crash caused by division by zero
[oweals/minetest.git] / src / treegen.cpp
1 /*
2 Minetest
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.
9
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.
14
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.
18 */
19
20 #include "irr_v3d.h"
21 #include <stack>
22 #include "util/pointer.h"
23 #include "util/numeric.h"
24 #include "map.h"
25 #include "serverenvironment.h"
26 #include "nodedef.h"
27 #include "treegen.h"
28 #include "voxelalgorithms.h"
29
30 namespace treegen
31 {
32
33 void make_tree(MMVManip &vmanip, v3s16 p0,
34                 bool is_apple_tree, INodeDefManager *ndef, s32 seed)
35 {
36         /*
37                 NOTE: Tree-placing code is currently duplicated in the engine
38                 and in games that have saplings; both are deprecated but not
39                 replaced yet
40         */
41         MapNode treenode(ndef->getId("mapgen_tree"));
42         MapNode leavesnode(ndef->getId("mapgen_leaves"));
43         MapNode applenode(ndef->getId("mapgen_apple"));
44
45         PseudoRandom pr(seed);
46         s16 trunk_h = pr.range(4, 5);
47         v3s16 p1 = p0;
48         for (s16 ii = 0; ii < trunk_h; ii++) {
49                 if (vmanip.m_area.contains(p1)) {
50                         u32 vi = vmanip.m_area.index(p1);
51                         vmanip.m_data[vi] = treenode;
52                 }
53                 p1.Y++;
54         }
55
56         // p1 is now the last piece of the trunk
57         p1.Y -= 1;
58
59         VoxelArea leaves_a(v3s16(-2, -1, -2), v3s16(2, 2, 2));
60         Buffer<u8> leaves_d(leaves_a.getVolume());
61         for (s32 i = 0; i < leaves_a.getVolume(); i++)
62                 leaves_d[i] = 0;
63
64         // Force leaves at near the end of the trunk
65         s16 d = 1;
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;
70         }
71
72         // Add leaves randomly
73         for (u32 iii = 0; iii < 7; iii++) {
74                 v3s16 p(
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)
78                 );
79
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;
84                 }
85         }
86
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++) {
94                         v3s16 p(x, y, z);
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;
102                                         else
103                                                 vmanip.m_data[vi] = leavesnode;
104                                 }
105                         }
106                         vi++;
107                         i++;
108                 }
109         }
110 }
111
112
113 // L-System tree LUA spawner
114 treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0,
115                 INodeDefManager *ndef, const TreeDef &tree_definition)
116 {
117         ServerMap *map = &env->getServerMap();
118         std::map<v3s16, MapBlock*> modified_blocks;
119         MMVManip vmanip(map);
120         v3s16 tree_blockp = getNodeBlockPos(p0);
121         treegen::error e;
122
123         vmanip.initialEmerge(tree_blockp - v3s16(1, 1, 1), tree_blockp + v3s16(1, 3, 1));
124         e = make_ltree(vmanip, p0, ndef, tree_definition);
125         if (e != SUCCESS)
126                 return e;
127
128         voxalgo::blit_back_with_light(map, &vmanip, &modified_blocks);
129
130         // Send a MEET_OTHER event
131         MapEditEvent event;
132         event.type = MEET_OTHER;
133         for (std::map<v3s16, MapBlock*>::iterator
134                         i = modified_blocks.begin();
135                         i != modified_blocks.end(); ++i)
136                 event.modified_blocks.insert(i->first);
137         map->dispatchEvent(&event);
138         return SUCCESS;
139 }
140
141
142 //L-System tree generator
143 treegen::error make_ltree(MMVManip &vmanip, v3s16 p0,
144                 INodeDefManager *ndef, TreeDef tree_definition)
145 {
146         MapNode dirtnode(ndef->getId("mapgen_dirt"));
147         s32 seed;
148         if (tree_definition.explicit_seed)
149                 seed = tree_definition.seed + 14002;
150         else
151                 seed = p0.X * 2 + p0.Y * 4 + p0.Z;  // use the tree position to seed PRNG
152         PseudoRandom ps(seed);
153
154         // chance of inserting abcd rules
155         double prop_a = 9;
156         double prop_b = 8;
157         double prop_c = 7;
158         double prop_d = 6;
159
160         //randomize tree growth level, minimum=2
161         s16 iterations = tree_definition.iterations;
162         if (tree_definition.iterations_random_level > 0)
163                 iterations -= ps.range(0, tree_definition.iterations_random_level);
164         if (iterations < 2)
165                 iterations = 2;
166
167         s16 MAX_ANGLE_OFFSET = 5;
168         double angle_in_radians = (double)tree_definition.angle * M_PI / 180;
169         double angleOffset_in_radians = (s16)(ps.range(0, 1) % MAX_ANGLE_OFFSET) * M_PI / 180;
170
171         //initialize rotation matrix, position and stacks for branches
172         core::matrix4 rotation;
173         rotation = setRotationAxisRadians(rotation, M_PI / 2, v3f(0, 0, 1));
174         v3f position;
175         position.X = p0.X;
176         position.Y = p0.Y;
177         position.Z = p0.Z;
178         std::stack <core::matrix4> stack_orientation;
179         std::stack <v3f> stack_position;
180
181         //generate axiom
182         std::string axiom = tree_definition.initial_axiom;
183         for (s16 i = 0; i < iterations; i++) {
184                 std::string temp = "";
185                 for (s16 j = 0; j < (s16)axiom.size(); j++) {
186                         char axiom_char = axiom.at(j);
187                         switch (axiom_char) {
188                         case 'A':
189                                 temp += tree_definition.rules_a;
190                                 break;
191                         case 'B':
192                                 temp += tree_definition.rules_b;
193                                 break;
194                         case 'C':
195                                 temp += tree_definition.rules_c;
196                                 break;
197                         case 'D':
198                                 temp += tree_definition.rules_d;
199                                 break;
200                         case 'a':
201                                 if (prop_a >= ps.range(1, 10))
202                                         temp += tree_definition.rules_a;
203                                 break;
204                         case 'b':
205                                 if (prop_b >= ps.range(1, 10))
206                                         temp += tree_definition.rules_b;
207                                 break;
208                         case 'c':
209                                 if (prop_c >= ps.range(1, 10))
210                                         temp += tree_definition.rules_c;
211                                 break;
212                         case 'd':
213                                 if (prop_d >= ps.range(1, 10))
214                                         temp += tree_definition.rules_d;
215                                 break;
216                         default:
217                                 temp += axiom_char;
218                                 break;
219                         }
220                 }
221                 axiom = temp;
222         }
223
224         //make sure tree is not floating in the air
225         if (tree_definition.trunk_type == "double") {
226                 tree_node_placement(
227                         vmanip,
228                         v3f(position.X + 1, position.Y - 1, position.Z),
229                         dirtnode
230                 );
231                 tree_node_placement(
232                         vmanip,
233                         v3f(position.X, position.Y - 1, position.Z + 1),
234                         dirtnode
235                 );
236                 tree_node_placement(
237                         vmanip,
238                         v3f(position.X + 1, position.Y - 1, position.Z + 1),
239                         dirtnode
240                 );
241         } else if (tree_definition.trunk_type == "crossed") {
242                 tree_node_placement(
243                         vmanip,
244                         v3f(position.X + 1, position.Y - 1, position.Z),
245                         dirtnode
246                 );
247                 tree_node_placement(
248                         vmanip,
249                         v3f(position.X - 1, position.Y - 1, position.Z),
250                         dirtnode
251                 );
252                 tree_node_placement(
253                         vmanip,
254                         v3f(position.X, position.Y - 1, position.Z + 1),
255                         dirtnode
256                 );
257                 tree_node_placement(
258                         vmanip,
259                         v3f(position.X, position.Y - 1, position.Z - 1),
260                         dirtnode
261                 );
262         }
263
264         /* build tree out of generated axiom
265
266         Key for Special L-System Symbols used in Axioms
267
268     G  - move forward one unit with the pen up
269     F  - move forward one unit with the pen down drawing trunks and branches
270     f  - move forward one unit with the pen down drawing leaves (100% chance)
271     T  - move forward one unit with the pen down drawing trunks only
272     R  - move forward one unit with the pen down placing fruit
273     A  - replace with rules set A
274     B  - replace with rules set B
275     C  - replace with rules set C
276     D  - replace with rules set D
277     a  - replace with rules set A, chance 90%
278     b  - replace with rules set B, chance 80%
279     c  - replace with rules set C, chance 70%
280     d  - replace with rules set D, chance 60%
281     +  - yaw the turtle right by angle degrees
282     -  - yaw the turtle left by angle degrees
283     &  - pitch the turtle down by angle degrees
284     ^  - pitch the turtle up by angle degrees
285     /  - roll the turtle to the right by angle degrees
286     *  - roll the turtle to the left by angle degrees
287     [  - save in stack current state info
288     ]  - recover from stack state info
289
290     */
291
292         s16 x,y,z;
293         for (s16 i = 0; i < (s16)axiom.size(); i++) {
294                 char axiom_char = axiom.at(i);
295                 core::matrix4 temp_rotation;
296                 temp_rotation.makeIdentity();
297                 v3f dir;
298                 switch (axiom_char) {
299                 case 'G':
300                         dir = v3f(1, 0, 0);
301                         dir = transposeMatrix(rotation, dir);
302                         position += dir;
303                         break;
304                 case 'T':
305                         tree_trunk_placement(
306                                 vmanip,
307                                 v3f(position.X, position.Y, position.Z),
308                                 tree_definition
309                         );
310                         if (tree_definition.trunk_type == "double" &&
311                                         !tree_definition.thin_branches) {
312                                 tree_trunk_placement(
313                                         vmanip,
314                                         v3f(position.X + 1, position.Y, position.Z),
315                                         tree_definition
316                                 );
317                                 tree_trunk_placement(
318                                         vmanip,
319                                         v3f(position.X, position.Y, position.Z + 1),
320                                         tree_definition
321                                 );
322                                 tree_trunk_placement(
323                                         vmanip,
324                                         v3f(position.X + 1, position.Y, position.Z + 1),
325                                         tree_definition
326                                 );
327                         } else if (tree_definition.trunk_type == "crossed" &&
328                                         !tree_definition.thin_branches) {
329                                 tree_trunk_placement(
330                                         vmanip,
331                                         v3f(position.X + 1, position.Y, position.Z),
332                                         tree_definition
333                                 );
334                                 tree_trunk_placement(
335                                         vmanip,
336                                         v3f(position.X - 1, position.Y, position.Z),
337                                         tree_definition
338                                 );
339                                 tree_trunk_placement(
340                                         vmanip,
341                                         v3f(position.X, position.Y, position.Z + 1),
342                                         tree_definition
343                                 );
344                                 tree_trunk_placement(
345                                         vmanip,
346                                         v3f(position.X, position.Y, position.Z - 1),
347                                         tree_definition
348                                 );
349                         }
350                         dir = v3f(1, 0, 0);
351                         dir = transposeMatrix(rotation, dir);
352                         position += dir;
353                         break;
354                 case 'F':
355                         tree_trunk_placement(
356                                 vmanip,
357                                 v3f(position.X, position.Y, position.Z),
358                                 tree_definition
359                         );
360                         if ((stack_orientation.empty() &&
361                                         tree_definition.trunk_type == "double") ||
362                                         (!stack_orientation.empty() &&
363                                         tree_definition.trunk_type == "double" &&
364                                         !tree_definition.thin_branches)) {
365                                 tree_trunk_placement(
366                                         vmanip,
367                                         v3f(position.X +1 , position.Y, position.Z),
368                                         tree_definition
369                                 );
370                                 tree_trunk_placement(
371                                         vmanip,
372                                         v3f(position.X, position.Y, position.Z + 1),
373                                         tree_definition
374                                 );
375                                 tree_trunk_placement(
376                                         vmanip,
377                                         v3f(position.X + 1, position.Y, position.Z + 1),
378                                         tree_definition
379                                 );
380                         } else if ((stack_orientation.empty() &&
381                                         tree_definition.trunk_type == "crossed") ||
382                                         (!stack_orientation.empty() &&
383                                         tree_definition.trunk_type == "crossed" &&
384                                         !tree_definition.thin_branches)) {
385                                 tree_trunk_placement(
386                                         vmanip,
387                                         v3f(position.X + 1, position.Y, position.Z),
388                                         tree_definition
389                                 );
390                                 tree_trunk_placement(
391                                         vmanip,
392                                         v3f(position.X - 1, position.Y, position.Z),
393                                         tree_definition
394                                 );
395                                 tree_trunk_placement(
396                                         vmanip,
397                                         v3f(position.X, position.Y, position.Z + 1),
398                                         tree_definition
399                                 );
400                                 tree_trunk_placement(
401                                         vmanip,
402                                         v3f(position.X, position.Y, position.Z - 1),
403                                         tree_definition
404                                 );
405                         } if (stack_orientation.empty() == false) {
406                                 s16 size = 1;
407                                 for (x = -size; x <= size; x++)
408                                 for (y = -size; y <= size; y++)
409                                 for (z = -size; z <= size; z++) {
410                                         if (abs(x) == size &&
411                                                         abs(y) == size &&
412                                                         abs(z) == size) {
413                                                 tree_leaves_placement(
414                                                         vmanip,
415                                                         v3f(position.X + x + 1, position.Y + y,
416                                                                         position.Z + z),
417                                                         ps.next(),
418                                                         tree_definition
419                                                 );
420                                                 tree_leaves_placement(
421                                                         vmanip,
422                                                         v3f(position.X + x - 1, position.Y + y,
423                                                                         position.Z + z),
424                                                         ps.next(),
425                                                         tree_definition
426                                                 );
427                                                 tree_leaves_placement(
428                                                         vmanip,v3f(position.X + x, position.Y + y,
429                                                                         position.Z + z + 1),
430                                                         ps.next(),
431                                                         tree_definition
432                                                 );
433                                                 tree_leaves_placement(
434                                                         vmanip,v3f(position.X + x, position.Y + y,
435                                                                         position.Z + z - 1),
436                                                         ps.next(),
437                                                         tree_definition
438                                                 );
439                                         }
440                                 }
441                         }
442                         dir = v3f(1, 0, 0);
443                         dir = transposeMatrix(rotation, dir);
444                         position += dir;
445                         break;
446                 case 'f':
447                         tree_single_leaves_placement(
448                                 vmanip,
449                                 v3f(position.X, position.Y, position.Z),
450                                 ps.next(),
451                                 tree_definition
452                         );
453                         dir = v3f(1, 0, 0);
454                         dir = transposeMatrix(rotation, dir);
455                         position += dir;
456                         break;
457                 case 'R':
458                         tree_fruit_placement(
459                                 vmanip,
460                                 v3f(position.X, position.Y, position.Z),
461                                 tree_definition
462                         );
463                         dir = v3f(1, 0, 0);
464                         dir = transposeMatrix(rotation, dir);
465                         position += dir;
466                         break;
467
468                 // turtle orientation commands
469                 case '[':
470                         stack_orientation.push(rotation);
471                         stack_position.push(position);
472                         break;
473                 case ']':
474                         if (stack_orientation.empty())
475                                 return UNBALANCED_BRACKETS;
476                         rotation = stack_orientation.top();
477                         stack_orientation.pop();
478                         position = stack_position.top();
479                         stack_position.pop();
480                         break;
481                 case '+':
482                         temp_rotation.makeIdentity();
483                         temp_rotation = setRotationAxisRadians(temp_rotation,
484                                         angle_in_radians + angleOffset_in_radians, v3f(0, 0, 1));
485                         rotation *= temp_rotation;
486                         break;
487                 case '-':
488                         temp_rotation.makeIdentity();
489                         temp_rotation = setRotationAxisRadians(temp_rotation,
490                                         angle_in_radians + angleOffset_in_radians, v3f(0, 0, -1));
491                         rotation *= temp_rotation;
492                         break;
493                 case '&':
494                         temp_rotation.makeIdentity();
495                         temp_rotation = setRotationAxisRadians(temp_rotation,
496                                         angle_in_radians + angleOffset_in_radians, v3f(0, 1, 0));
497                         rotation *= temp_rotation;
498                         break;
499                 case '^':
500                         temp_rotation.makeIdentity();
501                         temp_rotation = setRotationAxisRadians(temp_rotation,
502                                         angle_in_radians + angleOffset_in_radians, v3f(0, -1, 0));
503                         rotation *= temp_rotation;
504                         break;
505                 case '*':
506                         temp_rotation.makeIdentity();
507                         temp_rotation = setRotationAxisRadians(temp_rotation,
508                                         angle_in_radians, v3f(1, 0, 0));
509                         rotation *= temp_rotation;
510                         break;
511                 case '/':
512                         temp_rotation.makeIdentity();
513                         temp_rotation = setRotationAxisRadians(temp_rotation,
514                                         angle_in_radians, v3f(-1, 0, 0));
515                         rotation *= temp_rotation;
516                         break;
517                 default:
518                         break;
519                 }
520         }
521
522         return SUCCESS;
523 }
524
525
526 void tree_node_placement(MMVManip &vmanip, v3f p0, MapNode node)
527 {
528         v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
529         if (vmanip.m_area.contains(p1) == false)
530                 return;
531         u32 vi = vmanip.m_area.index(p1);
532         if (vmanip.m_data[vi].getContent() != CONTENT_AIR
533                         && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
534                 return;
535         vmanip.m_data[vmanip.m_area.index(p1)] = node;
536 }
537
538
539 void tree_trunk_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition)
540 {
541         v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
542         if (vmanip.m_area.contains(p1) == false)
543                 return;
544         u32 vi = vmanip.m_area.index(p1);
545         if (vmanip.m_data[vi].getContent() != CONTENT_AIR
546                         && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
547                 return;
548         vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.trunknode;
549 }
550
551
552 void tree_leaves_placement(MMVManip &vmanip, v3f p0,
553                 PseudoRandom ps, TreeDef &tree_definition)
554 {
555         MapNode leavesnode = tree_definition.leavesnode;
556         if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance)
557                 leavesnode = tree_definition.leaves2node;
558         v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
559         if (vmanip.m_area.contains(p1) == false)
560                 return;
561         u32 vi = vmanip.m_area.index(p1);
562         if (vmanip.m_data[vi].getContent() != CONTENT_AIR
563                         && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
564                 return;
565         if (tree_definition.fruit_chance > 0) {
566                 if (ps.range(1, 100) > 100 - tree_definition.fruit_chance)
567                         vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
568                 else
569                         vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
570         } else if (ps.range(1, 100) > 20) {
571                 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
572         }
573 }
574
575
576 void tree_single_leaves_placement(MMVManip &vmanip, v3f p0,
577                 PseudoRandom ps, TreeDef &tree_definition)
578 {
579         MapNode leavesnode = tree_definition.leavesnode;
580         if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance)
581                 leavesnode = tree_definition.leaves2node;
582         v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
583         if (vmanip.m_area.contains(p1) == false)
584                 return;
585         u32 vi = vmanip.m_area.index(p1);
586         if (vmanip.m_data[vi].getContent() != CONTENT_AIR
587                         && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
588                 return;
589         vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
590 }
591
592
593 void tree_fruit_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition)
594 {
595         v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
596         if (vmanip.m_area.contains(p1) == false)
597                 return;
598         u32 vi = vmanip.m_area.index(p1);
599         if (vmanip.m_data[vi].getContent() != CONTENT_AIR
600                         && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
601                 return;
602         vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
603 }
604
605
606 irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis)
607 {
608         double c = cos(angle);
609         double s = sin(angle);
610         double t = 1.0 - c;
611
612         double tx  = t * axis.X;
613         double ty  = t * axis.Y;
614         double tz  = t * axis.Z;
615         double sx  = s * axis.X;
616         double sy  = s * axis.Y;
617         double sz  = s * axis.Z;
618
619         M[0] = tx * axis.X + c;
620         M[1] = tx * axis.Y + sz;
621         M[2] = tx * axis.Z - sy;
622
623         M[4] = ty * axis.X - sz;
624         M[5] = ty * axis.Y + c;
625         M[6] = ty * axis.Z + sx;
626
627         M[8]  = tz * axis.X + sy;
628         M[9]  = tz * axis.Y - sx;
629         M[10] = tz * axis.Z + c;
630         return M;
631 }
632
633
634 v3f transposeMatrix(irr::core::matrix4 M, v3f v)
635 {
636         v3f translated;
637         double x = M[0] * v.X + M[4] * v.Y + M[8]  * v.Z +M[12];
638         double y = M[1] * v.X + M[5] * v.Y + M[9]  * v.Z +M[13];
639         double z = M[2] * v.X + M[6] * v.Y + M[10] * v.Z +M[14];
640         translated.X = x;
641         translated.Y = y;
642         translated.Z = z;
643         return translated;
644 }
645
646
647 void make_jungletree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, s32 seed)
648 {
649         /*
650                 NOTE: Tree-placing code is currently duplicated in the engine
651                 and in games that have saplings; both are deprecated but not
652                 replaced yet
653         */
654         content_t c_tree   = ndef->getId("mapgen_jungletree");
655         content_t c_leaves = ndef->getId("mapgen_jungleleaves");
656         if (c_tree == CONTENT_IGNORE)
657                 c_tree = ndef->getId("mapgen_tree");
658         if (c_leaves == CONTENT_IGNORE)
659                 c_leaves = ndef->getId("mapgen_leaves");
660
661         MapNode treenode(c_tree);
662         MapNode leavesnode(c_leaves);
663
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)
668                         continue;
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);
673
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;
680         }
681         vmanip.m_data[vmanip.m_area.index(p0)] = treenode;
682
683         s16 trunk_h = pr.range(8, 12);
684         v3s16 p1 = p0;
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;
689                 }
690                 p1.Y++;
691         }
692
693         // p1 is now the last piece of the trunk
694         p1.Y -= 1;
695
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++)
700                 leaves_d[i] = 0;
701
702         // Force leaves at near the end of the trunk
703         s16 d = 1;
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;
708         }
709
710         // Add leaves randomly
711         for (u32 iii = 0; iii < 30; iii++) {
712                 v3s16 p(
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)
716                 );
717
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;
722                 }
723         }
724
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++) {
732                         v3s16 p(x, y, z);
733                         if (vmanip.m_area.contains(p + p1) == true &&
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;
738                         }
739                         vi++;
740                         i++;
741                 }
742         }
743 }
744
745
746 void make_pine_tree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, s32 seed)
747 {
748         /*
749                 NOTE: Tree-placing code is currently duplicated in the engine
750                 and in games that have saplings; both are deprecated but not
751                 replaced yet
752         */
753         content_t c_tree   = ndef->getId("mapgen_pine_tree");
754         content_t c_leaves = ndef->getId("mapgen_pine_needles");
755         content_t c_snow = ndef->getId("mapgen_snow");
756         if (c_tree == CONTENT_IGNORE)
757                 c_tree = ndef->getId("mapgen_tree");
758         if (c_leaves == CONTENT_IGNORE)
759                 c_leaves = ndef->getId("mapgen_leaves");
760         if (c_snow == CONTENT_IGNORE)
761                 c_snow = CONTENT_AIR;
762
763         MapNode treenode(c_tree);
764         MapNode leavesnode(c_leaves);
765         MapNode snownode(c_snow);
766
767         PseudoRandom pr(seed);
768         u16 trunk_h = pr.range(9, 13);
769         v3s16 p1 = p0;
770         for (u16 ii = 0; ii < trunk_h; ii++) {
771                 if (vmanip.m_area.contains(p1)) {
772                         u32 vi = vmanip.m_area.index(p1);
773                         vmanip.m_data[vi] = treenode;
774                 }
775                 p1.Y++;
776         }
777
778         // Make p1 the top node of the trunk
779         p1.Y -= 1;
780
781         VoxelArea leaves_a(v3s16(-3, -6, -3), v3s16(3, 3, 3));
782         Buffer<u8> leaves_d(leaves_a.getVolume());
783         for (s32 i = 0; i < leaves_a.getVolume(); i++)
784                 leaves_d[i] = 0;
785
786         // Upper branches
787         u16 dev = 3;
788         for (s16 yy = -1; yy <= 1; yy++) {
789                 for (s16 zz = -dev; zz <= dev; zz++) {
790                         u32 i = leaves_a.index(v3s16(-dev, yy, zz));
791                         u32 ia = leaves_a.index(v3s16(-dev, yy+1, zz));
792                         for (s16 xx = -dev; xx <= dev; xx++) {
793                                 if (pr.range(0, 20) <= 19 - dev) {
794                                         leaves_d[i] = 1;
795                                         leaves_d[ia] = 2;
796                                 }
797                                 i++;
798                                 ia++;
799                         }
800                 }
801                 dev--;
802         }
803
804         // Centre top nodes
805         leaves_d[leaves_a.index(v3s16(0, 1, 0))] = 1;
806         leaves_d[leaves_a.index(v3s16(0, 2, 0))] = 1;
807         leaves_d[leaves_a.index(v3s16(0, 3, 0))] = 2;
808
809         // Lower branches
810         s16 my = -6;
811         for (u32 iii = 0; iii < 20; iii++) {
812                 s16 xi = pr.range(-3, 2);
813                 s16 yy = pr.range(-6, -5);
814                 s16 zi = pr.range(-3, 2);
815                 if (yy > my)
816                         my = yy;
817                 for (s16 zz = zi; zz <= zi + 1; zz++) {
818                         u32 i = leaves_a.index(v3s16(xi, yy, zz));
819                         u32 ia = leaves_a.index(v3s16(xi, yy + 1, zz));
820                         for (s32 xx = xi; xx <= xi + 1; xx++) {
821                                 leaves_d[i] = 1;
822                                 if (leaves_d[ia] == 0)
823                                         leaves_d[ia] = 2;
824                                 i++;
825                                 ia++;
826                         }
827                 }
828         }
829
830         dev = 2;
831         for (s16 yy = my + 1; yy <= my + 2; yy++) {
832                 for (s16 zz = -dev; zz <= dev; zz++) {
833                         u32 i = leaves_a.index(v3s16(-dev, yy, zz));
834                         u32 ia = leaves_a.index(v3s16(-dev, yy + 1, zz));
835                         for (s16 xx = -dev; xx <= dev; xx++) {
836                                 if (pr.range(0, 20) <= 19 - dev) {
837                                         leaves_d[i] = 1;
838                                         leaves_d[ia] = 2;
839                                 }
840                                 i++;
841                                 ia++;
842                         }
843                 }
844                 dev--;
845         }
846
847         // Blit leaves to vmanip
848         for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
849         for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
850                 v3s16 pmin(leaves_a.MinEdge.X, y, z);
851                 u32 i = leaves_a.index(pmin);
852                 u32 vi = vmanip.m_area.index(pmin + p1);
853                 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
854                         v3s16 p(x, y, z);
855                         if (vmanip.m_area.contains(p + p1) == true &&
856                                         (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
857                                         vmanip.m_data[vi].getContent() == CONTENT_IGNORE ||
858                                         vmanip.m_data[vi] == snownode)) {
859                                 if (leaves_d[i] == 1)
860                                         vmanip.m_data[vi] = leavesnode;
861                                 else if (leaves_d[i] == 2)
862                                         vmanip.m_data[vi] = snownode;
863                         }
864                         vi++;
865                         i++;
866                 }
867         }
868 }
869
870 }; // namespace treegen