]> git.lizzy.rs Git - minetest.git/blob - src/treegen.cpp
Optimize headers (part 2) (#6272)
[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 "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) == 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         content_t current_node = vmanip.m_data[vi].getContent();
547         if (current_node != CONTENT_AIR && current_node != CONTENT_IGNORE
548                         && current_node != tree_definition.leavesnode.getContent()
549                         && current_node != tree_definition.leaves2node.getContent()
550                         && current_node != tree_definition.fruitnode.getContent())
551                 return;
552         vmanip.m_data[vi] = 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         Buffer<u8> leaves_d(leaves_a.getVolume());
787         for (s32 i = 0; i < leaves_a.getVolume(); i++)
788                 leaves_d[i] = 0;
789
790         // Upper branches
791         u16 dev = 3;
792         for (s16 yy = -1; yy <= 1; yy++) {
793                 for (s16 zz = -dev; zz <= dev; zz++) {
794                         u32 i = leaves_a.index(v3s16(-dev, yy, zz));
795                         u32 ia = leaves_a.index(v3s16(-dev, yy+1, zz));
796                         for (s16 xx = -dev; xx <= dev; xx++) {
797                                 if (pr.range(0, 20) <= 19 - dev) {
798                                         leaves_d[i] = 1;
799                                         leaves_d[ia] = 2;
800                                 }
801                                 i++;
802                                 ia++;
803                         }
804                 }
805                 dev--;
806         }
807
808         // Centre top nodes
809         leaves_d[leaves_a.index(v3s16(0, 1, 0))] = 1;
810         leaves_d[leaves_a.index(v3s16(0, 2, 0))] = 1;
811         leaves_d[leaves_a.index(v3s16(0, 3, 0))] = 2;
812
813         // Lower branches
814         s16 my = -6;
815         for (u32 iii = 0; iii < 20; iii++) {
816                 s16 xi = pr.range(-3, 2);
817                 s16 yy = pr.range(-6, -5);
818                 s16 zi = pr.range(-3, 2);
819                 if (yy > my)
820                         my = yy;
821                 for (s16 zz = zi; zz <= zi + 1; zz++) {
822                         u32 i = leaves_a.index(v3s16(xi, yy, zz));
823                         u32 ia = leaves_a.index(v3s16(xi, yy + 1, zz));
824                         for (s32 xx = xi; xx <= xi + 1; xx++) {
825                                 leaves_d[i] = 1;
826                                 if (leaves_d[ia] == 0)
827                                         leaves_d[ia] = 2;
828                                 i++;
829                                 ia++;
830                         }
831                 }
832         }
833
834         dev = 2;
835         for (s16 yy = my + 1; yy <= my + 2; yy++) {
836                 for (s16 zz = -dev; zz <= dev; zz++) {
837                         u32 i = leaves_a.index(v3s16(-dev, yy, zz));
838                         u32 ia = leaves_a.index(v3s16(-dev, yy + 1, zz));
839                         for (s16 xx = -dev; xx <= dev; xx++) {
840                                 if (pr.range(0, 20) <= 19 - dev) {
841                                         leaves_d[i] = 1;
842                                         leaves_d[ia] = 2;
843                                 }
844                                 i++;
845                                 ia++;
846                         }
847                 }
848                 dev--;
849         }
850
851         // Blit leaves to vmanip
852         for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
853         for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
854                 v3s16 pmin(leaves_a.MinEdge.X, y, z);
855                 u32 i = leaves_a.index(pmin);
856                 u32 vi = vmanip.m_area.index(pmin + p1);
857                 for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
858                         v3s16 p(x, y, z);
859                         if (vmanip.m_area.contains(p + p1) == true &&
860                                         (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
861                                         vmanip.m_data[vi].getContent() == CONTENT_IGNORE ||
862                                         vmanip.m_data[vi] == snownode)) {
863                                 if (leaves_d[i] == 1)
864                                         vmanip.m_data[vi] = leavesnode;
865                                 else if (leaves_d[i] == 2)
866                                         vmanip.m_data[vi] = snownode;
867                         }
868                         vi++;
869                         i++;
870                 }
871         }
872 }
873
874 }; // namespace treegen