]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/server/tree.c
Trees break if they have no connection to ground
[dragonblocks_alpha.git] / src / server / tree.c
1 #include <stdlib.h>
2 #include "server/biomes.h"
3 #include "server/server_node.h"
4 #include "server/server_terrain.h"
5 #include "server/tree.h"
6 #include "server/voxel_procedural.h"
7
8 typedef struct {
9         NodeType type;
10         v3s32 root;
11 } ProceduralTreeArg;
12
13 static TerrainNode create_tree_node(__attribute__((unused)) v3s32 pos, v3f32 color, ProceduralTreeArg *arg)
14 {
15         return server_node_create_tree(arg->type, (TreeData) {
16                 .color = color,
17                 .has_root = 1,
18                 .root = arg->root,
19         });
20 }
21
22 // oak
23
24 static bool oak_condition(TreeArgsCondition *args)
25 {
26         return args->biome == BIOME_HILLS;
27 }
28
29 static void oak_tree_leaf(VoxelProcedural *proc, v3s32 root)
30 {
31         if (!voxel_procedural_is_alive(proc))
32                 return;
33
34         voxel_procedural_push(proc);
35                 voxel_procedural_cube(proc, (void *) &create_tree_node,
36                         &(ProceduralTreeArg) {NODE_OAK_LEAVES, root});
37         voxel_procedural_pop(proc);
38
39         voxel_procedural_push(proc);
40                 voxel_procedural_x(proc, 0.5f);
41                 voxel_procedural_sx(proc, 0.9f);
42                 voxel_procedural_sy(proc, 0.9f);
43                 voxel_procedural_sz(proc, 0.8f);
44                 voxel_procedural_ry(proc, 25.0f);
45                 voxel_procedural_x(proc, 0.4f);
46                 oak_tree_leaf(proc, root);
47         voxel_procedural_pop(proc);
48 }
49
50 static void oak_tree_top(VoxelProcedural *proc, v3s32 root)
51 {
52         if (!voxel_procedural_is_alive(proc))
53                 return;
54
55         voxel_procedural_push(proc);
56         for (int i = 0; i < 8; i++) {
57                 voxel_procedural_rz(proc, 360.0f / 8.0f);
58                 voxel_procedural_push(proc);
59                         voxel_procedural_life(proc, 8);
60                         voxel_procedural_sy(proc, 2.0f);
61                         voxel_procedural_z(proc, voxel_procedural_random(proc, 0.0f, 5.0f));
62                         voxel_procedural_s(proc, 5.0f);
63                         voxel_procedural_light(proc, -0.4f);
64                         voxel_procedural_sat(proc, 0.5f);
65                         voxel_procedural_hue(proc, voxel_procedural_random(proc, 60.0f, 20.0f));
66                         voxel_procedural_ry(proc, -45.0f);
67                         oak_tree_leaf(proc, root);
68                 voxel_procedural_pop(proc);
69         }
70         voxel_procedural_pop(proc);
71 }
72
73 static void oak_tree_part(VoxelProcedural *proc, v3s32 root, f32 n)
74 {
75         if (!voxel_procedural_is_alive(proc))
76                 return;
77
78         voxel_procedural_push(proc);
79         for (int i = 1; i <= n; i++) {
80                 voxel_procedural_z(proc, 1.0f);
81                 voxel_procedural_rz(proc, voxel_procedural_random(proc, 30.0f, 10.0f));
82                 voxel_procedural_rx(proc, voxel_procedural_random(proc, 0.0f, 10.0f));
83
84                 voxel_procedural_push(proc);
85                         voxel_procedural_s(proc, 4.0f);
86                         voxel_procedural_x(proc, 0.1f);
87                         voxel_procedural_light(proc, voxel_procedural_random(proc, 0.0f, 0.1f));
88                         voxel_procedural_cylinder(proc, (void *) &create_tree_node,
89                                 &(ProceduralTreeArg) {NODE_OAK_WOOD, root});
90                 voxel_procedural_pop(proc);
91
92                 if (i == (int) (n - 2.0f)) {
93                         voxel_procedural_push(proc);
94                                 oak_tree_top(proc, root);
95                         voxel_procedural_pop(proc);
96                 }
97         }
98         voxel_procedural_pop(proc);
99 }
100
101 static void oak_tree(v3s32 root, List *changed_chunks)
102 {
103         VoxelProcedural *proc = voxel_procedural_create(changed_chunks, STAGE_TREES, root);
104
105         voxel_procedural_hue(proc, 40.0f);
106         voxel_procedural_light(proc, -0.5f);
107         voxel_procedural_sat(proc, 0.5f);
108
109         f32 n = voxel_procedural_random(proc, 40.0f, 10.0f);
110
111         voxel_procedural_push(proc);
112         for (int i = 1; i <= 3; i++) {
113                 voxel_procedural_rz(proc, voxel_procedural_random(proc, 120.0f, 45.0f));
114                 voxel_procedural_push(proc);
115                         voxel_procedural_y(proc, 0.5f);
116                         voxel_procedural_light(proc, voxel_procedural_random(proc, -0.3f, 0.05f));
117                         oak_tree_part(proc, root, n);
118                 voxel_procedural_pop(proc);
119         }
120         voxel_procedural_pop(proc);
121
122         voxel_procedural_delete(proc);
123 }
124
125 // pine
126
127 static bool pine_condition(TreeArgsCondition *args)
128 {
129         return args->biome == BIOME_MOUNTAIN;
130 }
131
132 static void pine_tree(v3s32 pos, List *changed_chunks)
133 {
134         s32 tree_top = (noise2d(pos.x, pos.z, 0, seed + OFFSET_PINETREE_HEIGHT) * 0.5 + 0.5) * (35.0 - 20.0) + 20.0 + pos.y;
135         for (v3s32 tree_pos = pos; tree_pos.y < tree_top; tree_pos.y++) {
136                 f64 branch_length = noise3d(tree_pos.x, tree_pos.y, tree_pos.z, 0, seed + OFFSET_PINETREE_BRANCH) * 3.0;
137
138                 v3s32 dirs[4] = {
139                         {+0, +0, +1},
140                         {+1, +0, +0},
141                         {+0, +0, -1},
142                         {-1, +0, +0},
143                 };
144
145                 s32 dir = (noise3d(tree_pos.x, tree_pos.y, tree_pos.z, 0, seed + OFFSET_PINETREE_BRANCH_DIR) * 0.5 + 0.5) * 4.0;
146
147                 for (v3s32 branch_pos = tree_pos; branch_length > 0; branch_length--, branch_pos = v3s32_add(branch_pos, dirs[dir]))
148                         server_terrain_gen_node(branch_pos, server_node_create(NODE_PINE_WOOD),
149                                 STAGE_TREES, changed_chunks);
150
151                 server_terrain_gen_node(tree_pos, server_node_create(NODE_PINE_WOOD),
152                         STAGE_TREES, changed_chunks);
153         }
154 }
155
156 // palm
157
158 static bool palm_condition(TreeArgsCondition *args)
159 {
160         return args->biome == BIOME_OCEAN
161                 && ocean_get_node_at((v3s32) {args->pos.x, args->pos.y - 0, args->pos.z}, 1, args->row_data) == NODE_AIR
162                 && ocean_get_node_at((v3s32) {args->pos.x, args->pos.y - 1, args->pos.z}, 0, args->row_data) == NODE_SAND;
163 }
164
165 static void palm_branch(VoxelProcedural *proc, v3s32 root)
166 {
167         if (!voxel_procedural_is_alive(proc))
168                 return;
169
170         voxel_procedural_cube(proc, (void *) &create_tree_node,
171                 &(ProceduralTreeArg) {NODE_PALM_LEAVES, root});
172
173         voxel_procedural_push(proc);
174                 voxel_procedural_z(proc, 0.5f);
175                 voxel_procedural_s(proc, 0.8f);
176                 voxel_procedural_rx(proc, voxel_procedural_random(proc, 20.0f, 4.0f));
177                 voxel_procedural_z(proc, 0.5f);
178                 palm_branch(proc, root);
179         voxel_procedural_pop(proc);
180 }
181
182 static void palm_tree(v3s32 root, List *changed_chunks)
183 {
184         VoxelProcedural *proc = voxel_procedural_create(changed_chunks, STAGE_TREES, (v3s32) {root.x, root.y - 1, root.z});
185
186         f32 s = voxel_procedural_random(proc, 8.0f, 2.0f);
187
188         voxel_procedural_push(proc);
189         for (int i = 1; i <= s; i++) {
190                 voxel_procedural_z(proc, 1.0f);
191                 voxel_procedural_push(proc);
192                         voxel_procedural_s(proc, 1.0f);
193                         voxel_procedural_light(proc, voxel_procedural_random(proc, -0.8f, 0.1f));
194                         voxel_procedural_sat(proc, 0.5f);
195                         voxel_procedural_cube(proc, (void *) &create_tree_node,
196                                 &(ProceduralTreeArg) {NODE_PALM_WOOD, root});
197                 voxel_procedural_pop(proc);
198         }
199         voxel_procedural_pop(proc);
200
201         voxel_procedural_z(proc, s);
202         voxel_procedural_sat(proc, 1.0f),
203         voxel_procedural_light(proc, -0.5f);
204         voxel_procedural_hue(proc, voxel_procedural_random(proc, 50.0f, 30.0f));
205
206         voxel_procedural_push(proc);
207         for (int i = 0; i < 6; i++) {
208                 voxel_procedural_rz(proc, 360.0f / 6.0f);
209                 voxel_procedural_rz(proc, voxel_procedural_random(proc, 0.0f, 10.0f));
210                 voxel_procedural_push(proc);
211                         voxel_procedural_light(proc, voxel_procedural_random(proc, 0.0f, 0.3f));
212                         voxel_procedural_rx(proc, 90.0f);
213                         voxel_procedural_s(proc, 2.0f);
214                         palm_branch(proc, root);
215                 voxel_procedural_pop(proc);
216         }
217         voxel_procedural_pop(proc);
218
219         voxel_procedural_delete(proc);
220 }
221
222 TreeDef tree_def[NUM_TREES] = {
223         // oak
224         {
225                 .spread = 64.0f,
226                 .probability = 0.0005f,
227                 .area_probability = 0.3f,
228                 .offset = OFFSET_OAKTREE,
229                 .area_offset = OFFSET_OAKTREE_AREA,
230                 .condition = &oak_condition,
231                 .generate = &oak_tree,
232         },
233         // pine
234         {
235                 .spread = 256.0f,
236                 .probability = 0.01f,
237                 .area_probability = 0.1f,
238                 .offset = OFFSET_PINETREE,
239                 .area_offset = OFFSET_PINETREE_AREA,
240                 .condition = &pine_condition,
241                 .generate = &pine_tree,
242         },
243         // palm
244         {
245                 .spread = 16.0f,
246                 .probability = 0.005f,
247                 .area_probability = 0.5f,
248                 .offset = OFFSET_PALMTREE,
249                 .area_offset = OFFSET_PALMTREE_AREA,
250                 .condition = &palm_condition,
251                 .generate = &palm_tree,
252         },
253 };
254