aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/lua_api.txt54
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/content_abm.cpp4
-rw-r--r--src/mapgen.cpp170
-rw-r--r--src/mapgen.h4
-rw-r--r--src/scriptapi.cpp41
-rw-r--r--src/treegen.cpp518
-rw-r--r--src/treegen.h71
8 files changed, 689 insertions, 174 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index a9944935f..117d4b24e 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -1063,6 +1063,60 @@ methods:
^ Return world-specific perlin noise (int(worldseed)+seeddiff)
- clear_objects()
^ clear all objects in the environments
+- spawn_tree (pos, {treedef})
+ ^ spawns L-System tree at given pos with definition in treedef table
+ treedef={
+ axiom, - string initial tree axiom
+ rules_a, - string rules set A
+ rules_b, - string rules set B
+ rules_c, - string rules set C
+ rules_d, - string rules set D
+ trunk, - string trunk node name
+ leaves, - string leaves node name
+ angle, - num angle in deg
+ iterations, - num max # of iterations, usually 2 -5
+ random_level, - num factor to lower nr of iterations, usually 0 - 3
+ thin_trunks, - boolean true -> use thin trunks
+ fruit_tree, - boolean true -> is a fruit tree
+ fruit - string fruit node name
+ }
+
+ Key for Special L-System Symbols used in Axioms
+ G - move forward one unit with the pin down
+ F - move forward one unit with the pin up
+ A - replace with rules set A
+ B - replace with rules set B
+ C - replace with rules set C
+ D - replace with rules set D
+ a - replace with rules set A, chance 90%
+ b - replace with rules set B, chance 80%
+ c - replace with rules set C, chance 70%
+ d - replace with rules set D, chance 60%
+ + - yaw the turtle right by angle parameter
+ - - yaw the turtle left by angle parameter
+ & - pitch the turtle down by angle parameter
+ ^ - pitch the turtle up by angle parameter
+ / - roll the turtle to the right by angle parameter
+ * - roll the turtle to the left by angle parameter
+ [ - save in stack current state info
+ ] - recover from stack state info
+
+ Example usage: spawn small apple tree
+ apple_tree={
+ axiom="FFFFFAFFBF",
+ rules_a="[&&&FFFFF&&FFFF][&&&++++FFFFF&&FFFF][&&&----FFFFF&&FFFF]",
+ rules_b="[&&&++FFFFF&&FFFF][&&&--FFFFF&&FFFF][&&&------FFFFF&&FFFF]",
+ trunk="default:tree",
+ leaves="default:leaves",
+ angle=30,
+ iterations=2,
+ random_level=0,
+ thin_trunks=true,
+ fruit_tree=true,
+ fruit="default:apple"
+ }
+ minetest.env:spawn_tree(pos,apple_tree)
+
Deprecated:
- add_rat(pos): Add C++ rat object (no-op)
- add_firefly(pos): Add C++ firefly object (no-op)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 107f580ce..5e1bfd65d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -188,6 +188,7 @@ set(common_SRCS
log.cpp
content_sao.cpp
mapgen.cpp
+ treegen.cpp
content_nodemeta.cpp
content_mapnode.cpp
collision.cpp
diff --git a/src/content_abm.cpp b/src/content_abm.cpp
index 12dbeea8e..0d0f0dedb 100644
--- a/src/content_abm.cpp
+++ b/src/content_abm.cpp
@@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_sao.h"
#include "settings.h"
#include "mapblock.h" // For getNodeBlockPos
-#include "mapgen.h" // For mapgen::make_tree
+#include "treegen.h" // For treegen::make_tree
#include "map.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@@ -118,7 +118,7 @@ public:
v3s16 tree_blockp = getNodeBlockPos(tree_p);
vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,1,1));
bool is_apple_tree = myrand()%4 == 0;
- mapgen::make_tree(vmanip, tree_p, is_apple_tree, ndef);
+ treegen::make_tree(vmanip, tree_p, is_apple_tree, ndef);
vmanip.blitBackAll(&modified_blocks);
// update lighting
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index 782f00b62..ae0c551cb 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "voxelalgorithms.h"
#include "profiler.h"
#include "main.h" // For g_profiler
+#include "treegen.h"
namespace mapgen
{
@@ -120,174 +121,7 @@ static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
}
#endif
-void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
- bool is_apple_tree, INodeDefManager *ndef)
-{
- MapNode treenode(ndef->getId("mapgen_tree"));
- MapNode leavesnode(ndef->getId("mapgen_leaves"));
- MapNode applenode(ndef->getId("mapgen_apple"));
-
- s16 trunk_h = myrand_range(4, 5);
- v3s16 p1 = p0;
- for(s16 ii=0; ii<trunk_h; ii++)
- {
- if(vmanip.m_area.contains(p1))
- if(ii == 0 || vmanip.getNodeNoExNoEmerge(p1).getContent() == CONTENT_AIR)
- vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
- p1.Y++;
- }
-
- // p1 is now the last piece of the trunk
- p1.Y -= 1;
-
- VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
- //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
- Buffer<u8> leaves_d(leaves_a.getVolume());
- for(s32 i=0; i<leaves_a.getVolume(); i++)
- leaves_d[i] = 0;
-
- // Force leaves at near the end of the trunk
- {
- s16 d = 1;
- for(s16 z=-d; z<=d; z++)
- for(s16 y=-d; y<=d; y++)
- for(s16 x=-d; x<=d; x++)
- {
- leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
- }
- }
-
- // Add leaves randomly
- for(u32 iii=0; iii<7; iii++)
- {
- s16 d = 1;
-
- v3s16 p(
- myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
- myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
- myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
- );
-
- for(s16 z=0; z<=d; z++)
- for(s16 y=0; y<=d; y++)
- for(s16 x=0; x<=d; x++)
- {
- leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
- }
- }
-
- // Blit leaves to vmanip
- for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
- for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
- for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
- {
- v3s16 p(x,y,z);
- p += p1;
- if(vmanip.m_area.contains(p) == false)
- continue;
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() != CONTENT_AIR
- && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
- continue;
- u32 i = leaves_a.index(x,y,z);
- if(leaves_d[i] == 1) {
- bool is_apple = myrand_range(0,99) < 10;
- if(is_apple_tree && is_apple) {
- vmanip.m_data[vi] = applenode;
- } else {
- vmanip.m_data[vi] = leavesnode;
- }
- }
- }
-}
-
#if 0
-static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
- INodeDefManager *ndef)
-{
- MapNode treenode(ndef->getId("mapgen_jungletree"));
- MapNode leavesnode(ndef->getId("mapgen_leaves"));
-
- for(s16 x=-1; x<=1; x++)
- for(s16 z=-1; z<=1; z++)
- {
- if(myrand_range(0, 2) == 0)
- continue;
- v3s16 p1 = p0 + v3s16(x,0,z);
- v3s16 p2 = p0 + v3s16(x,-1,z);
- if(vmanip.m_area.contains(p2)
- && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
- vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
- else if(vmanip.m_area.contains(p1))
- vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
- }
-
- s16 trunk_h = myrand_range(8, 12);
- v3s16 p1 = p0;
- for(s16 ii=0; ii<trunk_h; ii++)
- {
- if(vmanip.m_area.contains(p1))
- vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
- p1.Y++;
- }
-
- // p1 is now the last piece of the trunk
- p1.Y -= 1;
-
- VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
- //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
- Buffer<u8> leaves_d(leaves_a.getVolume());
- for(s32 i=0; i<leaves_a.getVolume(); i++)
- leaves_d[i] = 0;
-
- // Force leaves at near the end of the trunk
- {
- s16 d = 1;
- for(s16 z=-d; z<=d; z++)
- for(s16 y=-d; y<=d; y++)
- for(s16 x=-d; x<=d; x++)
- {
- leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
- }
- }
-
- // Add leaves randomly
- for(u32 iii=0; iii<30; iii++)
- {
- s16 d = 1;
-
- v3s16 p(
- myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
- myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
- myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
- );
-
- for(s16 z=0; z<=d; z++)
- for(s16 y=0; y<=d; y++)
- for(s16 x=0; x<=d; x++)
- {
- leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
- }
- }
-
- // Blit leaves to vmanip
- for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
- for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
- for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
- {
- v3s16 p(x,y,z);
- p += p1;
- if(vmanip.m_area.contains(p) == false)
- continue;
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() != CONTENT_AIR
- && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
- continue;
- u32 i = leaves_a.index(x,y,z);
- if(leaves_d[i] == 1)
- vmanip.m_data[vi] = leavesnode;
- }
-}
static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
INodeDefManager *ndef)
@@ -2239,7 +2073,7 @@ void make_block(BlockMakeData *data)
}
p.Y++;
// Make a tree
- make_tree(vmanip, p, false, ndef);
+ treegen::make_tree(vmanip, p, false, ndef);
}
}
}
diff --git a/src/mapgen.h b/src/mapgen.h
index e2f20ecaf..8986ddab0 100644
--- a/src/mapgen.h
+++ b/src/mapgen.h
@@ -42,10 +42,6 @@ namespace mapgen
// Main map generation routine
void make_block(BlockMakeData *data);
- // Add a tree
- void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
- bool is_apple_tree, INodeDefManager *ndef);
-
/*
These are used by FarMesh
*/
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index e26e880a9..d086b7e51 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -48,6 +48,7 @@ extern "C" {
#include "noise.h" // PseudoRandom for LuaPseudoRandom
#include "util/pointedthing.h"
#include "rollback.h"
+#include "treegen.h"
static void stackDump(lua_State *L, std::ostream &o)
{
@@ -4004,6 +4005,45 @@ private:
return 0;
}
+ static int l_spawn_tree(lua_State *L)
+ {
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ v3s16 p0 = read_v3s16(L, 2);
+
+ treegen::TreeDef tree_def;
+ std::string trunk,leaves,fruit;
+ INodeDefManager *ndef = env->getGameDef()->ndef();
+
+ if(lua_istable(L, 3))
+ {
+ getstringfield(L, 3, "axiom", tree_def.initial_axiom);
+ getstringfield(L, 3, "rules_a", tree_def.rules_a);
+ getstringfield(L, 3, "rules_b", tree_def.rules_b);
+ getstringfield(L, 3, "rules_c", tree_def.rules_a);
+ getstringfield(L, 3, "rules_d", tree_def.rules_b);
+ getstringfield(L, 3, "trunk", trunk);
+ tree_def.trunknode=ndef->getId(trunk);
+ getstringfield(L, 3, "leaves", leaves);
+ tree_def.leavesnode=ndef->getId(leaves);
+ getintfield(L, 3, "angle", tree_def.angle);
+ getintfield(L, 3, "iterations", tree_def.iterations);
+ getintfield(L, 3, "random_level", tree_def.iterations_random_level);
+ getboolfield(L, 3, "thin_trunks", tree_def.thin_trunks);
+ getboolfield(L, 3, "fruit_tree", tree_def.fruit_tree);
+ if (tree_def.fruit_tree)
+ {
+ getstringfield(L, 3, "fruit", fruit);
+ tree_def.fruitnode=ndef->getId(fruit);
+ }
+ }
+ else
+ return 0;
+ treegen::spawn_ltree (env, p0, ndef, tree_def);
+ return 1;
+ }
+
public:
EnvRef(ServerEnvironment *env):
m_env(env)
@@ -4086,6 +4126,7 @@ const luaL_reg EnvRef::methods[] = {
method(EnvRef, find_nodes_in_area),
method(EnvRef, get_perlin),
method(EnvRef, clear_objects),
+ method(EnvRef, spawn_tree),
{0,0}
};
diff --git a/src/treegen.cpp b/src/treegen.cpp
new file mode 100644
index 000000000..3354f97a2
--- /dev/null
+++ b/src/treegen.cpp
@@ -0,0 +1,518 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>,
+ 2012 RealBadAngel, Maciej Kasatkin <mk@realbadangel.pl>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <irr_v3d.h>
+#include <stack>
+#include "noise.h"
+#include "map.h"
+#include "environment.h"
+#include "nodedef.h"
+#include "treegen.h"
+
+namespace treegen
+{
+
+void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
+ bool is_apple_tree, INodeDefManager *ndef)
+{
+ MapNode treenode(ndef->getId("mapgen_tree"));
+ MapNode leavesnode(ndef->getId("mapgen_leaves"));
+ MapNode applenode(ndef->getId("mapgen_apple"));
+
+ s16 trunk_h = myrand_range(4, 5);
+ v3s16 p1 = p0;
+ for(s16 ii=0; ii<trunk_h; ii++)
+ {
+ if(vmanip.m_area.contains(p1))
+ if(ii == 0 || vmanip.getNodeNoExNoEmerge(p1).getContent() == CONTENT_AIR)
+ vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
+ p1.Y++;
+ }
+
+ // p1 is now the last piece of the trunk
+ p1.Y -= 1;
+
+ VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
+ //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
+ Buffer<u8> leaves_d(leaves_a.getVolume());
+ for(s32 i=0; i<leaves_a.getVolume(); i++)
+ leaves_d[i] = 0;
+
+ // Force leaves at near the end of the trunk
+ {
+ s16 d = 1;
+ for(s16 z=-d; z<=d; z++)
+ for(s16 y=-d; y<=d; y++)
+ for(s16 x=-d; x<=d; x++)
+ {
+ leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
+ }
+ }
+
+ // Add leaves randomly
+ for(u32 iii=0; iii<7; iii++)
+ {
+ s16 d = 1;
+
+ v3s16 p(
+ myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
+ myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
+ myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
+ );
+
+ for(s16 z=0; z<=d; z++)
+ for(s16 y=0; y<=d; y++)
+ for(s16 x=0; x<=d; x++)
+ {
+ leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
+ }
+ }
+
+ // Blit leaves to vmanip
+ for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
+ for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
+ for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
+ {
+ v3s16 p(x,y,z);
+ p += p1;
+ if(vmanip.m_area.contains(p) == false)
+ continue;
+ u32 vi = vmanip.m_area.index(p);
+ if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+ && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
+ continue;
+ u32 i = leaves_a.index(x,y,z);
+ if(leaves_d[i] == 1) {
+ bool is_apple = myrand_range(0,99) < 10;
+ if(is_apple_tree && is_apple) {
+ vmanip.m_data[vi] = applenode;
+ } else {
+ vmanip.m_data[vi] = leavesnode;
+ }
+ }
+ }
+}
+
+// L-System tree LUA spawner
+void spawn_ltree (ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition)
+{
+ ServerMap *map = &env->getServerMap();
+ core::map<v3s16, MapBlock*> modified_blocks;
+ ManualMapVoxelManipulator vmanip(map);
+ v3s16 tree_blockp = getNodeBlockPos(p0);
+ vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,1,1));
+ make_ltree (vmanip, p0, ndef, tree_definition);
+ vmanip.blitBackAll(&modified_blocks);
+
+ // update lighting
+ core::map<v3s16, MapBlock*> lighting_modified_blocks;
+ for(core::map<v3s16, MapBlock*>::Iterator
+ i = modified_blocks.getIterator();
+ i.atEnd() == false; i++)
+ {
+ lighting_modified_blocks.insert(i.getNode()->getKey(), i.getNode()->getValue());
+ }
+ map->updateLighting(lighting_modified_blocks, modified_blocks);
+ // Send a MEET_OTHER event
+ MapEditEvent event;
+ event.type = MEET_OTHER;
+ for(core::map<v3s16, MapBlock*>::Iterator
+ i = modified_blocks.getIterator();
+ i.atEnd() == false; i++)
+ {
+ v3s16 p = i.getNode()->getKey();
+ event.modified_blocks.insert(p, true);
+ }
+ map->dispatchEvent(&event);
+}
+
+//L-System tree generator
+void make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *ndef,
+ TreeDef tree_definition)
+{
+ MapNode dirtnode(ndef->getId("mapgen_dirt"));
+
+ // chance of inserting abcd rules
+ double prop_a = 9;
+ double prop_b = 8;
+ double prop_c = 7;
+ double prop_d = 6;
+
+ //randomize tree growth level, minimum=2
+ s16 iterations = tree_definition.iterations;
+ if (tree_definition.iterations_random_level>0)
+ iterations -= myrand_range(0,tree_definition.iterations_random_level);
+ if (iterations<2)
+ iterations=2;
+
+ s16 MAX_ANGLE_OFFSET = 5;
+ double angle_in_radians = (double)tree_definition.angle*M_PI/180;
+ double angleOffset_in_radians = (s16)(myrand_range(0,1)%MAX_ANGLE_OFFSET)*M_PI/180;
+
+ //initialize rotation matrix, position and stacks for branches
+ core::matrix4 rotation;
+ rotation=setRotationAxisRadians(rotation, M_PI/2,v3f(0,0,1));
+ v3f position = v3f(0,0,0);
+ std::stack <core::matrix4> stack_orientation;
+ std::stack <v3f> stack_position;
+
+ //generate axiom
+ std::string axiom = tree_definition.initial_axiom;
+ for(s16 i=0; i<iterations; i++)
+ {
+ std::string temp = "";
+ for(s16 j=0; j<(s16)axiom.size(); j++)
+ {
+ char axiom_char = axiom.at(j);
+ switch (axiom_char)
+ {
+ case 'A':
+ temp+=tree_definition.rules_a;
+ break;
+ case 'B':
+ temp+=tree_definition.rules_b;
+ break;
+ case 'C':
+ temp+=tree_definition.rules_c;
+ break;
+ case 'D':
+ temp+=tree_definition.rules_d;
+ break;
+ case 'a':
+ if (prop_a >= myrand_range(1,10))
+ temp+=tree_definition.rules_a;
+ break;
+ case 'b':
+ if (prop_b >= myrand_range(1,10))
+ temp+=tree_definition.rules_b;
+ break;
+ case 'c':
+ if (prop_c >= myrand_range(1,10))
+ temp+=tree_definition.rules_c;
+ break;
+ case 'd':
+ if (prop_d >= myrand_range(1,10))
+ temp+=tree_definition.rules_d;
+ break;
+ default:
+ temp+=axiom_char;
+ break;
+ }
+ }
+ axiom=temp;
+ }
+
+ //make sure tree is not floating in the air
+ if (tree_definition.thin_trunks == false)
+ {
+ make_tree_node_placement(vmanip,v3f(p0.X+position.X+1,p0.Y+position.Y-1,p0.Z+position.Z),dirtnode);
+ make_tree_node_placement(vmanip,v3f(p0.X+position.X-1,p0.Y+position.Y-1,p0.Z+position.Z),dirtnode);
+ make_tree_node_placement(vmanip,v3f(p0.X+position.X,p0.Y+position.Y-1,p0.Z+position.Z+1),dirtnode);
+ make_tree_node_placement(vmanip,v3f(p0.X+position.X,p0.Y+position.Y-1,p0.Z+position.Z-1),dirtnode);
+ }
+
+ /* build tree out of generated axiom
+
+ Key for Special L-System Symbols used in Axioms
+
+ G - move forward one unit with the pin down
+ F - move forward one unit with the pin up
+ A - replace with rules set A
+ B - replace with rules set B
+ C - replace with rules set C
+ D - replace with rules set D
+ a - replace with rules set A, chance 90%
+ b - replace with rules set B, chance 80%
+ c - replace with rules set C, chance 70%
+ d - replace with rules set D, chance 60%
+ + - yaw the turtle right by angle degrees
+ - - yaw the turtle left by angle degrees
+ & - pitch the turtle down by angle degrees
+ ^ - pitch the turtle up by angle degrees
+ / - roll the turtle to the right by angle degrees
+ * - roll the turtle to the left by angle degrees
+ [ - save in stack current state info
+ ] - recover from stack state info
+
+ */
+
+ s16 x,y,z;
+ for(s16 i=0; i<(s16)axiom.size(); i++)
+ {
+ char axiom_char = axiom.at(i);
+ core::matrix4 temp_rotation;
+ temp_rotation.makeIdentity();
+ v3f dir;
+ switch (axiom_char)
+ {
+ case 'G':
+ dir = v3f(-1,0,0);
+ dir = transposeMatrix(rotation,dir);
+ position+=dir;
+ break;
+ case 'F':
+ make_tree_trunk_placement(vmanip,v3f(p0.X+position.X,p0.Y+position.Y,p0.Z+position.Z),tree_definition);
+ if (tree_definition.thin_trunks == false)
+ {
+ make_tree_trunk_placement(vmanip,v3f(p0.X+position.X+1,p0.Y+position.Y,p0.Z+position.Z),tree_definition);
+ make_tree_trunk_placement(vmanip,v3f(p0.X+position.X-1,p0.Y+position.Y,p0.Z+position.Z),tree_definition);
+ make_tree_trunk_placement(vmanip,v3f(p0.X+position.X,p0.Y+position.Y,p0.Z+position.Z+1),tree_definition);
+ make_tree_trunk_placement(vmanip,v3f(p0.X+position.X,p0.Y+position.Y,p0.Z+position.Z-1),tree_definition);
+ }
+ if (stack_orientation.empty() == false)
+ {
+ s16 size = 1;
+ for(x=-size; x<size+1; x++)
+ for(y=-size; y<size+1; y++)
+ for(z=-size; z<size+1; z++)
+ if (abs(x) == size and abs(y) == size and abs(z) == size)
+ {
+ make_tree_leaves_placement(vmanip,v3f(p0.X+position.X+x+1,p0.Y+position.Y+y,p0.Z+position.Z+z),tree_definition);
+ make_tree_leaves_placement(vmanip,v3f(p0.X+position.X+x-1,p0.Y+position.Y+y,p0.Z+position.Z+z),tree_definition);
+ make_tree_leaves_placement(vmanip,v3f(p0.X+position.X+x,p0.Y+position.Y+y,p0.Z+position.Z+z+1),tree_definition);
+ make_tree_leaves_placement(vmanip,v3f(p0.X+position.X+x,p0.Y+position.Y+y,p0.Z+position.Z+z-1),tree_definition);
+ }
+ }
+ dir = v3f(1,0,0);
+ dir = transposeMatrix(rotation,dir);
+ position+=dir;
+ break;
+ // turtle commands
+ case '[':
+ stack_orientation.push(rotation);
+ stack_position.push(position);
+ break;
+ case ']':
+ rotation=stack_orientation.top();
+ stack_orientation.pop();
+ position=stack_position.top();
+ stack_position.pop();
+ break;
+ case '+':
+ temp_rotation.makeIdentity();
+ temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,0,1));
+ rotation*=temp_rotation;
+ break;
+ case '-':
+ temp_rotation.makeIdentity();
+ temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,0,-1));
+ rotation*=temp_rotation;
+ break;
+ case '&':
+ temp_rotation.makeIdentity();
+ temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,1,0));
+ rotation*=temp_rotation;
+ break;
+ case '^':
+ temp_rotation.makeIdentity();
+ temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians+angleOffset_in_radians,v3f(0,-1,0));
+ rotation*=temp_rotation;
+ break;
+ case '*':
+ temp_rotation.makeIdentity();
+ temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians,v3f(1,0,0));
+ rotation*=temp_rotation;
+ break;
+ case '/':
+ temp_rotation.makeIdentity();
+ temp_rotation=setRotationAxisRadians(temp_rotation, angle_in_radians,v3f(-1,0,0));
+ rotation*=temp_rotation;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void make_tree_node_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
+ MapNode node)
+{
+ v3s16 p1 = v3s16(round(p0.X),round(p0.Y),round(p0.Z));
+ if(vmanip.m_area.contains(p1) == false)
+ return;
+ u32 vi = vmanip.m_area.index(p1);
+ if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+ && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
+ return;
+ vmanip.m_data[vmanip.m_area.index(p1)] = node;
+}
+
+void make_tree_trunk_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
+ TreeDef &tree_definition)
+{
+ v3s16 p1 = v3s16(round(p0.X),round(p0.Y),round(p0.Z));
+ if(vmanip.m_area.contains(p1) == false)
+ return;
+ u32 vi = vmanip.m_area.index(p1);
+ if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+ && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
+ return;
+ vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.trunknode;
+}
+
+void make_tree_leaves_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
+ TreeDef &tree_definition)
+{
+ v3s16 p1 = v3s16(round(p0.X),round(p0.Y),round(p0.Z));
+ if(vmanip.m_area.contains(p1) == false)
+ return;
+ u32 vi = vmanip.m_area.index(p1);
+ if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+ && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
+ return;
+ if (tree_definition.fruit_tree)
+ {
+ if (myrand_range(1,100) > 90+tree_definition.iterations)
+ vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
+ else
+ vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.leavesnode;
+ }
+ else if (myrand_range(1,100) > 20)
+ vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.leavesnode;
+}
+
+irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis)
+{
+ double c = cos(angle);
+ double s = sin(angle);
+ double t = 1.0 - c;
+
+ double tx = t * axis.X;
+ double ty = t * axis.Y;
+ double tz = t * axis.Z;
+ double sx = s * axis.X;
+ double sy = s * axis.Y;
+ double sz = s * axis.Z;
+
+ M[0] = tx * axis.X + c;
+ M[1] = tx * axis.Y + sz;
+ M[2] = tx * axis.Z - sy;
+
+ M[4] = ty * axis.X - sz;
+ M[5] = ty * axis.Y + c;
+ M[6] = ty * axis.Z + sx;
+
+ M[8] = tz * axis.X + sy;
+ M[9] = tz * axis.Y - sx;
+ M[10] = tz * axis.Z + c;
+ return M;
+}
+
+v3f transposeMatrix(irr::core::matrix4 M, v3f v)
+{
+ v3f translated;
+ double x = M[0] * v.X + M[4] * v.Y + M[8] * v.Z +M[12];
+ double y = M[1] * v.X + M[5] * v.Y + M[9] * v.Z +M[13];
+ double z = M[2] * v.X + M[6] * v.Y + M[10] * v.Z +M[14];
+ translated.X=x;
+ translated.Y=y;
+ translated.Z=z;
+ return translated;
+}
+
+#if 0
+static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
+ INodeDefManager *ndef)
+{
+ MapNode treenode(ndef->getId("mapgen_jungletree"));
+ MapNode leavesnode(ndef->getId("mapgen_leaves"));
+
+ for(s16 x=-1; x<=1; x++)
+ for(s16 z=-1; z<=1; z++)
+ {
+ if(myrand_range(0, 2) == 0)
+ continue;
+ v3s16 p1 = p0 + v3s16(x,0,z);
+ v3s16 p2 = p0 + v3s16(x,-1,z);
+ if(vmanip.m_area.contains(p2)
+ && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
+ vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
+ else if(vmanip.m_area.contains(p1))
+ vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
+ }
+
+ s16 trunk_h = myrand_range(8, 12);
+ v3s16 p1 = p0;
+ for(s16 ii=0; ii<trunk_h; ii++)
+ {
+ if(vmanip.m_area.contains(p1))
+ vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
+ p1.Y++;
+ }
+
+ // p1 is now the last piece of the trunk
+ p1.Y -= 1;
+
+ VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
+ //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
+ Buffer<u8> leaves_d(leaves_a.getVolume());
+ for(s32 i=0; i<leaves_a.getVolume(); i++)
+ leaves_d[i] = 0;
+
+ // Force leaves at near the end of the trunk
+ {
+ s16 d = 1;
+ for(s16 z=-d; z<=d; z++)
+ for(s16 y=-d; y<=d; y++)
+ for(s16 x=-d; x<=d; x++)
+ {
+ leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
+ }
+ }
+
+ // Add leaves randomly
+ for(u32 iii=0; iii<30; iii++)
+ {
+ s16 d = 1;
+
+ v3s16 p(
+ myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
+ myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
+ myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
+ );
+
+ for(s16 z=0; z<=d; z++)
+ for(s16 y=0; y<=d; y++)
+ for(s16 x=0; x<=d; x++)
+ {
+ leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
+ }
+ }
+
+ // Blit leaves to vmanip
+ for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
+ for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
+ for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
+ {
+ v3s16 p(x,y,z);
+ p += p1;
+ if(vmanip.m_area.contains(p) == false)
+ continue;
+ u32 vi = vmanip.m_area.index(p);
+ if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+ && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
+ continue;
+ u32 i = leaves_a.index(x,y,z);
+ if(leaves_d[i] == 1)
+ vmanip.m_data[vi] = leavesnode;
+ }
+}
+#endif
+
+}; // namespace treegen
diff --git a/src/treegen.h b/src/treegen.h
new file mode 100644
index 000000000..62a220ee2
--- /dev/null
+++ b/src/treegen.h
@@ -0,0 +1,71 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>,
+ 2012 RealBadAngel, Maciej Kasatkin <mk@realbadangel.pl>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef TREEGEN_HEADER
+#define TREEGEN_HEADER
+
+#include <matrix4.h>
+
+class ManualMapVoxelManipulator;
+class INodeDefManager;
+
+
+namespace treegen
+{
+
+struct TreeDef
+{
+std::string initial_axiom;
+std::string rules_a;
+std::string rules_b;
+std::string rules_c;
+std::string rules_d;
+MapNode trunknode;
+MapNode leavesnode;
+int angle;
+int iterations;
+int iterations_random_level;
+bool thin_trunks;
+bool fruit_tree;
+MapNode fruitnode;
+};
+
+ // Add default tree
+ void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
+ bool is_apple_tree, INodeDefManager *ndef);
+
+ // Add L-Systems tree (used by engine)
+ void make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *ndef,
+ TreeDef tree_definition);
+ // Spawn L-systems tree from LUA
+ void spawn_ltree (ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition);
+
+ // L-System tree gen helper functions
+ void make_tree_node_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
+ MapNode node);
+ void make_tree_trunk_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
+ TreeDef &tree_definition);
+ void make_tree_leaves_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
+ TreeDef &tree_definition);
+ irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle,v3f axis);
+
+ v3f transposeMatrix(irr::core::matrix4 M ,v3f v);
+
+}; // namespace treegen
+#endif