]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/server/voxel_procedural.c
Fix boulder shapes: depth-search to ground
[dragonblocks_alpha.git] / src / server / voxel_procedural.c
1 #include <stdlib.h>
2 #include <pthread.h>
3 #include "color.h"
4 #include "perlin.h"
5 #include "server/terrain_gen.h"
6 #include "server/voxel_procedural.h"
7
8 #define VOXEL_PROCEDURAL_STATE(proc) (*((VoxelProceduralState *) (proc)->state.fst->dat))
9
10 static VoxelProceduralState *create_state(VoxelProceduralState *old)
11 {
12         VoxelProceduralState *state = malloc(sizeof *state);
13
14         if (old) {
15                 *state = *old;
16         } else {
17                 state->pos[0] = 0.0f;
18                 state->pos[1] = 0.0f;
19                 state->pos[2] = 0.0f;
20                 state->pos[3] = 0.0f;
21                 state->scale[0] = 1.0f;
22                 state->scale[1] = 1.0f;
23                 state->scale[2] = 1.0f;
24                 mat4x4_identity(state->mat);
25                 state->h = 0.0f;
26                 state->s = 0.0f;
27                 state->l = 1.0f;
28                 state->life = 0;
29         }
30
31         return state;
32 }
33
34 VoxelProcedural *voxel_procedural_create(List *changed_chunks, TerrainGenStage tgs, v3s32 pos)
35 {
36         VoxelProcedural *proc = malloc(sizeof(VoxelProcedural));
37
38         proc->changed_chunks = changed_chunks;
39         proc->tgs = tgs;
40         proc->pos = pos;
41         proc->random = 0;
42
43         list_ini(&proc->state);
44         list_apd(&proc->state, create_state(NULL));
45
46         return proc;
47 }
48
49 void voxel_procedural_delete(VoxelProcedural *proc)
50 {
51         list_clr(&proc->state, &free, NULL, NULL);
52         free(proc);
53 }
54
55 static void move_value(f32 *x, f32 v, f32 range)
56 {
57     f32 dst = v >= 0 ? range : 0;
58     v = fabs(v);
59     *x = f32_mix(*x, dst, v);
60 }
61
62 void voxel_procedural_hue(VoxelProcedural *proc, f32 value)
63 {
64         VOXEL_PROCEDURAL_STATE(proc).h += value;
65 }
66
67 void voxel_procedural_sat(VoxelProcedural *proc, f32 value)
68 {
69         move_value(&VOXEL_PROCEDURAL_STATE(proc).s, value, 1.0f);
70 }
71
72 void voxel_procedural_light(VoxelProcedural *proc, f32 value)
73 {
74         move_value(&VOXEL_PROCEDURAL_STATE(proc).l, value, 1.0f);
75 }
76
77 void voxel_procedural_life(VoxelProcedural *proc, s32 value)
78 {
79         VOXEL_PROCEDURAL_STATE(proc).life += value;
80 }
81
82 static void apply_translation(VoxelProcedural *proc, v3f32 translate)
83 {
84         vec4 dst, src = {translate.x, translate.y, translate.z, 0.0f};
85         mat4x4_mul_vec4(dst, VOXEL_PROCEDURAL_STATE(proc).mat, src);
86         vec4_add(VOXEL_PROCEDURAL_STATE(proc).pos, VOXEL_PROCEDURAL_STATE(proc).pos, dst);
87 }
88
89 void voxel_procedural_x(VoxelProcedural *proc, f32 value)
90 {
91         apply_translation(proc, (v3f32) {value, 0.0f, 0.0f});
92 }
93
94 void voxel_procedural_y(VoxelProcedural *proc, f32 value)
95 {
96         apply_translation(proc, (v3f32) {0.0f, value, 0.0f});
97 }
98
99 void voxel_procedural_z(VoxelProcedural *proc, f32 value)
100 {
101         apply_translation(proc, (v3f32) {0.0f, 0.0f, value});
102 }
103
104 void voxel_procedural_rx(VoxelProcedural *proc, f32 value)
105 {
106         mat4x4_rotate_X(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat,
107                 value * M_PI / 180.0f);
108 }
109
110 void voxel_procedural_ry(VoxelProcedural *proc, f32 value)
111 {
112         mat4x4_rotate_Y(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat,
113                 value * M_PI / 180.0f);
114 }
115
116 void voxel_procedural_rz(VoxelProcedural *proc, f32 value)
117 {
118         mat4x4_rotate_Z(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat,
119                 value * M_PI / 180.0f);
120 }
121
122 static void apply_scale(VoxelProcedural *proc, v3f32 scale)
123 {
124         VOXEL_PROCEDURAL_STATE(proc).scale[0] *= scale.x;
125         VOXEL_PROCEDURAL_STATE(proc).scale[1] *= scale.y;
126         VOXEL_PROCEDURAL_STATE(proc).scale[2] *= scale.z;
127
128         mat4x4_scale_aniso(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat,
129                 scale.x, scale.y, scale.z);
130 }
131
132 void voxel_procedural_sx(VoxelProcedural *proc, f32 value)
133 {
134         apply_scale(proc, (v3f32) {value, 1.0f, 1.0f});
135 }
136
137 void voxel_procedural_sy(VoxelProcedural *proc, f32 value)
138 {
139         apply_scale(proc, (v3f32) {1.0f, value, 1.0f});
140 }
141
142 void voxel_procedural_sz(VoxelProcedural *proc, f32 value)
143 {
144         apply_scale(proc, (v3f32) {1.0f, 1.0f, value});
145 }
146
147 void voxel_procedural_s(VoxelProcedural *proc, f32 value)
148 {
149         apply_scale(proc, (v3f32) {value, value, value});
150 }
151
152 void voxel_procedural_pop(VoxelProcedural *proc)
153 {
154         free(proc->state.fst->dat);
155         list_nrm(&proc->state, &proc->state.fst);
156 }
157
158 void voxel_procedural_push(VoxelProcedural *proc)
159 {
160         list_ppd(&proc->state, create_state(&VOXEL_PROCEDURAL_STATE(proc)));
161 }
162
163 bool voxel_procedural_is_alive(VoxelProcedural *proc)
164 {
165         if (VOXEL_PROCEDURAL_STATE(proc).life > 0 && --VOXEL_PROCEDURAL_STATE(proc).life <= 0)
166                 return false;
167
168         return
169                 VOXEL_PROCEDURAL_STATE(proc).scale[0] >= 1.0f &&
170                 VOXEL_PROCEDURAL_STATE(proc).scale[1] >= 1.0f &&
171                 VOXEL_PROCEDURAL_STATE(proc).scale[2] >= 1.0f;
172 }
173
174 void voxel_procedural_cube(VoxelProcedural *proc, NodeType node, bool use_color)
175 {
176         if (!voxel_procedural_is_alive(proc))
177                 return;
178
179         vec4 base_corners[8] = {
180                 {0.0f, 0.0f, 0.0f, 0.0f},
181                 {0.0f, 0.0f, 1.0f, 0.0f},
182                 {0.0f, 1.0f, 0.0f, 0.0f},
183                 {0.0f, 1.0f, 1.0f, 0.0f},
184                 {1.0f, 0.0f, 0.0f, 0.0f},
185                 {1.0f, 0.0f, 1.0f, 0.0f},
186                 {1.0f, 1.0f, 0.0f, 0.0f},
187                 {1.0f, 1.0f, 1.0f, 0.0f},
188         };
189
190         vec4 corners[8];
191
192         s32 max_len = 0;
193
194         vec4 center;
195
196         mat4x4_mul_vec4(center, VOXEL_PROCEDURAL_STATE(proc).mat, (vec4) {0.5f, 0.5f, 0.5f});
197
198         for (int i = 0; i < 8; i++) {
199                 mat4x4_mul_vec4(corners[i], VOXEL_PROCEDURAL_STATE(proc).mat, base_corners[i]);
200
201                 vec3 from_center;
202                 vec3_sub(from_center, corners[i], center);
203
204                 s32 len = ceil(vec3_len(from_center));
205
206                 if (max_len < len)
207                         max_len = len;
208         }
209
210         for (s32 x = -max_len; x <= +max_len; x++)
211         for (s32 y = -max_len; y <= +max_len; y++)
212         for (s32 z = -max_len; z <= +max_len; z++) {
213                 s32 v[3];
214
215                 for (int i = 0; i < 3; i++) {
216                         f32 f = trunc(
217                                 + f32_mix(corners[0][i], corners[4][i], (f32) x / (f32) max_len / 2.0f)
218                                 + f32_mix(corners[0][i], corners[2][i], (f32) y / (f32) max_len / 2.0f)
219                                 + f32_mix(corners[0][i], corners[1][i], (f32) z / (f32) max_len / 2.0f));
220
221                         v[i] = floor(VOXEL_PROCEDURAL_STATE(proc).pos[i] + f + 0.5f);
222                 }
223
224                 Blob buffer = {0, NULL};
225
226                 if (use_color)
227                         ColorData_write(&buffer, &(ColorData) {hsl_to_rgb((v3f32) {
228                                 VOXEL_PROCEDURAL_STATE(proc).h / 360.0,
229                                 VOXEL_PROCEDURAL_STATE(proc).s,
230                                 VOXEL_PROCEDURAL_STATE(proc).l,
231                         })});
232
233                 server_terrain_gen_node(
234                         v3s32_add(proc->pos, (v3s32) {v[0], v[2], v[1]}),
235                         terrain_node_create(node, buffer),
236                         proc->tgs,
237                         proc->changed_chunks
238                 );
239
240                 Blob_free(&buffer);
241         }
242 }
243
244
245 void voxel_procedural_cylinder(VoxelProcedural *proc, NodeType node, bool use_color)
246 {
247         voxel_procedural_cube(proc, node, use_color);
248 }
249
250 /*
251 void voxel_procedural_cylinder(VoxelProcedural *proc, Node node, bool use_color)
252 {
253         if (!voxel_procedural_is_alive(proc))
254                 return;
255
256         return;
257
258         f32 xf = VOXEL_PROCEDURAL_STATE(proc).scale[0] / 2.0f;
259         for (s32 x = round(-xf + 0.5f); x <= round(xf); x++) {
260                 f32 yf = cos(x / VOXEL_PROCEDURAL_STATE(proc).scale[0] * M_PI) * VOXEL_PROCEDURAL_STATE(proc).scale[1] / 2.0f;
261                 for (s32 y = round(-yf); y <= round(yf); y++) {
262                         f32 zf = VOXEL_PROCEDURAL_STATE(proc).scale[2] / 2.0f;
263                         for (s32 z = round(-zf + 0.5f); z <= round(zf); z++) {
264                                 mapgen_set_node((v3s32) {
265                                         proc->pos.x + round(VOXEL_PROCEDURAL_STATE(proc).pos[0] + x),
266                                         proc->pos.y + round(VOXEL_PROCEDURAL_STATE(proc).pos[2] + z),
267                                         proc->pos.z + round(VOXEL_PROCEDURAL_STATE(proc).pos[1] + y),
268                                 }, CREATE_NODE, proc->tgs, proc->changed_chunks);
269                         }
270                 }
271         }
272 }
273 */
274
275 f32 voxel_procedural_random(VoxelProcedural *proc, f32 base, f32 vary)
276 {
277         return base + noise3d(proc->pos.x, proc->pos.y, proc->pos.z, proc->random++, seed + OFFSET_VOXEL_PROCEDURAL) * vary;
278 }