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