]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/server/voxelctx.c
Add trees
[dragonblocks_alpha.git] / src / server / voxelctx.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <pthread.h>
4 #include "server/mapgen.h"
5 #include "server/voxelctx.h"
6 #include "perlin.h"
7 #include "util.h"
8
9 #define CREATE_NODE map_node_create(node, use_color ? (f32[]) {VOXELCTXSTATE(ctx).h / 360.0, VOXELCTXSTATE(ctx).s, VOXELCTXSTATE(ctx).l} : NULL, use_color ? sizeof(f32) * 3 : 0)
10
11 static VoxelctxState *create_state(VoxelctxState *old)
12 {
13         VoxelctxState *state = malloc(sizeof(VoxelctxState));
14
15         if (old) {
16                 *state = *old;
17                 state->strs = array_create(sizeof(char *));
18
19                 for (size_t i = 0; i < old->strs.siz; i++) {
20                         char *s = strdup(((char **) old->strs.ptr)[i]);
21                         array_append(&state->strs, &s);
22                 }
23         } else {
24                 state->pos[0] = 0.0f;
25                 state->pos[1] = 0.0f;
26                 state->pos[2] = 0.0f;
27                 state->pos[3] = 1.0f;
28                 state->scale[0] = 1.0f;
29                 state->scale[1] = 1.0f;
30                 state->scale[2] = 1.0f;
31                 mat4x4_identity(state->mat);
32                 state->h = 0.0f;
33                 state->s = 0.0f;
34                 state->l = 1.0f;
35                 state->life = 0;
36
37                 state->strs = array_create(sizeof(char *));
38                 char *s = format_string("glm.mat4()\n");
39                 array_append(&state->strs, &s);
40         }
41
42         return state;
43 }
44
45 Voxelctx *voxelctx_create(List *changed_blocks, MapgenStage mgs, v3s32 pos)
46 {
47         Voxelctx *ctx = malloc(sizeof(Voxelctx));
48
49         ctx->changed_blocks = changed_blocks;
50         ctx->mgs = mgs;
51         ctx->pos = pos;
52         ctx->statestack = list_create(NULL);
53         ctx->random = 0;
54
55         list_put(&ctx->statestack, create_state(NULL), NULL);
56
57         return ctx;
58 }
59
60 static void delete_state(VoxelctxState *state)
61 {
62         for (size_t i = 0; i < state->strs.siz; i++)
63                 free(((char **) state->strs.ptr)[i]);
64
65         free(state->strs.ptr);
66 }
67
68 static void list_delete_state(void *key, unused void *value, unused void *arg)
69 {
70         delete_state(key);
71         free(key);
72 }
73
74 void voxelctx_delete(Voxelctx *ctx)
75 {
76         list_clear_func(&ctx->statestack, &list_delete_state, NULL);
77         free(ctx);
78 }
79
80 static inline f32 mix(f32 x, f32 y, f32 t)
81 {
82     return (1.0 - t) * x + t * y;
83 }
84
85 static void move_value(f32 *x, f32 v, f32 range)
86 {
87     f32 dst = v >= 0 ? range : 0;
88     v = fabs(v);
89     *x = mix(*x, dst, v);
90 }
91
92 void voxelctx_hue(Voxelctx *ctx, f32 value)
93 {
94         VOXELCTXSTATE(ctx).h += value;
95 }
96
97 void voxelctx_sat(Voxelctx *ctx, f32 value)
98 {
99         move_value(&VOXELCTXSTATE(ctx).s, value, 1.0f);
100 }
101
102 void voxelctx_light(Voxelctx *ctx, f32 value)
103 {
104         move_value(&VOXELCTXSTATE(ctx).l, value, 1.0f);
105 }
106
107 void voxelctx_life(Voxelctx *ctx, s32 value)
108 {
109         VOXELCTXSTATE(ctx).life += value;
110 }
111
112 static void apply_translation(Voxelctx *ctx, v3f32 translate)
113 {
114         vec4 translate_vec;
115 #pragma GCC diagnostic push
116 #pragma GCC diagnostic ignored "-Wpedantic"
117         mat4x4_mul_vec4(translate_vec, VOXELCTXSTATE(ctx).mat, (vec4) {translate.x, translate.y, translate.z, 0.0f});
118 #pragma GCC diagnostic pop
119         vec4_add(VOXELCTXSTATE(ctx).pos, VOXELCTXSTATE(ctx).pos, translate_vec);
120 }
121
122 void voxelctx_x(Voxelctx *ctx, f32 value)
123 {
124         apply_translation(ctx, (v3f32) {value, 0.0f, 0.0f});
125 }
126
127 // swap y and z
128 void voxelctx_z(Voxelctx *ctx, f32 value)
129 {
130         apply_translation(ctx, (v3f32) {0.0f, value, 0.0f});
131 }
132
133 void voxelctx_y(Voxelctx *ctx, f32 value)
134 {
135         apply_translation(ctx, (v3f32) {0.0f, 0.0f, value});
136 }
137
138 void voxelctx_rx(Voxelctx *ctx, f32 value)
139 {
140 #pragma GCC diagnostic push
141 #pragma GCC diagnostic ignored "-Wpedantic"
142         mat4x4_rotate_X(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, value * M_PI / 180.0f);
143 #pragma GCC diagnostic pop
144 }
145
146 // swap y and z
147 void voxelctx_rz(Voxelctx *ctx, f32 value)
148 {
149 #pragma GCC diagnostic push
150 #pragma GCC diagnostic ignored "-Wpedantic"
151
152         mat4x4_rotate_Y(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, value * M_PI / 180.0f);
153 #pragma GCC diagnostic pop
154 }
155
156 void voxelctx_ry(Voxelctx *ctx, f32 value)
157 {
158 #pragma GCC diagnostic push
159 #pragma GCC diagnostic ignored "-Wpedantic"
160         mat4x4_rotate_Z(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, value * M_PI / 180.0f);
161 #pragma GCC diagnostic pop
162 }
163
164 static void apply_scale(Voxelctx *ctx, v3f32 scale)
165 {
166         VOXELCTXSTATE(ctx).scale[0] *= scale.x;
167         VOXELCTXSTATE(ctx).scale[1] *= scale.y;
168         VOXELCTXSTATE(ctx).scale[2] *= scale.z;
169
170 #pragma GCC diagnostic push
171 #pragma GCC diagnostic ignored "-Wpedantic"
172         mat4x4_scale_aniso(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, scale.x, scale.y, scale.z);
173 #pragma GCC diagnostic pop
174 }
175
176 void voxelctx_sx(Voxelctx *ctx, f32 value)
177 {
178         apply_scale(ctx, (v3f32) {value, 1.0f, 1.0f});
179 }
180
181 // swap y and z
182 void voxelctx_sz(Voxelctx *ctx, f32 value)
183 {
184         apply_scale(ctx, (v3f32) {1.0f, value, 1.0f});
185 }
186
187 void voxelctx_sy(Voxelctx *ctx, f32 value)
188 {
189         apply_scale(ctx, (v3f32) {1.0f, 1.0f, value});
190 }
191
192 void voxelctx_s(Voxelctx *ctx, f32 value)
193 {
194         apply_scale(ctx, (v3f32) {value, value, value});
195 }
196
197 void voxelctx_pop(Voxelctx *ctx)
198 {
199         ListPair *next = ctx->statestack.first->next;
200         delete_state(ctx->statestack.first->key);
201         free(ctx->statestack.first->key);
202         free(ctx->statestack.first);
203         ctx->statestack.first = next;
204 }
205
206 void voxelctx_push(Voxelctx *ctx)
207 {
208         ListPair *pair = malloc(sizeof(ListPair));
209         pair->key = create_state(&VOXELCTXSTATE(ctx));
210         pair->value = NULL;
211         pair->next = ctx->statestack.first;
212
213         ctx->statestack.first = pair;
214 }
215
216 bool voxelctx_is_alive(Voxelctx *ctx)
217 {
218         if (VOXELCTXSTATE(ctx).life > 0) {
219                 VOXELCTXSTATE(ctx).life--;
220                 if (VOXELCTXSTATE(ctx).life <= 0)
221                         return false;
222         }
223
224         return VOXELCTXSTATE(ctx).scale[0] >= 1.0f && VOXELCTXSTATE(ctx).scale[1] >= 1.0f && VOXELCTXSTATE(ctx).scale[2] >= 1.0f;
225 }
226
227 void voxelctx_cube(Voxelctx *ctx, Node node, bool use_color)
228 {
229         if (! voxelctx_is_alive(ctx))
230                 return;
231
232         vec4 base_corners[8] = {
233                 {0.0f, 0.0f, 0.0f, 0.0f},
234                 {0.0f, 0.0f, 1.0f, 0.0f},
235                 {0.0f, 1.0f, 0.0f, 0.0f},
236                 {0.0f, 1.0f, 1.0f, 0.0f},
237                 {1.0f, 0.0f, 0.0f, 0.0f},
238                 {1.0f, 0.0f, 1.0f, 0.0f},
239                 {1.0f, 1.0f, 0.0f, 0.0f},
240                 {1.0f, 1.0f, 1.0f, 0.0f},
241         };
242
243         vec4 corners[8];
244
245         s32 max_len = 0;
246
247         vec4 center;
248 #pragma GCC diagnostic push
249 #pragma GCC diagnostic ignored "-Wpedantic"
250         mat4x4_mul_vec4(center, VOXELCTXSTATE(ctx).mat, (vec4) {0.5f, 0.5f, 0.5f});
251 #pragma GCC diagnostic pop
252
253         for (int i = 0; i < 8; i++) {
254 #pragma GCC diagnostic push
255 #pragma GCC diagnostic ignored "-Wpedantic"
256                 mat4x4_mul_vec4(corners[i], VOXELCTXSTATE(ctx).mat, base_corners[i]);
257 #pragma GCC diagnostic pop
258
259                 vec3 from_center;
260                 vec3_sub(from_center, corners[i], center);
261
262                 s32 len = ceil(vec3_len(from_center));
263
264                 if (max_len < len)
265                         max_len = len;
266         }
267
268         for (s32 x = -max_len; x <= +max_len; x++)
269         for (s32 y = -max_len; y <= +max_len; y++)
270         for (s32 z = -max_len; z <= +max_len; z++) {
271                 s32 v[3];
272
273                 for (int i = 0; i < 3; i++)
274                         v[i] = floor(VOXELCTXSTATE(ctx).pos[0] + 0.5f
275                                 + mix(corners[0][i], corners[4][i], (f32) x / (f32) max_len / 2.0f)
276                                 + mix(corners[0][i], corners[2][i], (f32) y / (f32) max_len / 2.0f)
277                                 + mix(corners[0][i], corners[1][i], (f32) z / (f32) max_len / 2.0f));
278
279                 mapgen_set_node(v3s32_add(ctx->pos, (v3s32) {v[0], v[1], v[2]}), CREATE_NODE, ctx->mgs, ctx->changed_blocks);
280         }
281 }
282
283 /*
284 void voxelctx_cylinder(Voxelctx *ctx, Node node, bool use_color)
285 {
286         if (! voxelctx_is_alive(ctx))
287                 return;
288
289         return;
290
291         f32 xf = VOXELCTXSTATE(ctx).scale[0] / 2.0f;
292         for (s32 x = round(-xf + 0.5f); x <= round(xf); x++) {
293                 f32 yf = cos(x / VOXELCTXSTATE(ctx).scale[0] * M_PI) * VOXELCTXSTATE(ctx).scale[1] / 2.0f;
294                 for (s32 y = round(-yf); y <= round(yf); y++) {
295                         f32 zf = VOXELCTXSTATE(ctx).scale[2] / 2.0f;
296                         for (s32 z = round(-zf + 0.5f); z <= round(zf); z++) {
297                                 mapgen_set_node((v3s32) {
298                                         ctx->pos.x + round(VOXELCTXSTATE(ctx).pos[0] + x),
299                                         ctx->pos.y + round(VOXELCTXSTATE(ctx).pos[2] + z),
300                                         ctx->pos.z + round(VOXELCTXSTATE(ctx).pos[1] + y),
301                                 }, CREATE_NODE, ctx->mgs, ctx->changed_blocks);
302                         }
303                 }
304         }
305 }
306 */
307
308 f32 voxelctx_random(Voxelctx *ctx, f32 base, f32 vary)
309 {
310         return base + noise3d(ctx->pos.x, ctx->pos.y, ctx->pos.z, ctx->random++, seed + SO_VOXELCTX) * vary;
311 }