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