3 #include "common/color.h"
4 #include "common/perlin.h"
5 #include "server/terrain_gen.h"
6 #include "server/voxel_procedural.h"
8 #define VOXEL_PROCEDURAL_STATE(proc) (*((VoxelProceduralState *) (proc)->state.fst->dat))
10 static VoxelProceduralState *create_state(VoxelProceduralState *old)
12 VoxelProceduralState *state = malloc(sizeof *state);
21 state->scale[0] = 1.0f;
22 state->scale[1] = 1.0f;
23 state->scale[2] = 1.0f;
24 mat4x4_identity(state->mat);
34 VoxelProcedural *voxel_procedural_create(List *changed_chunks, TerrainGenStage tgs, v3s32 pos)
36 VoxelProcedural *proc = malloc(sizeof(VoxelProcedural));
38 proc->changed_chunks = changed_chunks;
43 list_ini(&proc->state);
44 list_apd(&proc->state, create_state(NULL));
49 void voxel_procedural_delete(VoxelProcedural *proc)
51 list_clr(&proc->state, &free, NULL, NULL);
55 static void move_value(f32 *x, f32 v, f32 range)
57 f32 dst = v >= 0 ? range : 0;
59 *x = f32_mix(*x, dst, v);
62 void voxel_procedural_hue(VoxelProcedural *proc, f32 value)
64 VOXEL_PROCEDURAL_STATE(proc).h += value;
67 void voxel_procedural_sat(VoxelProcedural *proc, f32 value)
69 move_value(&VOXEL_PROCEDURAL_STATE(proc).s, value, 1.0f);
72 void voxel_procedural_light(VoxelProcedural *proc, f32 value)
74 move_value(&VOXEL_PROCEDURAL_STATE(proc).l, value, 1.0f);
77 void voxel_procedural_life(VoxelProcedural *proc, s32 value)
79 VOXEL_PROCEDURAL_STATE(proc).life += value;
82 static void apply_translation(VoxelProcedural *proc, v3f32 translate)
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);
89 void voxel_procedural_x(VoxelProcedural *proc, f32 value)
91 apply_translation(proc, (v3f32) {value, 0.0f, 0.0f});
94 void voxel_procedural_y(VoxelProcedural *proc, f32 value)
96 apply_translation(proc, (v3f32) {0.0f, value, 0.0f});
99 void voxel_procedural_z(VoxelProcedural *proc, f32 value)
101 apply_translation(proc, (v3f32) {0.0f, 0.0f, value});
104 void voxel_procedural_rx(VoxelProcedural *proc, f32 value)
106 mat4x4_rotate_X(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat,
107 value * M_PI / 180.0f);
110 void voxel_procedural_ry(VoxelProcedural *proc, f32 value)
112 mat4x4_rotate_Y(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat,
113 value * M_PI / 180.0f);
116 void voxel_procedural_rz(VoxelProcedural *proc, f32 value)
118 mat4x4_rotate_Z(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat,
119 value * M_PI / 180.0f);
122 static void apply_scale(VoxelProcedural *proc, v3f32 scale)
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;
128 mat4x4_scale_aniso(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat,
129 scale.x, scale.y, scale.z);
132 void voxel_procedural_sx(VoxelProcedural *proc, f32 value)
134 apply_scale(proc, (v3f32) {value, 1.0f, 1.0f});
137 void voxel_procedural_sy(VoxelProcedural *proc, f32 value)
139 apply_scale(proc, (v3f32) {1.0f, value, 1.0f});
142 void voxel_procedural_sz(VoxelProcedural *proc, f32 value)
144 apply_scale(proc, (v3f32) {1.0f, 1.0f, value});
147 void voxel_procedural_s(VoxelProcedural *proc, f32 value)
149 apply_scale(proc, (v3f32) {value, value, value});
152 void voxel_procedural_pop(VoxelProcedural *proc)
154 free(proc->state.fst->dat);
155 list_nrm(&proc->state, &proc->state.fst);
158 void voxel_procedural_push(VoxelProcedural *proc)
160 list_ppd(&proc->state, create_state(&VOXEL_PROCEDURAL_STATE(proc)));
163 bool voxel_procedural_is_alive(VoxelProcedural *proc)
165 if (VOXEL_PROCEDURAL_STATE(proc).life > 0 && --VOXEL_PROCEDURAL_STATE(proc).life <= 0)
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;
174 void voxel_procedural_cube(VoxelProcedural *proc, VoxelProceduralNode func, void *arg)
176 if (!voxel_procedural_is_alive(proc))
179 v3f32 color = hsl_to_rgb((v3f32) {
180 VOXEL_PROCEDURAL_STATE(proc).h / 360.0,
181 VOXEL_PROCEDURAL_STATE(proc).s,
182 VOXEL_PROCEDURAL_STATE(proc).l});
184 vec4 base_corners[8] = {
185 {0.0f, 0.0f, 0.0f, 0.0f},
186 {0.0f, 0.0f, 1.0f, 0.0f},
187 {0.0f, 1.0f, 0.0f, 0.0f},
188 {0.0f, 1.0f, 1.0f, 0.0f},
189 {1.0f, 0.0f, 0.0f, 0.0f},
190 {1.0f, 0.0f, 1.0f, 0.0f},
191 {1.0f, 1.0f, 0.0f, 0.0f},
192 {1.0f, 1.0f, 1.0f, 0.0f},
201 mat4x4_mul_vec4(center, VOXEL_PROCEDURAL_STATE(proc).mat, (vec4) {0.5f, 0.5f, 0.5f});
203 for (int i = 0; i < 8; i++) {
204 mat4x4_mul_vec4(corners[i], VOXEL_PROCEDURAL_STATE(proc).mat, base_corners[i]);
207 vec3_sub(from_center, corners[i], center);
209 s32 len = ceil(vec3_len(from_center));
215 for (s32 x = -max_len; x <= +max_len; x++)
216 for (s32 y = -max_len; y <= +max_len; y++)
217 for (s32 z = -max_len; z <= +max_len; z++) {
220 for (int i = 0; i < 3; i++) {
222 + f32_mix(corners[0][i], corners[4][i], (f32) x / (f32) max_len / 2.0f)
223 + f32_mix(corners[0][i], corners[2][i], (f32) y / (f32) max_len / 2.0f)
224 + f32_mix(corners[0][i], corners[1][i], (f32) z / (f32) max_len / 2.0f));
226 v[i] = floor(VOXEL_PROCEDURAL_STATE(proc).pos[i] + f + 0.5f);
229 v3s32 pos = v3s32_add(proc->pos, (v3s32) {v[0], v[2], v[1]});
230 server_terrain_gen_node(pos, func(pos, color, arg),
231 proc->tgs, proc->changed_chunks);
236 void voxel_procedural_cylinder(VoxelProcedural *proc, VoxelProceduralNode func, void *arg)
238 voxel_procedural_cube(proc, func, arg);
242 void voxel_procedural_cylinder(VoxelProcedural *proc, Node node, bool use_color)
244 if (!voxel_procedural_is_alive(proc))
249 f32 xf = VOXEL_PROCEDURAL_STATE(proc).scale[0] / 2.0f;
250 for (s32 x = round(-xf + 0.5f); x <= round(xf); x++) {
251 f32 yf = cos(x / VOXEL_PROCEDURAL_STATE(proc).scale[0] * M_PI) * VOXEL_PROCEDURAL_STATE(proc).scale[1] / 2.0f;
252 for (s32 y = round(-yf); y <= round(yf); y++) {
253 f32 zf = VOXEL_PROCEDURAL_STATE(proc).scale[2] / 2.0f;
254 for (s32 z = round(-zf + 0.5f); z <= round(zf); z++) {
255 mapgen_set_node((v3s32) {
256 proc->pos.x + round(VOXEL_PROCEDURAL_STATE(proc).pos[0] + x),
257 proc->pos.y + round(VOXEL_PROCEDURAL_STATE(proc).pos[2] + z),
258 proc->pos.z + round(VOXEL_PROCEDURAL_STATE(proc).pos[1] + y),
259 }, CREATE_NODE, proc->tgs, proc->changed_chunks);
266 f32 voxel_procedural_random(VoxelProcedural *proc, f32 base, f32 vary)
268 return base + noise3d(proc->pos.x, proc->pos.y, proc->pos.z, proc->random++, seed + OFFSET_VOXEL_PROCEDURAL) * vary;