Line data Source code
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 0 : 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 0 : MapNode treenode(ndef->getId("mapgen_tree"));
42 0 : MapNode leavesnode(ndef->getId("mapgen_leaves"));
43 0 : MapNode applenode(ndef->getId("mapgen_apple"));
44 :
45 0 : PseudoRandom pr(seed);
46 0 : s16 trunk_h = pr.range(4, 5);
47 0 : v3s16 p1 = p0;
48 0 : for (s16 ii = 0; ii < trunk_h; ii++) {
49 0 : if (vmanip.m_area.contains(p1)) {
50 0 : u32 vi = vmanip.m_area.index(p1);
51 0 : vmanip.m_data[vi] = treenode;
52 : }
53 0 : p1.Y++;
54 : }
55 :
56 : // p1 is now the last piece of the trunk
57 0 : p1.Y -= 1;
58 :
59 0 : VoxelArea leaves_a(v3s16(-2, -1, -2), v3s16(2, 2, 2));
60 : //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
61 0 : Buffer<u8> leaves_d(leaves_a.getVolume());
62 0 : for (s32 i = 0; i < leaves_a.getVolume(); i++)
63 0 : leaves_d[i] = 0;
64 :
65 : // Force leaves at near the end of the trunk
66 0 : s16 d = 1;
67 0 : for (s16 z = -d; z <= d; z++)
68 0 : for (s16 y = -d; y <= d; y++)
69 0 : for (s16 x = -d; x <= d; x++) {
70 0 : leaves_d[leaves_a.index(v3s16(x, y, z))] = 1;
71 : }
72 :
73 : // Add leaves randomly
74 0 : for (u32 iii = 0; iii < 7; iii++) {
75 : v3s16 p(
76 0 : pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d),
77 0 : pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d),
78 0 : pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d)
79 0 : );
80 :
81 0 : for (s16 z = 0; z <= d; z++)
82 0 : for (s16 y = 0; y <= d; y++)
83 0 : for (s16 x = 0; x <= d; x++) {
84 0 : leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1;
85 : }
86 : }
87 :
88 : // Blit leaves to vmanip
89 0 : for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
90 0 : for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
91 0 : v3s16 pmin(leaves_a.MinEdge.X, y, z);
92 0 : u32 i = leaves_a.index(pmin);
93 0 : u32 vi = vmanip.m_area.index(pmin + p1);
94 0 : for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
95 0 : v3s16 p(x, y, z);
96 0 : if (vmanip.m_area.contains(p + p1) == true &&
97 0 : (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
98 0 : vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) {
99 0 : if (leaves_d[i] == 1) {
100 0 : bool is_apple = pr.range(0, 99) < 10;
101 0 : if (is_apple_tree && is_apple)
102 0 : vmanip.m_data[vi] = applenode;
103 : else
104 0 : vmanip.m_data[vi] = leavesnode;
105 : }
106 : }
107 0 : vi++;
108 0 : i++;
109 : }
110 : }
111 0 : }
112 :
113 :
114 : // L-System tree LUA spawner
115 0 : treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0,
116 : INodeDefManager *ndef, TreeDef tree_definition)
117 : {
118 0 : ServerMap *map = &env->getServerMap();
119 0 : std::map<v3s16, MapBlock*> modified_blocks;
120 0 : MMVManip vmanip(map);
121 0 : v3s16 tree_blockp = getNodeBlockPos(p0);
122 : treegen::error e;
123 :
124 0 : vmanip.initialEmerge(tree_blockp - v3s16(1, 1, 1), tree_blockp + v3s16(1, 3, 1));
125 0 : e = make_ltree(vmanip, p0, ndef, tree_definition);
126 0 : if (e != SUCCESS)
127 0 : return e;
128 :
129 0 : vmanip.blitBackAll(&modified_blocks);
130 :
131 : // update lighting
132 0 : std::map<v3s16, MapBlock*> lighting_modified_blocks;
133 0 : lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
134 0 : map->updateLighting(lighting_modified_blocks, modified_blocks);
135 : // Send a MEET_OTHER event
136 0 : MapEditEvent event;
137 0 : event.type = MEET_OTHER;
138 0 : for (std::map<v3s16, MapBlock*>::iterator
139 0 : i = modified_blocks.begin();
140 0 : i != modified_blocks.end(); ++i)
141 0 : event.modified_blocks.insert(i->first);
142 0 : map->dispatchEvent(&event);
143 0 : return SUCCESS;
144 : }
145 :
146 :
147 : //L-System tree generator
148 0 : treegen::error make_ltree(MMVManip &vmanip, v3s16 p0,
149 : INodeDefManager *ndef, TreeDef tree_definition)
150 : {
151 0 : MapNode dirtnode(ndef->getId("mapgen_dirt"));
152 : int seed;
153 0 : if (tree_definition.explicit_seed)
154 0 : seed = tree_definition.seed + 14002;
155 : else
156 0 : seed = p0.X * 2 + p0.Y * 4 + p0.Z; // use the tree position to seed PRNG
157 0 : PseudoRandom ps(seed);
158 :
159 : // chance of inserting abcd rules
160 0 : double prop_a = 9;
161 0 : double prop_b = 8;
162 0 : double prop_c = 7;
163 0 : double prop_d = 6;
164 :
165 : //randomize tree growth level, minimum=2
166 0 : s16 iterations = tree_definition.iterations;
167 0 : if (tree_definition.iterations_random_level > 0)
168 0 : iterations -= ps.range(0, tree_definition.iterations_random_level);
169 0 : if (iterations < 2)
170 0 : iterations = 2;
171 :
172 0 : s16 MAX_ANGLE_OFFSET = 5;
173 0 : double angle_in_radians = (double)tree_definition.angle * M_PI / 180;
174 0 : double angleOffset_in_radians = (s16)(ps.range(0, 1) % MAX_ANGLE_OFFSET) * M_PI / 180;
175 :
176 : //initialize rotation matrix, position and stacks for branches
177 0 : core::matrix4 rotation;
178 0 : rotation = setRotationAxisRadians(rotation, M_PI / 2, v3f(0, 0, 1));
179 0 : v3f position;
180 0 : position.X = p0.X;
181 0 : position.Y = p0.Y;
182 0 : position.Z = p0.Z;
183 0 : std::stack <core::matrix4> stack_orientation;
184 0 : std::stack <v3f> stack_position;
185 :
186 : //generate axiom
187 0 : std::string axiom = tree_definition.initial_axiom;
188 0 : for (s16 i = 0; i < iterations; i++) {
189 0 : std::string temp = "";
190 0 : for (s16 j = 0; j < (s16)axiom.size(); j++) {
191 0 : char axiom_char = axiom.at(j);
192 0 : switch (axiom_char) {
193 : case 'A':
194 0 : temp += tree_definition.rules_a;
195 0 : break;
196 : case 'B':
197 0 : temp += tree_definition.rules_b;
198 0 : break;
199 : case 'C':
200 0 : temp += tree_definition.rules_c;
201 0 : break;
202 : case 'D':
203 0 : temp += tree_definition.rules_d;
204 0 : break;
205 : case 'a':
206 0 : if (prop_a >= ps.range(1, 10))
207 0 : temp += tree_definition.rules_a;
208 0 : break;
209 : case 'b':
210 0 : if (prop_b >= ps.range(1, 10))
211 0 : temp += tree_definition.rules_b;
212 0 : break;
213 : case 'c':
214 0 : if (prop_c >= ps.range(1, 10))
215 0 : temp += tree_definition.rules_c;
216 0 : break;
217 : case 'd':
218 0 : if (prop_d >= ps.range(1, 10))
219 0 : temp += tree_definition.rules_d;
220 0 : break;
221 : default:
222 0 : temp += axiom_char;
223 0 : break;
224 : }
225 : }
226 0 : axiom = temp;
227 : }
228 :
229 : //make sure tree is not floating in the air
230 0 : if (tree_definition.trunk_type == "double") {
231 0 : tree_node_placement(
232 : vmanip,
233 0 : v3f(position.X + 1, position.Y - 1, position.Z),
234 : dirtnode
235 0 : );
236 0 : tree_node_placement(
237 : vmanip,
238 0 : v3f(position.X, position.Y - 1, position.Z + 1),
239 : dirtnode
240 0 : );
241 0 : tree_node_placement(
242 : vmanip,
243 0 : v3f(position.X + 1, position.Y - 1, position.Z + 1),
244 : dirtnode
245 0 : );
246 0 : } else if (tree_definition.trunk_type == "crossed") {
247 0 : tree_node_placement(
248 : vmanip,
249 0 : v3f(position.X + 1, position.Y - 1, position.Z),
250 : dirtnode
251 0 : );
252 0 : tree_node_placement(
253 : vmanip,
254 0 : v3f(position.X - 1, position.Y - 1, position.Z),
255 : dirtnode
256 0 : );
257 0 : tree_node_placement(
258 : vmanip,
259 0 : v3f(position.X, position.Y - 1, position.Z + 1),
260 : dirtnode
261 0 : );
262 0 : tree_node_placement(
263 : vmanip,
264 0 : v3f(position.X, position.Y - 1, position.Z - 1),
265 : dirtnode
266 0 : );
267 : }
268 :
269 : /* build tree out of generated axiom
270 :
271 : Key for Special L-System Symbols used in Axioms
272 :
273 : G - move forward one unit with the pen up
274 : F - move forward one unit with the pen down drawing trunks and branches
275 : f - move forward one unit with the pen down drawing leaves (100% chance)
276 : T - move forward one unit with the pen down drawing trunks only
277 : R - move forward one unit with the pen down placing fruit
278 : A - replace with rules set A
279 : B - replace with rules set B
280 : C - replace with rules set C
281 : D - replace with rules set D
282 : a - replace with rules set A, chance 90%
283 : b - replace with rules set B, chance 80%
284 : c - replace with rules set C, chance 70%
285 : d - replace with rules set D, chance 60%
286 : + - yaw the turtle right by angle degrees
287 : - - yaw the turtle left by angle degrees
288 : & - pitch the turtle down by angle degrees
289 : ^ - pitch the turtle up by angle degrees
290 : / - roll the turtle to the right by angle degrees
291 : * - roll the turtle to the left by angle degrees
292 : [ - save in stack current state info
293 : ] - recover from stack state info
294 :
295 : */
296 :
297 : s16 x,y,z;
298 0 : for (s16 i = 0; i < (s16)axiom.size(); i++) {
299 0 : char axiom_char = axiom.at(i);
300 0 : core::matrix4 temp_rotation;
301 0 : temp_rotation.makeIdentity();
302 0 : v3f dir;
303 0 : switch (axiom_char) {
304 : case 'G':
305 0 : dir = v3f(1, 0, 0);
306 0 : dir = transposeMatrix(rotation, dir);
307 0 : position += dir;
308 0 : break;
309 : case 'T':
310 0 : tree_trunk_placement(
311 : vmanip,
312 : v3f(position.X, position.Y, position.Z),
313 : tree_definition
314 0 : );
315 0 : if (tree_definition.trunk_type == "double" &&
316 0 : !tree_definition.thin_branches) {
317 0 : tree_trunk_placement(
318 : vmanip,
319 0 : v3f(position.X + 1, position.Y, position.Z),
320 : tree_definition
321 0 : );
322 0 : tree_trunk_placement(
323 : vmanip,
324 0 : v3f(position.X, position.Y, position.Z + 1),
325 : tree_definition
326 0 : );
327 0 : tree_trunk_placement(
328 : vmanip,
329 0 : v3f(position.X + 1, position.Y, position.Z + 1),
330 : tree_definition
331 0 : );
332 0 : } else if (tree_definition.trunk_type == "crossed" &&
333 0 : !tree_definition.thin_branches) {
334 0 : tree_trunk_placement(
335 : vmanip,
336 0 : v3f(position.X + 1, position.Y, position.Z),
337 : tree_definition
338 0 : );
339 0 : tree_trunk_placement(
340 : vmanip,
341 0 : v3f(position.X - 1, position.Y, position.Z),
342 : tree_definition
343 0 : );
344 0 : tree_trunk_placement(
345 : vmanip,
346 0 : v3f(position.X, position.Y, position.Z + 1),
347 : tree_definition
348 0 : );
349 0 : tree_trunk_placement(
350 : vmanip,
351 0 : v3f(position.X, position.Y, position.Z - 1),
352 : tree_definition
353 0 : );
354 : }
355 0 : dir = v3f(1, 0, 0);
356 0 : dir = transposeMatrix(rotation, dir);
357 0 : position += dir;
358 0 : break;
359 : case 'F':
360 0 : tree_trunk_placement(
361 : vmanip,
362 : v3f(position.X, position.Y, position.Z),
363 : tree_definition
364 0 : );
365 0 : if ((stack_orientation.empty() &&
366 0 : tree_definition.trunk_type == "double") ||
367 0 : (!stack_orientation.empty() &&
368 0 : tree_definition.trunk_type == "double" &&
369 0 : !tree_definition.thin_branches)) {
370 0 : tree_trunk_placement(
371 : vmanip,
372 0 : v3f(position.X +1 , position.Y, position.Z),
373 : tree_definition
374 0 : );
375 0 : tree_trunk_placement(
376 : vmanip,
377 0 : v3f(position.X, position.Y, position.Z + 1),
378 : tree_definition
379 0 : );
380 0 : tree_trunk_placement(
381 : vmanip,
382 0 : v3f(position.X + 1, position.Y, position.Z + 1),
383 : tree_definition
384 0 : );
385 0 : } else if ((stack_orientation.empty() &&
386 0 : tree_definition.trunk_type == "crossed") ||
387 0 : (!stack_orientation.empty() &&
388 0 : tree_definition.trunk_type == "crossed" &&
389 0 : !tree_definition.thin_branches)) {
390 0 : tree_trunk_placement(
391 : vmanip,
392 0 : v3f(position.X + 1, position.Y, position.Z),
393 : tree_definition
394 0 : );
395 0 : tree_trunk_placement(
396 : vmanip,
397 0 : v3f(position.X - 1, position.Y, position.Z),
398 : tree_definition
399 0 : );
400 0 : tree_trunk_placement(
401 : vmanip,
402 0 : v3f(position.X, position.Y, position.Z + 1),
403 : tree_definition
404 0 : );
405 0 : tree_trunk_placement(
406 : vmanip,
407 0 : v3f(position.X, position.Y, position.Z - 1),
408 : tree_definition
409 0 : );
410 0 : } if (stack_orientation.empty() == false) {
411 0 : s16 size = 1;
412 0 : for (x = -size; x <= size; x++)
413 0 : for (y = -size; y <= size; y++)
414 0 : for (z = -size; z <= size; z++) {
415 0 : if (abs(x) == size &&
416 0 : abs(y) == size &&
417 0 : abs(z) == size) {
418 0 : tree_leaves_placement(
419 : vmanip,
420 0 : v3f(position.X + x + 1, position.Y + y,
421 0 : position.Z + z),
422 : ps.next(),
423 : tree_definition
424 0 : );
425 0 : tree_leaves_placement(
426 : vmanip,
427 0 : v3f(position.X + x - 1, position.Y + y,
428 0 : position.Z + z),
429 : ps.next(),
430 : tree_definition
431 0 : );
432 0 : tree_leaves_placement(
433 0 : vmanip,v3f(position.X + x, position.Y + y,
434 0 : position.Z + z + 1),
435 : ps.next(),
436 : tree_definition
437 0 : );
438 0 : tree_leaves_placement(
439 0 : vmanip,v3f(position.X + x, position.Y + y,
440 0 : position.Z + z - 1),
441 : ps.next(),
442 : tree_definition
443 0 : );
444 : }
445 : }
446 : }
447 0 : dir = v3f(1, 0, 0);
448 0 : dir = transposeMatrix(rotation, dir);
449 0 : position += dir;
450 0 : break;
451 : case 'f':
452 0 : tree_single_leaves_placement(
453 : vmanip,
454 : v3f(position.X, position.Y, position.Z),
455 : ps.next(),
456 : tree_definition
457 0 : );
458 0 : dir = v3f(1, 0, 0);
459 0 : dir = transposeMatrix(rotation, dir);
460 0 : position += dir;
461 0 : break;
462 : case 'R':
463 0 : tree_fruit_placement(
464 : vmanip,
465 : v3f(position.X, position.Y, position.Z),
466 : tree_definition
467 0 : );
468 0 : dir = v3f(1, 0, 0);
469 0 : dir = transposeMatrix(rotation, dir);
470 0 : position += dir;
471 0 : break;
472 :
473 : // turtle orientation commands
474 : case '[':
475 0 : stack_orientation.push(rotation);
476 0 : stack_position.push(position);
477 0 : break;
478 : case ']':
479 0 : if (stack_orientation.empty())
480 0 : return UNBALANCED_BRACKETS;
481 0 : rotation = stack_orientation.top();
482 0 : stack_orientation.pop();
483 0 : position = stack_position.top();
484 0 : stack_position.pop();
485 0 : break;
486 : case '+':
487 0 : temp_rotation.makeIdentity();
488 0 : temp_rotation = setRotationAxisRadians(temp_rotation,
489 0 : angle_in_radians + angleOffset_in_radians, v3f(0, 0, 1));
490 0 : rotation *= temp_rotation;
491 0 : break;
492 : case '-':
493 0 : temp_rotation.makeIdentity();
494 0 : temp_rotation = setRotationAxisRadians(temp_rotation,
495 0 : angle_in_radians + angleOffset_in_radians, v3f(0, 0, -1));
496 0 : rotation *= temp_rotation;
497 0 : break;
498 : case '&':
499 0 : temp_rotation.makeIdentity();
500 0 : temp_rotation = setRotationAxisRadians(temp_rotation,
501 0 : angle_in_radians + angleOffset_in_radians, v3f(0, 1, 0));
502 0 : rotation *= temp_rotation;
503 0 : break;
504 : case '^':
505 0 : temp_rotation.makeIdentity();
506 0 : temp_rotation = setRotationAxisRadians(temp_rotation,
507 0 : angle_in_radians + angleOffset_in_radians, v3f(0, -1, 0));
508 0 : rotation *= temp_rotation;
509 0 : break;
510 : case '*':
511 0 : temp_rotation.makeIdentity();
512 0 : temp_rotation = setRotationAxisRadians(temp_rotation,
513 0 : angle_in_radians, v3f(1, 0, 0));
514 0 : rotation *= temp_rotation;
515 0 : break;
516 : case '/':
517 0 : temp_rotation.makeIdentity();
518 0 : temp_rotation = setRotationAxisRadians(temp_rotation,
519 0 : angle_in_radians, v3f(-1, 0, 0));
520 0 : rotation *= temp_rotation;
521 0 : break;
522 : default:
523 0 : break;
524 : }
525 : }
526 :
527 0 : return SUCCESS;
528 : }
529 :
530 :
531 0 : void tree_node_placement(MMVManip &vmanip, v3f p0, MapNode node)
532 : {
533 0 : v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
534 0 : if (vmanip.m_area.contains(p1) == false)
535 0 : return;
536 0 : u32 vi = vmanip.m_area.index(p1);
537 0 : if (vmanip.m_data[vi].getContent() != CONTENT_AIR
538 0 : && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
539 0 : return;
540 0 : vmanip.m_data[vmanip.m_area.index(p1)] = node;
541 : }
542 :
543 :
544 0 : void tree_trunk_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition)
545 : {
546 0 : v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
547 0 : if (vmanip.m_area.contains(p1) == false)
548 0 : return;
549 0 : u32 vi = vmanip.m_area.index(p1);
550 0 : if (vmanip.m_data[vi].getContent() != CONTENT_AIR
551 0 : && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
552 0 : return;
553 0 : vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.trunknode;
554 : }
555 :
556 :
557 0 : void tree_leaves_placement(MMVManip &vmanip, v3f p0,
558 : PseudoRandom ps, TreeDef &tree_definition)
559 : {
560 0 : MapNode leavesnode = tree_definition.leavesnode;
561 0 : if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance)
562 0 : leavesnode = tree_definition.leaves2node;
563 0 : v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
564 0 : if (vmanip.m_area.contains(p1) == false)
565 0 : return;
566 0 : u32 vi = vmanip.m_area.index(p1);
567 0 : if (vmanip.m_data[vi].getContent() != CONTENT_AIR
568 0 : && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
569 0 : return;
570 0 : if (tree_definition.fruit_chance > 0) {
571 0 : if (ps.range(1, 100) > 100 - tree_definition.fruit_chance)
572 0 : vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
573 : else
574 0 : vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
575 0 : } else if (ps.range(1, 100) > 20) {
576 0 : vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
577 : }
578 : }
579 :
580 :
581 0 : void tree_single_leaves_placement(MMVManip &vmanip, v3f p0,
582 : PseudoRandom ps, TreeDef &tree_definition)
583 : {
584 0 : MapNode leavesnode = tree_definition.leavesnode;
585 0 : if (ps.range(1, 100) > 100 - tree_definition.leaves2_chance)
586 0 : leavesnode = tree_definition.leaves2node;
587 0 : v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
588 0 : if (vmanip.m_area.contains(p1) == false)
589 0 : return;
590 0 : u32 vi = vmanip.m_area.index(p1);
591 0 : if (vmanip.m_data[vi].getContent() != CONTENT_AIR
592 0 : && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
593 0 : return;
594 0 : vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
595 : }
596 :
597 :
598 0 : void tree_fruit_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition)
599 : {
600 0 : v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z));
601 0 : if (vmanip.m_area.contains(p1) == false)
602 0 : return;
603 0 : u32 vi = vmanip.m_area.index(p1);
604 0 : if (vmanip.m_data[vi].getContent() != CONTENT_AIR
605 0 : && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
606 0 : return;
607 0 : vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
608 : }
609 :
610 :
611 0 : irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis)
612 : {
613 0 : double c = cos(angle);
614 0 : double s = sin(angle);
615 0 : double t = 1.0 - c;
616 :
617 0 : double tx = t * axis.X;
618 0 : double ty = t * axis.Y;
619 0 : double tz = t * axis.Z;
620 0 : double sx = s * axis.X;
621 0 : double sy = s * axis.Y;
622 0 : double sz = s * axis.Z;
623 :
624 0 : M[0] = tx * axis.X + c;
625 0 : M[1] = tx * axis.Y + sz;
626 0 : M[2] = tx * axis.Z - sy;
627 :
628 0 : M[4] = ty * axis.X - sz;
629 0 : M[5] = ty * axis.Y + c;
630 0 : M[6] = ty * axis.Z + sx;
631 :
632 0 : M[8] = tz * axis.X + sy;
633 0 : M[9] = tz * axis.Y - sx;
634 0 : M[10] = tz * axis.Z + c;
635 0 : return M;
636 : }
637 :
638 :
639 0 : v3f transposeMatrix(irr::core::matrix4 M, v3f v)
640 : {
641 0 : v3f translated;
642 0 : double x = M[0] * v.X + M[4] * v.Y + M[8] * v.Z +M[12];
643 0 : double y = M[1] * v.X + M[5] * v.Y + M[9] * v.Z +M[13];
644 0 : double z = M[2] * v.X + M[6] * v.Y + M[10] * v.Z +M[14];
645 0 : translated.X = x;
646 0 : translated.Y = y;
647 0 : translated.Z = z;
648 0 : return translated;
649 : }
650 :
651 :
652 0 : void make_jungletree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, int seed)
653 : {
654 : /*
655 : NOTE: Tree-placing code is currently duplicated in the engine
656 : and in games that have saplings; both are deprecated but not
657 : replaced yet
658 : */
659 0 : MapNode treenode(ndef->getId("mapgen_jungletree"));
660 0 : MapNode leavesnode(ndef->getId("mapgen_jungleleaves"));
661 :
662 0 : PseudoRandom pr(seed);
663 0 : for (s16 x= -1; x <= 1; x++)
664 0 : for (s16 z= -1; z <= 1; z++) {
665 0 : if (pr.range(0, 2) == 0)
666 0 : continue;
667 0 : v3s16 p1 = p0 + v3s16(x, 0, z);
668 0 : v3s16 p2 = p0 + v3s16(x, -1, z);
669 0 : u32 vi1 = vmanip.m_area.index(p1);
670 0 : u32 vi2 = vmanip.m_area.index(p2);
671 :
672 0 : if (vmanip.m_area.contains(p2) &&
673 0 : vmanip.m_data[vi2].getContent() == CONTENT_AIR)
674 0 : vmanip.m_data[vi2] = treenode;
675 0 : else if (vmanip.m_area.contains(p1) &&
676 0 : vmanip.m_data[vi1].getContent() == CONTENT_AIR)
677 0 : vmanip.m_data[vi1] = treenode;
678 : }
679 0 : vmanip.m_data[vmanip.m_area.index(p0)] = treenode;
680 :
681 0 : s16 trunk_h = pr.range(8, 12);
682 0 : v3s16 p1 = p0;
683 0 : for (s16 ii = 0; ii < trunk_h; ii++) {
684 0 : if (vmanip.m_area.contains(p1)) {
685 0 : u32 vi = vmanip.m_area.index(p1);
686 0 : vmanip.m_data[vi] = treenode;
687 : }
688 0 : p1.Y++;
689 : }
690 :
691 : // p1 is now the last piece of the trunk
692 0 : p1.Y -= 1;
693 :
694 0 : VoxelArea leaves_a(v3s16(-3, -2, -3), v3s16(3, 2, 3));
695 : //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
696 0 : Buffer<u8> leaves_d(leaves_a.getVolume());
697 0 : for (s32 i = 0; i < leaves_a.getVolume(); i++)
698 0 : leaves_d[i] = 0;
699 :
700 : // Force leaves at near the end of the trunk
701 0 : s16 d = 1;
702 0 : for (s16 z = -d; z <= d; z++)
703 0 : for (s16 y = -d; y <= d; y++)
704 0 : for (s16 x = -d; x <= d; x++) {
705 0 : leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
706 : }
707 :
708 : // Add leaves randomly
709 0 : for (u32 iii = 0; iii < 30; iii++) {
710 : v3s16 p(
711 0 : pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X - d),
712 0 : pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y - d),
713 0 : pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z - d)
714 0 : );
715 :
716 0 : for (s16 z = 0; z <= d; z++)
717 0 : for (s16 y = 0; y <= d; y++)
718 0 : for (s16 x = 0; x <= d; x++) {
719 0 : leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1;
720 : }
721 : }
722 :
723 : // Blit leaves to vmanip
724 0 : for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
725 0 : for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
726 0 : v3s16 pmin(leaves_a.MinEdge.X, y, z);
727 0 : u32 i = leaves_a.index(pmin);
728 0 : u32 vi = vmanip.m_area.index(pmin + p1);
729 0 : for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
730 0 : v3s16 p(x, y, z);
731 0 : if (vmanip.m_area.contains(p + p1) == true &&
732 0 : (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
733 0 : vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) {
734 0 : if (leaves_d[i] == 1)
735 0 : vmanip.m_data[vi] = leavesnode;
736 : }
737 0 : vi++;
738 0 : i++;
739 : }
740 : }
741 0 : }
742 :
743 :
744 0 : void make_pine_tree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, int seed)
745 : {
746 : /*
747 : NOTE: Tree-placing code is currently duplicated in the engine
748 : and in games that have saplings; both are deprecated but not
749 : replaced yet
750 : */
751 0 : MapNode treenode(ndef->getId("mapgen_pinetree"));
752 0 : MapNode leavesnode(ndef->getId("mapgen_pine_needles"));
753 0 : MapNode snownode(ndef->getId("mapgen_snow"));
754 :
755 0 : PseudoRandom pr(seed);
756 0 : s16 trunk_h = pr.range(9, 13);
757 0 : v3s16 p1 = p0;
758 0 : for (s16 ii = 0; ii < trunk_h; ii++) {
759 0 : if (vmanip.m_area.contains(p1)) {
760 0 : u32 vi = vmanip.m_area.index(p1);
761 0 : vmanip.m_data[vi] = treenode;
762 : }
763 0 : p1.Y++;
764 : }
765 :
766 : // Make p1 the top node of the trunk
767 0 : p1.Y -= 1;
768 :
769 0 : VoxelArea leaves_a(v3s16(-3, -6, -3), v3s16(3, 3, 3));
770 : //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
771 0 : Buffer<u8> leaves_d(leaves_a.getVolume());
772 0 : for (s32 i = 0; i < leaves_a.getVolume(); i++)
773 0 : leaves_d[i] = 0;
774 :
775 : // Upper branches
776 0 : s16 dev = 3;
777 0 : for (s16 yy = -1; yy <= 1; yy++) {
778 0 : for (s16 zz = -dev; zz <= dev; zz++) {
779 0 : u32 i = leaves_a.index(v3s16(-dev, yy, zz));
780 0 : u32 ia = leaves_a.index(v3s16(-dev, yy+1, zz));
781 0 : for (s16 xx = -dev; xx <= dev; xx++) {
782 0 : if (pr.range(0, 20) <= 19 - dev) {
783 0 : leaves_d[i] = 1;
784 0 : leaves_d[ia] = 2;
785 : }
786 0 : i++;
787 0 : ia++;
788 : }
789 : }
790 0 : dev--;
791 : }
792 :
793 : // Centre top nodes
794 0 : u32 i = leaves_a.index(v3s16(0, 1, 0));
795 0 : leaves_d[i] = 1;
796 0 : i = leaves_a.index(v3s16(0, 2, 0));
797 0 : leaves_d[i] = 1;
798 0 : i = leaves_a.index(v3s16(0, 3, 0));
799 0 : leaves_d[i] = 2;
800 :
801 : // Lower branches
802 0 : s16 my = -6;
803 0 : for (u32 iii = 0; iii < 20; iii++) {
804 0 : s16 xi = pr.range(-3, 2);
805 0 : s16 yy = pr.range(-6, -5);
806 0 : s16 zi = pr.range(-3, 2);
807 0 : if (yy > my)
808 0 : my = yy;
809 0 : for (s16 zz = zi; zz <= zi + 1; zz++) {
810 0 : u32 i = leaves_a.index(v3s16(xi, yy, zz));
811 0 : u32 ia = leaves_a.index(v3s16(xi, yy + 1, zz));
812 0 : for (s16 xx = xi; xx <= xi + 1; xx++) {
813 0 : leaves_d[i] = 1;
814 0 : if (leaves_d[ia] == 0)
815 0 : leaves_d[ia] = 2;
816 0 : i++;
817 0 : ia++;
818 : }
819 : }
820 : }
821 :
822 0 : dev = 2;
823 0 : for (s16 yy = my + 1; yy <= my + 2; yy++) {
824 0 : for (s16 zz = -dev; zz <= dev; zz++) {
825 0 : u32 i = leaves_a.index(v3s16(-dev, yy, zz));
826 0 : u32 ia = leaves_a.index(v3s16(-dev, yy + 1, zz));
827 0 : for (s16 xx = -dev; xx <= dev; xx++) {
828 0 : if (pr.range(0, 20) <= 19 - dev) {
829 0 : leaves_d[i] = 1;
830 0 : leaves_d[ia] = 2;
831 : }
832 0 : i++;
833 0 : ia++;
834 : }
835 : }
836 0 : dev--;
837 : }
838 :
839 : // Blit leaves to vmanip
840 0 : for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++)
841 0 : for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) {
842 0 : v3s16 pmin(leaves_a.MinEdge.X, y, z);
843 0 : u32 i = leaves_a.index(pmin);
844 0 : u32 vi = vmanip.m_area.index(pmin + p1);
845 0 : for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) {
846 0 : v3s16 p(x, y, z);
847 0 : if (vmanip.m_area.contains(p + p1) == true &&
848 0 : (vmanip.m_data[vi].getContent() == CONTENT_AIR ||
849 0 : vmanip.m_data[vi].getContent() == CONTENT_IGNORE ||
850 0 : vmanip.m_data[vi] == snownode)) {
851 0 : if (leaves_d[i] == 1)
852 0 : vmanip.m_data[vi] = leavesnode;
853 0 : else if (leaves_d[i] == 2)
854 0 : vmanip.m_data[vi] = snownode;
855 : }
856 0 : vi++;
857 0 : i++;
858 : }
859 : }
860 0 : }
861 :
862 3 : }; // namespace treegen
|