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