3 Copyright (C) 2010-2012 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"
26 #include "environment.h"
33 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
34 bool is_apple_tree, INodeDefManager *ndef)
36 MapNode treenode(ndef->getId("mapgen_tree"));
37 MapNode leavesnode(ndef->getId("mapgen_leaves"));
38 MapNode applenode(ndef->getId("mapgen_apple"));
40 s16 trunk_h = myrand_range(4, 5);
42 for(s16 ii=0; ii<trunk_h; ii++)
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;
50 // p1 is now the last piece of the trunk
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++)
59 // Force leaves at near the end of the trunk
62 for(s16 z=-d; z<=d; z++)
63 for(s16 y=-d; y<=d; y++)
64 for(s16 x=-d; x<=d; x++)
66 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
70 // Add leaves randomly
71 for(u32 iii=0; iii<7; iii++)
76 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
77 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
78 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
81 for(s16 z=0; z<=d; z++)
82 for(s16 y=0; y<=d; y++)
83 for(s16 x=0; x<=d; x++)
85 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
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++)
96 if(vmanip.m_area.contains(p) == false)
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)
102 u32 i = leaves_a.index(x,y,z);
103 if(leaves_d[i] == 1) {
104 bool is_apple = myrand_range(0,99) < 10;
105 if(is_apple_tree && is_apple) {
106 vmanip.m_data[vi] = applenode;
108 vmanip.m_data[vi] = leavesnode;
114 // L-System tree LUA spawner
115 void spawn_ltree (ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition)
117 ServerMap *map = &env->getServerMap();
118 core::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);
126 core::map<v3s16, MapBlock*> lighting_modified_blocks;
127 for(core::map<v3s16, MapBlock*>::Iterator
128 i = modified_blocks.getIterator();
129 i.atEnd() == false; i++)
131 lighting_modified_blocks.insert(i.getNode()->getKey(), i.getNode()->getValue());
133 map->updateLighting(lighting_modified_blocks, modified_blocks);
134 // Send a MEET_OTHER event
136 event.type = MEET_OTHER;
137 for(core::map<v3s16, MapBlock*>::Iterator
138 i = modified_blocks.getIterator();
139 i.atEnd() == false; i++)
141 v3s16 p = i.getNode()->getKey();
142 event.modified_blocks.insert(p, true);
144 map->dispatchEvent(&event);
147 //L-System tree generator
148 void make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *ndef,
149 TreeDef tree_definition)
151 MapNode dirtnode(ndef->getId("mapgen_dirt"));
153 // chance of inserting abcd rules
159 //randomize tree growth level, minimum=2
160 s16 iterations = tree_definition.iterations;
161 if (tree_definition.iterations_random_level>0)
162 iterations -= myrand_range(0,tree_definition.iterations_random_level);
166 s16 MAX_ANGLE_OFFSET = 5;
167 double angle_in_radians = (double)tree_definition.angle*M_PI/180;
168 double angleOffset_in_radians = (s16)(myrand_range(0,1)%MAX_ANGLE_OFFSET)*M_PI/180;
170 //initialize rotation matrix, position and stacks for branches
171 core::matrix4 rotation;
172 rotation = setRotationAxisRadians(rotation, M_PI/2,v3f(0,0,1));
177 std::stack <core::matrix4> stack_orientation;
178 std::stack <v3f> stack_position;
181 std::string axiom = tree_definition.initial_axiom;
182 for(s16 i=0; i<iterations; i++)
184 std::string temp = "";
185 for(s16 j=0; j<(s16)axiom.size(); j++)
187 char axiom_char = axiom.at(j);
191 temp+=tree_definition.rules_a;
194 temp+=tree_definition.rules_b;
197 temp+=tree_definition.rules_c;
200 temp+=tree_definition.rules_d;
203 if (prop_a >= myrand_range(1,10))
204 temp+=tree_definition.rules_a;
207 if (prop_b >= myrand_range(1,10))
208 temp+=tree_definition.rules_b;
211 if (prop_c >= myrand_range(1,10))
212 temp+=tree_definition.rules_c;
215 if (prop_d >= myrand_range(1,10))
216 temp+=tree_definition.rules_d;
226 //make sure tree is not floating in the air
227 if (tree_definition.trunk_type == "double")
229 tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z),dirtnode);
230 tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z+1),dirtnode);
231 tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z+1),dirtnode);
233 if (tree_definition.trunk_type == "crossed")
235 tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z),dirtnode);
236 tree_node_placement(vmanip,v3f(position.X-1,position.Y-1,position.Z),dirtnode);
237 tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z+1),dirtnode);
238 tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z-1),dirtnode);
241 /* build tree out of generated axiom
243 Key for Special L-System Symbols used in Axioms
245 G - move forward one unit with the pen up
246 F - move forward one unit with the pen down drawing trunks and branches
247 f - move forward one unit with the pen down drawing leaves (100% chance)
248 T - move forward one unit with the pen down drawing trunks only
249 R - move forward one unit with the pen down placing fruit
250 A - replace with rules set A
251 B - replace with rules set B
252 C - replace with rules set C
253 D - replace with rules set D
254 a - replace with rules set A, chance 90%
255 b - replace with rules set B, chance 80%
256 c - replace with rules set C, chance 70%
257 d - replace with rules set D, chance 60%
258 + - yaw the turtle right by angle degrees
259 - - yaw the turtle left by angle degrees
260 & - pitch the turtle down by angle degrees
261 ^ - pitch the turtle up by angle degrees
262 / - roll the turtle to the right by angle degrees
263 * - roll the turtle to the left by angle degrees
264 [ - save in stack current state info
265 ] - recover from stack state info
270 for(s16 i=0; i<(s16)axiom.size(); i++)
272 char axiom_char = axiom.at(i);
273 core::matrix4 temp_rotation;
274 temp_rotation.makeIdentity();
280 dir = transposeMatrix(rotation,dir);
284 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
285 if (tree_definition.trunk_type == "double" && !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,position.Y,position.Z+1),tree_definition);
289 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z+1),tree_definition);
291 if (tree_definition.trunk_type == "crossed" && !tree_definition.thin_branches)
293 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
294 tree_trunk_placement(vmanip,v3f(position.X-1,position.Y,position.Z),tree_definition);
295 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
296 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z-1),tree_definition);
299 dir = transposeMatrix(rotation,dir);
303 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
304 if ((stack_orientation.empty() && tree_definition.trunk_type == "double") ||
305 (!stack_orientation.empty() && tree_definition.trunk_type == "double" && !tree_definition.thin_branches))
307 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
308 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
309 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z+1),tree_definition);
311 if ((stack_orientation.empty() && tree_definition.trunk_type == "crossed") ||
312 (!stack_orientation.empty() && tree_definition.trunk_type == "crossed" && !tree_definition.thin_branches))
314 tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
315 tree_trunk_placement(vmanip,v3f(position.X-1,position.Y,position.Z),tree_definition);
316 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
317 tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z-1),tree_definition);
319 if (stack_orientation.empty() == false)
322 for(x=-size; x<=size; x++)
323 for(y=-size; y<=size; y++)
324 for(z=-size; z<=size; z++)
325 if (abs(x) == size && abs(y) == size && abs(z) == size)
327 tree_leaves_placement(vmanip,v3f(position.X+x+1,position.Y+y,position.Z+z),tree_definition);
328 tree_leaves_placement(vmanip,v3f(position.X+x-1,position.Y+y,position.Z+z),tree_definition);
329 tree_leaves_placement(vmanip,v3f(position.X+x,position.Y+y,position.Z+z+1),tree_definition);
330 tree_leaves_placement(vmanip,v3f(position.X+x,position.Y+y,position.Z+z-1),tree_definition);
334 dir = transposeMatrix(rotation,dir);
338 tree_single_leaves_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
340 dir = transposeMatrix(rotation,dir);
344 tree_fruit_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
346 dir = transposeMatrix(rotation,dir);
350 // turtle orientation commands
352 stack_orientation.push(rotation);
353 stack_position.push(position);
356 rotation=stack_orientation.top();
357 stack_orientation.pop();
358 position=stack_position.top();
359 stack_position.pop();
362 temp_rotation.makeIdentity();
363 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,0,1));
364 rotation*=temp_rotation;
367 temp_rotation.makeIdentity();
368 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,0,-1));
369 rotation*=temp_rotation;
372 temp_rotation.makeIdentity();
373 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,1,0));
374 rotation*=temp_rotation;
377 temp_rotation.makeIdentity();
378 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,-1,0));
379 rotation*=temp_rotation;
382 temp_rotation.makeIdentity();
383 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians,v3f(1,0,0));
384 rotation*=temp_rotation;
387 temp_rotation.makeIdentity();
388 temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians,v3f(-1,0,0));
389 rotation*=temp_rotation;
397 void tree_node_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
400 v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
401 if(vmanip.m_area.contains(p1) == false)
403 u32 vi = vmanip.m_area.index(p1);
404 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
405 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
407 vmanip.m_data[vmanip.m_area.index(p1)] = node;
410 void tree_trunk_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
411 TreeDef &tree_definition)
413 v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
414 if(vmanip.m_area.contains(p1) == false)
416 u32 vi = vmanip.m_area.index(p1);
417 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
418 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
420 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.trunknode;
423 void tree_leaves_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
424 TreeDef &tree_definition)
426 MapNode leavesnode=tree_definition.leavesnode;
427 if (myrand_range(1,100) > 100-tree_definition.leaves2_chance)
428 leavesnode=tree_definition.leaves2node;
429 v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
430 if(vmanip.m_area.contains(p1) == false)
432 u32 vi = vmanip.m_area.index(p1);
433 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
434 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
436 if (tree_definition.fruit_chance>0)
438 if (myrand_range(1,100) > 100-tree_definition.fruit_chance)
439 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
441 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
443 else if (myrand_range(1,100) > 20)
444 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
447 void tree_single_leaves_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
448 TreeDef &tree_definition)
450 MapNode leavesnode=tree_definition.leavesnode;
451 if (myrand_range(1,100) > 100-tree_definition.leaves2_chance)
452 leavesnode=tree_definition.leaves2node;
453 v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
454 if(vmanip.m_area.contains(p1) == false)
456 u32 vi = vmanip.m_area.index(p1);
457 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
458 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
460 vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
463 void tree_fruit_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
464 TreeDef &tree_definition)
466 v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
467 if(vmanip.m_area.contains(p1) == false)
469 u32 vi = vmanip.m_area.index(p1);
470 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
471 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
473 vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
476 irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis)
478 double c = cos(angle);
479 double s = sin(angle);
482 double tx = t * axis.X;
483 double ty = t * axis.Y;
484 double tz = t * axis.Z;
485 double sx = s * axis.X;
486 double sy = s * axis.Y;
487 double sz = s * axis.Z;
489 M[0] = tx * axis.X + c;
490 M[1] = tx * axis.Y + sz;
491 M[2] = tx * axis.Z - sy;
493 M[4] = ty * axis.X - sz;
494 M[5] = ty * axis.Y + c;
495 M[6] = ty * axis.Z + sx;
497 M[8] = tz * axis.X + sy;
498 M[9] = tz * axis.Y - sx;
499 M[10] = tz * axis.Z + c;
503 v3f transposeMatrix(irr::core::matrix4 M, v3f v)
506 double x = M[0] * v.X + M[4] * v.Y + M[8] * v.Z +M[12];
507 double y = M[1] * v.X + M[5] * v.Y + M[9] * v.Z +M[13];
508 double z = M[2] * v.X + M[6] * v.Y + M[10] * v.Z +M[14];
516 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
517 INodeDefManager *ndef)
519 MapNode treenode(ndef->getId("mapgen_jungletree"));
520 MapNode leavesnode(ndef->getId("mapgen_leaves"));
522 for(s16 x=-1; x<=1; x++)
523 for(s16 z=-1; z<=1; z++)
525 if(myrand_range(0, 2) == 0)
527 v3s16 p1 = p0 + v3s16(x,0,z);
528 v3s16 p2 = p0 + v3s16(x,-1,z);
529 if(vmanip.m_area.contains(p2)
530 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
531 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
532 else if(vmanip.m_area.contains(p1))
533 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
536 s16 trunk_h = myrand_range(8, 12);
538 for(s16 ii=0; ii<trunk_h; ii++)
540 if(vmanip.m_area.contains(p1))
541 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
545 // p1 is now the last piece of the trunk
548 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
549 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
550 Buffer<u8> leaves_d(leaves_a.getVolume());
551 for(s32 i=0; i<leaves_a.getVolume(); i++)
554 // Force leaves at near the end of the trunk
557 for(s16 z=-d; z<=d; z++)
558 for(s16 y=-d; y<=d; y++)
559 for(s16 x=-d; x<=d; x++)
561 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
565 // Add leaves randomly
566 for(u32 iii=0; iii<30; iii++)
571 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
572 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
573 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
576 for(s16 z=0; z<=d; z++)
577 for(s16 y=0; y<=d; y++)
578 for(s16 x=0; x<=d; x++)
580 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
584 // Blit leaves to vmanip
585 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
586 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
587 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
591 if(vmanip.m_area.contains(p) == false)
593 u32 vi = vmanip.m_area.index(p);
594 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
595 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
597 u32 i = leaves_a.index(x,y,z);
599 vmanip.m_data[vi] = leavesnode;
604 }; // namespace treegen