Translation to Portuguese of Brazil for Minetest
[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/numeric.h"
23 #include "util/mathconstants.h"
24 #include "map.h"
25 #include "environment.h"
26 #include "nodedef.h"
27 #include "treegen.h"
28
29 namespace treegen
30 {
31
32 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
33                 bool is_apple_tree, INodeDefManager *ndef, int seed)
34 {
35         MapNode treenode(ndef->getId("mapgen_tree"));
36         MapNode leavesnode(ndef->getId("mapgen_leaves"));
37         MapNode applenode(ndef->getId("mapgen_apple"));
38
39         PseudoRandom pr(seed);
40         s16 trunk_h = pr.range(4, 5);
41         v3s16 p1 = p0;
42         for(s16 ii=0; ii<trunk_h; ii++)
43         {
44                 if(vmanip.m_area.contains(p1))
45                         if(ii == 0 || vmanip.getNodeNoExNoEmerge(p1).getContent() == CONTENT_AIR)
46                                 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
47                 p1.Y++;
48         }
49
50         // p1 is now the last piece of the trunk
51         p1.Y -= 1;
52
53         VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
54         //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
55         Buffer<u8> leaves_d(leaves_a.getVolume());
56         for(s32 i=0; i<leaves_a.getVolume(); i++)
57                 leaves_d[i] = 0;
58
59         // Force leaves at near the end of the trunk
60         {
61                 s16 d = 1;
62                 for(s16 z=-d; z<=d; z++)
63                 for(s16 y=-d; y<=d; y++)
64                 for(s16 x=-d; x<=d; x++)
65                 {
66                         leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
67                 }
68         }
69
70         // Add leaves randomly
71         for(u32 iii=0; iii<7; iii++)
72         {
73                 s16 d = 1;
74
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                 {
85                         leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
86                 }
87         }
88
89         // Blit leaves to vmanip
90         for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
91         for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
92         for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
93         {
94                 v3s16 p(x,y,z);
95                 p += p1;
96                 if(vmanip.m_area.contains(p) == false)
97                         continue;
98                 u32 vi = vmanip.m_area.index(p);
99                 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
100                                 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
101                         continue;
102                 u32 i = leaves_a.index(x,y,z);
103                 if(leaves_d[i] == 1) {
104                         bool is_apple = pr.range(0,99) < 10;
105                         if(is_apple_tree && is_apple) {
106                                 vmanip.m_data[vi] = applenode;
107                         } else {
108                                 vmanip.m_data[vi] = leavesnode;
109                         }
110                 }
111         }
112 }
113
114 // L-System tree LUA spawner
115 void spawn_ltree(ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition)
116 {
117         ServerMap *map = &env->getServerMap();
118         std::map<v3s16, MapBlock*> modified_blocks;
119         ManualMapVoxelManipulator vmanip(map);
120         v3s16 tree_blockp = getNodeBlockPos(p0);
121         vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,3,1));
122         make_ltree (vmanip, p0, ndef, tree_definition);
123         vmanip.blitBackAll(&modified_blocks);
124
125         // update lighting
126         std::map<v3s16, MapBlock*> lighting_modified_blocks;
127         lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
128         map->updateLighting(lighting_modified_blocks, modified_blocks);
129         // Send a MEET_OTHER event
130         MapEditEvent event;
131         event.type = MEET_OTHER;
132         for(std::map<v3s16, MapBlock*>::iterator
133                 i = modified_blocks.begin();
134                 i != modified_blocks.end(); ++i)
135         {
136                 event.modified_blocks.insert(i->first);
137         }
138         map->dispatchEvent(&event);
139 }
140
141 //L-System tree generator
142 void make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *ndef,
143                 TreeDef tree_definition)
144 {
145         MapNode dirtnode(ndef->getId("mapgen_dirt"));
146
147         PseudoRandom ps(tree_definition.seed+14002);
148         // chance of inserting abcd rules
149         double prop_a = 9;
150         double prop_b = 8;
151         double prop_c = 7;
152         double prop_d = 6;
153
154         //randomize tree growth level, minimum=2
155         s16 iterations = tree_definition.iterations;
156         if (tree_definition.iterations_random_level>0)
157                 iterations -= ps.range(0,tree_definition.iterations_random_level);
158         if (iterations<2)
159                 iterations=2;
160
161         s16 MAX_ANGLE_OFFSET = 5;
162         double angle_in_radians = (double)tree_definition.angle*M_PI/180;
163         double angleOffset_in_radians = (s16)(ps.range(0,1)%MAX_ANGLE_OFFSET)*M_PI/180;
164
165         //initialize rotation matrix, position and stacks for branches
166         core::matrix4 rotation;
167         rotation = setRotationAxisRadians(rotation, M_PI/2,v3f(0,0,1));
168         v3f position;
169         position.X = p0.X;
170         position.Y = p0.Y;
171         position.Z = p0.Z;
172         std::stack <core::matrix4> stack_orientation;
173         std::stack <v3f> stack_position;
174
175         //generate axiom
176         std::string axiom = tree_definition.initial_axiom;
177         for(s16 i=0; i<iterations; i++)
178         {
179                 std::string temp = "";
180                 for(s16 j=0; j<(s16)axiom.size(); j++)
181                 {
182                         char axiom_char = axiom.at(j);
183                         switch (axiom_char)
184                         {
185                         case 'A':
186                                 temp+=tree_definition.rules_a;
187                                 break;
188                         case 'B':
189                                 temp+=tree_definition.rules_b;
190                                 break;
191                         case 'C':
192                                 temp+=tree_definition.rules_c;
193                                 break;
194                         case 'D':
195                                 temp+=tree_definition.rules_d;
196                                 break;
197                         case 'a':
198                                 if (prop_a >= ps.range(1,10))
199                                         temp+=tree_definition.rules_a;
200                                 break;
201                         case 'b':
202                                 if (prop_b >= ps.range(1,10))
203                                         temp+=tree_definition.rules_b;
204                                 break;
205                         case 'c':
206                                 if (prop_c >= ps.range(1,10))
207                                         temp+=tree_definition.rules_c;
208                                 break;
209                         case 'd':
210                                 if (prop_d >= ps.range(1,10))
211                                         temp+=tree_definition.rules_d;
212                                 break;
213                         default:
214                                 temp+=axiom_char;
215                                 break;
216                         }
217                 }
218                 axiom=temp;
219         }
220
221         //make sure tree is not floating in the air
222         if (tree_definition.trunk_type == "double")
223         {
224                 tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z),dirtnode);
225                 tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z+1),dirtnode);
226                 tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z+1),dirtnode);
227         }
228         if (tree_definition.trunk_type == "crossed")
229         {
230                 tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z),dirtnode);
231                 tree_node_placement(vmanip,v3f(position.X-1,position.Y-1,position.Z),dirtnode);
232                 tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z+1),dirtnode);
233                 tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z-1),dirtnode);
234         }
235
236         /* build tree out of generated axiom
237
238         Key for Special L-System Symbols used in Axioms
239
240     G  - move forward one unit with the pen up
241     F  - move forward one unit with the pen down drawing trunks and branches
242     f  - move forward one unit with the pen down drawing leaves (100% chance)
243     T  - move forward one unit with the pen down drawing trunks only
244     R  - move forward one unit with the pen down placing fruit
245     A  - replace with rules set A
246     B  - replace with rules set B
247     C  - replace with rules set C
248     D  - replace with rules set D
249     a  - replace with rules set A, chance 90%
250     b  - replace with rules set B, chance 80%
251     c  - replace with rules set C, chance 70%
252     d  - replace with rules set D, chance 60%
253     +  - yaw the turtle right by angle degrees
254     -  - yaw the turtle left by angle degrees
255     &  - pitch the turtle down by angle degrees
256     ^  - pitch the turtle up by angle degrees
257     /  - roll the turtle to the right by angle degrees
258     *  - roll the turtle to the left by angle degrees
259     [  - save in stack current state info
260     ]  - recover from stack state info
261
262     */
263
264         s16 x,y,z;
265         for(s16 i=0; i<(s16)axiom.size(); i++)
266         {
267                 char axiom_char = axiom.at(i);
268                 core::matrix4 temp_rotation;
269                 temp_rotation.makeIdentity();
270                 v3f dir;
271                 switch (axiom_char)
272                 {
273                 case 'G':
274                         dir = v3f(1,0,0);
275                         dir = transposeMatrix(rotation,dir);
276                         position+=dir;
277                         break;
278                 case 'T':
279                         tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
280                         if (tree_definition.trunk_type == "double" && !tree_definition.thin_branches)
281                         {
282                                 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
283                                 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
284                                 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z+1),tree_definition);
285                         }
286                         if (tree_definition.trunk_type == "crossed" && !tree_definition.thin_branches)
287                         {
288                                 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
289                                 tree_trunk_placement(vmanip,v3f(position.X-1,position.Y,position.Z),tree_definition);
290                                 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
291                                 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z-1),tree_definition);
292                         }
293                         dir = v3f(1,0,0);
294                         dir = transposeMatrix(rotation,dir);
295                         position+=dir;
296                         break;
297                 case 'F':
298                         tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
299                         if ((stack_orientation.empty() && tree_definition.trunk_type == "double") ||
300                                 (!stack_orientation.empty() && tree_definition.trunk_type == "double" && !tree_definition.thin_branches))
301                         {
302                                 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
303                                 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
304                                 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z+1),tree_definition);
305                         }
306                         if ((stack_orientation.empty() && tree_definition.trunk_type == "crossed") ||
307                                 (!stack_orientation.empty() && tree_definition.trunk_type == "crossed" && !tree_definition.thin_branches))
308                         {
309                                 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
310                                 tree_trunk_placement(vmanip,v3f(position.X-1,position.Y,position.Z),tree_definition);
311                                 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
312                                 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z-1),tree_definition);
313                         }
314                         if (stack_orientation.empty() == false)
315                         {
316                                 s16 size = 1;
317                                 for(x=-size; x<=size; x++)
318                                         for(y=-size; y<=size; y++)
319                                                 for(z=-size; z<=size; z++)
320                                                         if (abs(x) == size && abs(y) == size && abs(z) == size)
321                                                         {
322                                                                 tree_leaves_placement(vmanip,v3f(position.X+x+1,position.Y+y,position.Z+z),ps.next(), tree_definition);
323                                                                 tree_leaves_placement(vmanip,v3f(position.X+x-1,position.Y+y,position.Z+z),ps.next(), tree_definition);
324                                                                 tree_leaves_placement(vmanip,v3f(position.X+x,position.Y+y,position.Z+z+1),ps.next(), tree_definition);
325                                                                 tree_leaves_placement(vmanip,v3f(position.X+x,position.Y+y,position.Z+z-1),ps.next(), tree_definition);
326                                                         }
327                         }
328                         dir = v3f(1,0,0);
329                         dir = transposeMatrix(rotation,dir);
330                         position+=dir;
331                         break;
332                 case 'f':
333                         tree_single_leaves_placement(vmanip,v3f(position.X,position.Y,position.Z),ps.next() ,tree_definition);
334                         dir = v3f(1,0,0);
335                         dir = transposeMatrix(rotation,dir);
336                         position+=dir;
337                         break;
338                 case 'R':
339                         tree_fruit_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
340                         dir = v3f(1,0,0);
341                         dir = transposeMatrix(rotation,dir);
342                         position+=dir;
343                         break;
344
345                 // turtle orientation commands
346                 case '[':
347                         stack_orientation.push(rotation);
348                         stack_position.push(position);
349                         break;
350                 case ']':
351                         rotation=stack_orientation.top();
352                         stack_orientation.pop();
353                         position=stack_position.top();
354                         stack_position.pop();
355                         break;
356                 case '+':
357                         temp_rotation.makeIdentity();
358                         temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,0,1));
359                         rotation*=temp_rotation;
360                         break;
361                 case '-':
362                         temp_rotation.makeIdentity();
363                         temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,0,-1));
364                         rotation*=temp_rotation;
365                         break;
366                 case '&':
367                         temp_rotation.makeIdentity();
368                         temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,1,0));
369                         rotation*=temp_rotation;
370                         break;
371                 case '^':
372                         temp_rotation.makeIdentity();
373                         temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,-1,0));
374                         rotation*=temp_rotation;
375                         break;
376                 case '*':
377                         temp_rotation.makeIdentity();
378                         temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians,v3f(1,0,0));
379                         rotation*=temp_rotation;
380                         break;
381                 case '/':
382                         temp_rotation.makeIdentity();
383                         temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians,v3f(-1,0,0));
384                         rotation*=temp_rotation;
385                         break;
386                 default:
387                         break;
388                 }
389         }
390 }
391
392 void tree_node_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
393                 MapNode node)
394 {
395         v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
396         if(vmanip.m_area.contains(p1) == false)
397                 return;
398         u32 vi = vmanip.m_area.index(p1);
399         if(vmanip.m_data[vi].getContent() != CONTENT_AIR
400                         && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
401                 return;
402         vmanip.m_data[vmanip.m_area.index(p1)] = node;
403 }
404
405 void tree_trunk_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
406                 TreeDef &tree_definition)
407 {
408         v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
409         if(vmanip.m_area.contains(p1) == false)
410                 return;
411         u32 vi = vmanip.m_area.index(p1);
412         if(vmanip.m_data[vi].getContent() != CONTENT_AIR
413                         && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
414                 return;
415         vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.trunknode;
416 }
417
418 void tree_leaves_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
419                 PseudoRandom ps ,TreeDef &tree_definition)
420 {
421         MapNode leavesnode=tree_definition.leavesnode;
422         if (ps.range(1,100) > 100-tree_definition.leaves2_chance)
423                 leavesnode=tree_definition.leaves2node;
424         v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
425         if(vmanip.m_area.contains(p1) == false)
426                 return;
427         u32 vi = vmanip.m_area.index(p1);
428         if(vmanip.m_data[vi].getContent() != CONTENT_AIR
429                         && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
430                 return; 
431         if (tree_definition.fruit_chance>0)
432         {
433                 if (ps.range(1,100) > 100-tree_definition.fruit_chance)
434                         vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
435                 else
436                         vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
437         }
438         else if (ps.range(1,100) > 20)
439                 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
440 }
441
442 void tree_single_leaves_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
443                 PseudoRandom ps, TreeDef &tree_definition)
444 {
445         MapNode leavesnode=tree_definition.leavesnode;
446         if (ps.range(1,100) > 100-tree_definition.leaves2_chance)
447                 leavesnode=tree_definition.leaves2node;
448         v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
449         if(vmanip.m_area.contains(p1) == false)
450                 return;
451         u32 vi = vmanip.m_area.index(p1);
452         if(vmanip.m_data[vi].getContent() != CONTENT_AIR
453                 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
454                 return;
455         vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
456 }
457
458 void tree_fruit_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
459                 TreeDef &tree_definition)
460 {
461         v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
462         if(vmanip.m_area.contains(p1) == false)
463                 return;
464         u32 vi = vmanip.m_area.index(p1);
465         if(vmanip.m_data[vi].getContent() != CONTENT_AIR
466                 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
467                 return;
468         vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
469 }
470
471 irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis)
472 {
473         double c = cos(angle);
474         double s = sin(angle);
475         double t = 1.0 - c;
476
477         double tx  = t * axis.X;
478         double ty  = t * axis.Y;
479         double tz  = t * axis.Z;
480         double sx  = s * axis.X;
481         double sy  = s * axis.Y;
482         double sz  = s * axis.Z;
483
484         M[0] = tx * axis.X + c;
485         M[1] = tx * axis.Y + sz;
486         M[2] = tx * axis.Z - sy;
487
488         M[4] = ty * axis.X - sz;
489         M[5] = ty * axis.Y + c;
490         M[6] = ty * axis.Z + sx;
491
492         M[8]  = tz * axis.X + sy;
493         M[9]  = tz * axis.Y - sx;
494         M[10] = tz * axis.Z + c;
495         return M;
496 }
497
498 v3f transposeMatrix(irr::core::matrix4 M, v3f v)
499 {
500         v3f translated;
501         double x = M[0] * v.X + M[4] * v.Y + M[8]  * v.Z +M[12];
502         double y = M[1] * v.X + M[5] * v.Y + M[9]  * v.Z +M[13];
503         double z = M[2] * v.X + M[6] * v.Y + M[10] * v.Z +M[14];
504         translated.X=x;
505         translated.Y=y;
506         translated.Z=z;
507         return translated;
508 }
509
510 void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
511                 INodeDefManager *ndef, int seed)
512 {
513         content_t c_tree   = ndef->getId("mapgen_jungletree");
514         content_t c_leaves = ndef->getId("mapgen_jungleleaves");
515         if (c_tree == CONTENT_IGNORE)
516                 c_tree = ndef->getId("mapgen_tree");
517         if (c_leaves == CONTENT_IGNORE)
518                 c_leaves = ndef->getId("mapgen_leaves");
519
520         MapNode treenode(c_tree);
521         MapNode leavesnode(c_leaves);
522
523         PseudoRandom pr(seed);
524         for(s16 x=-1; x<=1; x++)
525         for(s16 z=-1; z<=1; z++)
526         {
527                 if(pr.range(0, 2) == 0)
528                         continue;
529                 v3s16 p1 = p0 + v3s16(x,0,z);
530                 v3s16 p2 = p0 + v3s16(x,-1,z);
531                 u32 vi1 = vmanip.m_area.index(p1);
532                 u32 vi2 = vmanip.m_area.index(p2);
533                 
534                 if (vmanip.m_area.contains(p2) &&
535                         vmanip.m_data[vi2].getContent() == CONTENT_AIR)
536                         vmanip.m_data[vi2] = treenode;
537                 else if (vmanip.m_area.contains(p1) &&
538                                 vmanip.m_data[vi1].getContent() == CONTENT_AIR)
539                         vmanip.m_data[vi1] = treenode;
540         }
541         vmanip.m_data[vmanip.m_area.index(p0)] = treenode;
542
543         s16 trunk_h = pr.range(8, 12);
544         v3s16 p1 = p0;
545         for (s16 ii=0; ii<trunk_h; ii++)
546         {
547                 if (vmanip.m_area.contains(p1)) {
548                         u32 vi = vmanip.m_area.index(p1);
549                         if (vmanip.m_data[vi].getContent() == CONTENT_AIR)
550                                 vmanip.m_data[vi] = treenode;
551                 }
552                 p1.Y++;
553         }
554
555         // p1 is now the last piece of the trunk
556         p1.Y -= 1;
557
558         VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
559         //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
560         Buffer<u8> leaves_d(leaves_a.getVolume());
561         for(s32 i=0; i<leaves_a.getVolume(); i++)
562                 leaves_d[i] = 0;
563
564         // Force leaves at near the end of the trunk
565         {
566                 s16 d = 1;
567                 for(s16 z=-d; z<=d; z++)
568                 for(s16 y=-d; y<=d; y++)
569                 for(s16 x=-d; x<=d; x++)
570                 {
571                         leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
572                 }
573         }
574
575         // Add leaves randomly
576         for(u32 iii=0; iii<30; iii++)
577         {
578                 s16 d = 1;
579
580                 v3s16 p(
581                         pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
582                         pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
583                         pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
584                 );
585
586                 for(s16 z=0; z<=d; z++)
587                 for(s16 y=0; y<=d; y++)
588                 for(s16 x=0; x<=d; x++)
589                 {
590                         leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
591                 }
592         }
593
594         // Blit leaves to vmanip
595         for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
596         for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
597         for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
598         {
599                 v3s16 p(x,y,z);
600                 p += p1;
601                 if(vmanip.m_area.contains(p) == false)
602                         continue;
603                 u32 vi = vmanip.m_area.index(p);
604                 if (vmanip.m_data[vi].getContent() != CONTENT_AIR &&
605                         vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
606                         continue;
607                 u32 i = leaves_a.index(x,y,z);
608                 if(leaves_d[i] == 1)
609                         vmanip.m_data[vi] = leavesnode;
610         }
611 }
612
613 }; // namespace treegen