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