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