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.
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.
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.
22 #include "util/numeric.h"
23 #include "util/mathconstants.h"
25 #include "environment.h"
31 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
32 bool is_apple_tree, INodeDefManager *ndef,int seed)
34 MapNode treenode(ndef->getId("mapgen_tree"));
35 MapNode leavesnode(ndef->getId("mapgen_leaves"));
36 MapNode applenode(ndef->getId("mapgen_apple"));
38 PseudoRandom ps(seed);
39 s16 trunk_h = ps.range(4, 5);
41 for(s16 ii=0; ii<trunk_h; ii++)
43 if(vmanip.m_area.contains(p1))
44 if(ii == 0 || vmanip.getNodeNoExNoEmerge(p1).getContent() == CONTENT_AIR)
45 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
49 // p1 is now the last piece of the trunk
52 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
53 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
54 Buffer<u8> leaves_d(leaves_a.getVolume());
55 for(s32 i=0; i<leaves_a.getVolume(); i++)
58 // Force leaves at near the end of the trunk
61 for(s16 z=-d; z<=d; z++)
62 for(s16 y=-d; y<=d; y++)
63 for(s16 x=-d; x<=d; x++)
65 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
69 // Add leaves randomly
70 for(u32 iii=0; iii<7; iii++)
75 ps.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
76 ps.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
77 ps.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
80 for(s16 z=0; z<=d; z++)
81 for(s16 y=0; y<=d; y++)
82 for(s16 x=0; x<=d; x++)
84 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
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 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
95 if(vmanip.m_area.contains(p) == false)
97 u32 vi = vmanip.m_area.index(p);
98 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
99 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
101 u32 i = leaves_a.index(x,y,z);
102 if(leaves_d[i] == 1) {
103 bool is_apple = ps.range(0,99) < 10;
104 if(is_apple_tree && is_apple) {
105 vmanip.m_data[vi] = applenode;
107 vmanip.m_data[vi] = leavesnode;
113 // L-System tree LUA spawner
114 void spawn_ltree (ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition)
116 ServerMap *map = &env->getServerMap();
117 std::map<v3s16, MapBlock*> modified_blocks;
118 ManualMapVoxelManipulator vmanip(map);
119 v3s16 tree_blockp = getNodeBlockPos(p0);
120 vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,3,1));
121 make_ltree (vmanip, p0, ndef, tree_definition);
122 vmanip.blitBackAll(&modified_blocks);
125 std::map<v3s16, MapBlock*> lighting_modified_blocks;
126 lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
127 map->updateLighting(lighting_modified_blocks, modified_blocks);
128 // Send a MEET_OTHER event
130 event.type = MEET_OTHER;
131 for(std::map<v3s16, MapBlock*>::iterator
132 i = modified_blocks.begin();
133 i != modified_blocks.end(); ++i)
135 event.modified_blocks.insert(i->first);
137 map->dispatchEvent(&event);
140 //L-System tree generator
141 void make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *ndef,
142 TreeDef tree_definition)
144 MapNode dirtnode(ndef->getId("mapgen_dirt"));
146 PseudoRandom ps(tree_definition.seed+14002);
147 // chance of inserting abcd rules
153 //randomize tree growth level, minimum=2
154 s16 iterations = tree_definition.iterations;
155 if (tree_definition.iterations_random_level>0)
156 iterations -= ps.range(0,tree_definition.iterations_random_level);
160 s16 MAX_ANGLE_OFFSET = 5;
161 double angle_in_radians = (double)tree_definition.angle*M_PI/180;
162 double angleOffset_in_radians = (s16)(ps.range(0,1)%MAX_ANGLE_OFFSET)*M_PI/180;
164 //initialize rotation matrix, position and stacks for branches
165 core::matrix4 rotation;
166 rotation = setRotationAxisRadians(rotation, M_PI/2,v3f(0,0,1));
171 std::stack <core::matrix4> stack_orientation;
172 std::stack <v3f> stack_position;
175 std::string axiom = tree_definition.initial_axiom;
176 for(s16 i=0; i<iterations; i++)
178 std::string temp = "";
179 for(s16 j=0; j<(s16)axiom.size(); j++)
181 char axiom_char = axiom.at(j);
185 temp+=tree_definition.rules_a;
188 temp+=tree_definition.rules_b;
191 temp+=tree_definition.rules_c;
194 temp+=tree_definition.rules_d;
197 if (prop_a >= ps.range(1,10))
198 temp+=tree_definition.rules_a;
201 if (prop_b >= ps.range(1,10))
202 temp+=tree_definition.rules_b;
205 if (prop_c >= ps.range(1,10))
206 temp+=tree_definition.rules_c;
209 if (prop_d >= ps.range(1,10))
210 temp+=tree_definition.rules_d;
220 //make sure tree is not floating in the air
221 if (tree_definition.trunk_type == "double")
223 tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z),dirtnode);
224 tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z+1),dirtnode);
225 tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z+1),dirtnode);
227 if (tree_definition.trunk_type == "crossed")
229 tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z),dirtnode);
230 tree_node_placement(vmanip,v3f(position.X-1,position.Y-1,position.Z),dirtnode);
231 tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z+1),dirtnode);
232 tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z-1),dirtnode);
235 /* build tree out of generated axiom
237 Key for Special L-System Symbols used in Axioms
239 G - move forward one unit with the pen up
240 F - move forward one unit with the pen down drawing trunks and branches
241 f - move forward one unit with the pen down drawing leaves (100% chance)
242 T - move forward one unit with the pen down drawing trunks only
243 R - move forward one unit with the pen down placing fruit
244 A - replace with rules set A
245 B - replace with rules set B
246 C - replace with rules set C
247 D - replace with rules set D
248 a - replace with rules set A, chance 90%
249 b - replace with rules set B, chance 80%
250 c - replace with rules set C, chance 70%
251 d - replace with rules set D, chance 60%
252 + - yaw the turtle right by angle degrees
253 - - yaw the turtle left by angle degrees
254 & - pitch the turtle down by angle degrees
255 ^ - pitch the turtle up by angle degrees
256 / - roll the turtle to the right by angle degrees
257 * - roll the turtle to the left by angle degrees
258 [ - save in stack current state info
259 ] - recover from stack state info
264 for(s16 i=0; i<(s16)axiom.size(); i++)
266 char axiom_char = axiom.at(i);
267 core::matrix4 temp_rotation;
268 temp_rotation.makeIdentity();
274 dir = transposeMatrix(rotation,dir);
278 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
279 if (tree_definition.trunk_type == "double" && !tree_definition.thin_branches)
281 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
282 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
283 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z+1),tree_definition);
285 if (tree_definition.trunk_type == "crossed" && !tree_definition.thin_branches)
287 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
288 tree_trunk_placement(vmanip,v3f(position.X-1,position.Y,position.Z),tree_definition);
289 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
290 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z-1),tree_definition);
293 dir = transposeMatrix(rotation,dir);
297 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
298 if ((stack_orientation.empty() && tree_definition.trunk_type == "double") ||
299 (!stack_orientation.empty() && tree_definition.trunk_type == "double" && !tree_definition.thin_branches))
301 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
302 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
303 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z+1),tree_definition);
305 if ((stack_orientation.empty() && tree_definition.trunk_type == "crossed") ||
306 (!stack_orientation.empty() && tree_definition.trunk_type == "crossed" && !tree_definition.thin_branches))
308 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
309 tree_trunk_placement(vmanip,v3f(position.X-1,position.Y,position.Z),tree_definition);
310 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
311 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z-1),tree_definition);
313 if (stack_orientation.empty() == false)
316 for(x=-size; x<=size; x++)
317 for(y=-size; y<=size; y++)
318 for(z=-size; z<=size; z++)
319 if (abs(x) == size && abs(y) == size && abs(z) == size)
321 tree_leaves_placement(vmanip,v3f(position.X+x+1,position.Y+y,position.Z+z),ps.next(), tree_definition);
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,position.Y+y,position.Z+z+1),ps.next(), tree_definition);
324 tree_leaves_placement(vmanip,v3f(position.X+x,position.Y+y,position.Z+z-1),ps.next(), tree_definition);
328 dir = transposeMatrix(rotation,dir);
332 tree_single_leaves_placement(vmanip,v3f(position.X,position.Y,position.Z),ps.next() ,tree_definition);
334 dir = transposeMatrix(rotation,dir);
338 tree_fruit_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
340 dir = transposeMatrix(rotation,dir);
344 // turtle orientation commands
346 stack_orientation.push(rotation);
347 stack_position.push(position);
350 rotation=stack_orientation.top();
351 stack_orientation.pop();
352 position=stack_position.top();
353 stack_position.pop();
356 temp_rotation.makeIdentity();
357 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,0,1));
358 rotation*=temp_rotation;
361 temp_rotation.makeIdentity();
362 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,0,-1));
363 rotation*=temp_rotation;
366 temp_rotation.makeIdentity();
367 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,1,0));
368 rotation*=temp_rotation;
371 temp_rotation.makeIdentity();
372 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,-1,0));
373 rotation*=temp_rotation;
376 temp_rotation.makeIdentity();
377 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians,v3f(1,0,0));
378 rotation*=temp_rotation;
381 temp_rotation.makeIdentity();
382 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians,v3f(-1,0,0));
383 rotation*=temp_rotation;
391 void tree_node_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
394 v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
395 if(vmanip.m_area.contains(p1) == false)
397 u32 vi = vmanip.m_area.index(p1);
398 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
399 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
401 vmanip.m_data[vmanip.m_area.index(p1)] = node;
404 void tree_trunk_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
405 TreeDef &tree_definition)
407 v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
408 if(vmanip.m_area.contains(p1) == false)
410 u32 vi = vmanip.m_area.index(p1);
411 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
412 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
414 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.trunknode;
417 void tree_leaves_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
418 PseudoRandom ps ,TreeDef &tree_definition)
420 MapNode leavesnode=tree_definition.leavesnode;
421 if (ps.range(1,100) > 100-tree_definition.leaves2_chance)
422 leavesnode=tree_definition.leaves2node;
423 v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
424 if(vmanip.m_area.contains(p1) == false)
426 u32 vi = vmanip.m_area.index(p1);
427 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
428 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
430 if (tree_definition.fruit_chance>0)
432 if (ps.range(1,100) > 100-tree_definition.fruit_chance)
433 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
435 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
437 else if (ps.range(1,100) > 20)
438 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
441 void tree_single_leaves_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
442 PseudoRandom ps, TreeDef &tree_definition)
444 MapNode leavesnode=tree_definition.leavesnode;
445 if (ps.range(1,100) > 100-tree_definition.leaves2_chance)
446 leavesnode=tree_definition.leaves2node;
447 v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
448 if(vmanip.m_area.contains(p1) == false)
450 u32 vi = vmanip.m_area.index(p1);
451 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
452 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
454 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
457 void tree_fruit_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
458 TreeDef &tree_definition)
460 v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
461 if(vmanip.m_area.contains(p1) == false)
463 u32 vi = vmanip.m_area.index(p1);
464 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
465 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
467 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
470 irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis)
472 double c = cos(angle);
473 double s = sin(angle);
476 double tx = t * axis.X;
477 double ty = t * axis.Y;
478 double tz = t * axis.Z;
479 double sx = s * axis.X;
480 double sy = s * axis.Y;
481 double sz = s * axis.Z;
483 M[0] = tx * axis.X + c;
484 M[1] = tx * axis.Y + sz;
485 M[2] = tx * axis.Z - sy;
487 M[4] = ty * axis.X - sz;
488 M[5] = ty * axis.Y + c;
489 M[6] = ty * axis.Z + sx;
491 M[8] = tz * axis.X + sy;
492 M[9] = tz * axis.Y - sx;
493 M[10] = tz * axis.Z + c;
497 v3f transposeMatrix(irr::core::matrix4 M, v3f v)
500 double x = M[0] * v.X + M[4] * v.Y + M[8] * v.Z +M[12];
501 double y = M[1] * v.X + M[5] * v.Y + M[9] * v.Z +M[13];
502 double z = M[2] * v.X + M[6] * v.Y + M[10] * v.Z +M[14];
510 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
511 INodeDefManager *ndef)
513 MapNode treenode(ndef->getId("mapgen_jungletree"));
514 MapNode leavesnode(ndef->getId("mapgen_leaves"));
516 for(s16 x=-1; x<=1; x++)
517 for(s16 z=-1; z<=1; z++)
519 if(myrand_range(0, 2) == 0)
521 v3s16 p1 = p0 + v3s16(x,0,z);
522 v3s16 p2 = p0 + v3s16(x,-1,z);
523 if(vmanip.m_area.contains(p2)
524 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
525 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
526 else if(vmanip.m_area.contains(p1))
527 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
530 s16 trunk_h = myrand_range(8, 12);
532 for(s16 ii=0; ii<trunk_h; ii++)
534 if(vmanip.m_area.contains(p1))
535 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
539 // p1 is now the last piece of the trunk
542 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
543 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
544 Buffer<u8> leaves_d(leaves_a.getVolume());
545 for(s32 i=0; i<leaves_a.getVolume(); i++)
548 // Force leaves at near the end of the trunk
551 for(s16 z=-d; z<=d; z++)
552 for(s16 y=-d; y<=d; y++)
553 for(s16 x=-d; x<=d; x++)
555 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
559 // Add leaves randomly
560 for(u32 iii=0; iii<30; iii++)
565 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
566 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
567 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
570 for(s16 z=0; z<=d; z++)
571 for(s16 y=0; y<=d; y++)
572 for(s16 x=0; x<=d; x++)
574 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
578 // Blit leaves to vmanip
579 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
580 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
581 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
585 if(vmanip.m_area.contains(p) == false)
587 u32 vi = vmanip.m_area.index(p);
588 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
589 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
591 u32 i = leaves_a.index(x,y,z);
593 vmanip.m_data[vi] = leavesnode;
598 }; // namespace treegen