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