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