From ac87180ab3f2e646c9ea40e7af09dd1a7f38a4a6 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 18 Apr 2022 00:35:54 +0200 Subject: [PATCH] Fix boulder shapes: depth-search to ground --- src/CMakeLists.txt | 3 +- src/client/client_node.c | 4 +- src/environment.c | 4 +- src/perlin.h | 50 +++--- src/server/biomes.c | 91 ++++++++--- src/server/biomes.h | 7 +- src/server/terrain_gen.c | 55 ++++--- src/server/terrain_gen.h | 1 + src/server/trees.c | 214 ++++++++++++------------ src/server/voxel_depth_search.c | 37 +++++ src/server/voxel_depth_search.h | 22 +++ src/server/voxel_procedural.c | 278 ++++++++++++++++++++++++++++++++ src/server/voxel_procedural.h | 50 ++++++ src/server/voxelctx.c | 272 ------------------------------- src/server/voxelctx.h | 50 ------ src/terrain.h | 6 +- 16 files changed, 638 insertions(+), 506 deletions(-) create mode 100644 src/server/voxel_depth_search.c create mode 100644 src/server/voxel_depth_search.h create mode 100644 src/server/voxel_procedural.c create mode 100644 src/server/voxel_procedural.h delete mode 100644 src/server/voxelctx.c delete mode 100644 src/server/voxelctx.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index df59104..fe2de51 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -140,7 +140,8 @@ add_executable(dragonblocks_server server/server_terrain.c server/terrain_gen.c server/trees.c - server/voxelctx.c + server/voxel_depth_search.c + server/voxel_procedural.c ) target_link_libraries(dragonblocks_server diff --git a/src/client/client_node.c b/src/client/client_node.c index 9700590..3a40619 100644 --- a/src/client/client_node.c +++ b/src/client/client_node.c @@ -29,8 +29,8 @@ static void render_grass(NodeArgsRender *args) static void render_stone(NodeArgsRender *args) { - args->vertex.cube.textureCoordinates.x += noise2d(args->pos.x, args->pos.z, 0, seed + SO_TEXTURE_OFFSET_S); - args->vertex.cube.textureCoordinates.y += noise2d(args->pos.x, args->pos.z, 0, seed + SO_TEXTURE_OFFSET_T); + args->vertex.cube.textureCoordinates.x += noise2d(args->pos.x, args->pos.z, 0, seed + OFFSET_TEXTURE_OFFSET_S); + args->vertex.cube.textureCoordinates.y += noise2d(args->pos.x, args->pos.z, 0, seed + OFFSET_TEXTURE_OFFSET_T); } static void render_color(NodeArgsRender *args) diff --git a/src/environment.c b/src/environment.c index 5341603..200eee7 100644 --- a/src/environment.c +++ b/src/environment.c @@ -3,10 +3,10 @@ f64 get_humidity(v3s32 pos) { - return smooth2d(U32(pos.x) / 128.0, U32(pos.z) / 128.0, 0, seed + SO_WETNESS) * 0.5 + 0.5; + return smooth2d(U32(pos.x) / 128.0, U32(pos.z) / 128.0, 0, seed + OFFSET_WETNESS) * 0.5 + 0.5; } f64 get_temperature(v3s32 pos) { - return smooth2d(U32(pos.x) / 128.0, U32(pos.z) / 128.0, 0, seed + SO_TEMPERATURE) * 0.5 + 0.5 - (pos.y - 32.0) / 64.0; + return smooth2d(U32(pos.x) / 128.0, U32(pos.z) / 128.0, 0, seed + OFFSET_TEMPERATURE) * 0.5 + 0.5 - (pos.y - 32.0) / 64.0; } diff --git a/src/perlin.h b/src/perlin.h index 15a63c9..2aab5e1 100644 --- a/src/perlin.h +++ b/src/perlin.h @@ -7,31 +7,31 @@ #define U32(x) (((u32) 1 << 31) + (x)) typedef enum { - SO_NONE, - SO_HEIGHT, - SO_MOUNTAIN, - SO_OCEAN, - SO_MOUNTAIN_HEIGHT, - SO_BOULDER, - SO_WETNESS, - SO_TEXTURE_OFFSET_S, - SO_TEXTURE_OFFSET_T, - SO_TEMPERATURE, - SO_VULCANO, - SO_VULCANO_HEIGHT, - SO_VULCANO_STONE, - SO_VULCANO_CRATER_TOP, - SO_HILLYNESS, - SO_VOXELCTX, - SO_OAKTREE, - SO_OAKTREE_AREA, - SO_PINETREE, - SO_PINETREE_AREA, - SO_PINETREE_HEIGHT, - SO_PINETREE_BRANCH, - SO_PINETREE_BRANCH_DIR, - SO_PALMTREE, - SO_PALMTREE_AREA, + OFFSET_NONE, + OFFSET_HEIGHT, + OFFSET_MOUNTAIN, + OFFSET_OCEAN, + OFFSET_MOUNTAIN_HEIGHT, + OFFSET_BOULDER, + OFFSET_WETNESS, + OFFSET_TEXTURE_OFFSET_S, + OFFSET_TEXTURE_OFFSET_T, + OFFSET_TEMPERATURE, + OFFSET_VULCANO, + OFFSET_VULCANO_HEIGHT, + OFFSET_VULCANO_STONE, + OFFSET_VULCANO_CRATER_TOP, + OFFSET_HILLYNESS, + OFFSET_VOXEL_PROCEDURAL, + OFFSET_OAKTREE, + OFFSET_OAKTREE_AREA, + OFFSET_PINETREE, + OFFSET_PINETREE_AREA, + OFFSET_PINETREE_HEIGHT, + OFFSET_PINETREE_BRANCH, + OFFSET_PINETREE_BRANCH_DIR, + OFFSET_PALMTREE, + OFFSET_PALMTREE_AREA, } SeedOffset; extern s32 seed; diff --git a/src/server/biomes.c b/src/server/biomes.c index fb0aea7..c034257 100644 --- a/src/server/biomes.c +++ b/src/server/biomes.c @@ -1,7 +1,10 @@ #include +#include +#include #include "server/biomes.h" #include "server/server_terrain.h" #include "server/terrain_gen.h" +#include "server/voxel_depth_search.h" Biome get_biome(v2s32 pos, f64 *factor) { @@ -24,7 +27,7 @@ Biome get_biome(v2s32 pos, f64 *factor) static s32 height_mountain(BiomeArgsHeight *args) { - return pow((args->height + 96) * pow(((smooth2d(U32(args->pos.x) / 48.0, U32(args->pos.y) / 48.0, 0, seed + SO_MOUNTAIN_HEIGHT) + 1.0) * 256.0 + 128.0), args->factor), 1.0 / (args->factor + 1.0)) - 96; + return pow((args->height + 96) * pow(((smooth2d(U32(args->pos.x) / 48.0, U32(args->pos.y) / 48.0, 0, seed + OFFSET_MOUNTAIN_HEIGHT) + 1.0) * 256.0 + 128.0), args->factor), 1.0 / (args->factor + 1.0)) - 96; } static NodeType generate_mountain(BiomeArgsGenerate *args) @@ -113,7 +116,7 @@ static s32 calculate_ocean_floor(f64 factor, s32 height) return height; } -static void chunk_ocean(BiomeArgsChunk *args) +static void before_chunk_ocean(BiomeArgsChunk *args) { OceanChunkData *chunk_data = args->chunk_data; @@ -123,12 +126,12 @@ static void chunk_ocean(BiomeArgsChunk *args) }; f64 factor; - chunk_data->has_vulcano = noise2d(chunk_data->vulcano_pos.x, chunk_data->vulcano_pos.y, 0, seed + SO_VULCANO) > 0.0 + chunk_data->has_vulcano = noise2d(chunk_data->vulcano_pos.x, chunk_data->vulcano_pos.y, 0, seed + OFFSET_VULCANO) > 0.0 && get_biome((v2s32) {chunk_data->vulcano_pos.x, chunk_data->vulcano_pos.y}, &factor) == BIOME_OCEAN && get_ocean_level(factor) == OCEAN_DEEP; } -static void row_ocean(BiomeArgsRow *args) +static void before_row_ocean(BiomeArgsRow *args) { OceanChunkData *chunk_data = args->chunk_data; OceanRowData *row_data = args->row_data; @@ -140,7 +143,7 @@ static void row_ocean(BiomeArgsRow *args) if (dist < vulcano_radius) { f64 crater_factor = pow(asin(1.0 - dist / vulcano_radius), 2.0); - f64 vulcano_height = (pnoise2d(U32(args->pos.x) / 100.0, U32(args->pos.y) / 100.0, 0.2, 2, seed + SO_VULCANO_HEIGHT) * 0.5 + 0.5) * 128.0 * crater_factor + 1.0 - 30.0; + f64 vulcano_height = (pnoise2d(U32(args->pos.x) / 100.0, U32(args->pos.y) / 100.0, 0.2, 2, seed + OFFSET_VULCANO_HEIGHT) * 0.5 + 0.5) * 128.0 * crater_factor + 1.0 - 30.0; bool is_crater = vulcano_height > 0; if (!is_crater) @@ -152,9 +155,9 @@ static void row_ocean(BiomeArgsRow *args) row_data->vulcano = true; row_data->vulcano_crater = is_crater; row_data->vulcano_height = floor(vulcano_height + 0.5); - row_data->vulcano_crater_top = 50 + floor((pnoise2d(U32(args->pos.x) / 3.0, U32(args->pos.y) / 3.0, 0.0, 1, seed + SO_VULCANO_CRATER_TOP) * 0.5 + 0.5) * 3.0 + 0.5); + row_data->vulcano_crater_top = 50 + floor((pnoise2d(U32(args->pos.x) / 3.0, U32(args->pos.y) / 3.0, 0.0, 1, seed + OFFSET_VULCANO_CRATER_TOP) * 0.5 + 0.5) * 3.0 + 0.5); row_data->vulcano_stone = is_crater - ? ((pnoise2d(U32(args->pos.x) / 16.0, U32(args->pos.y) / 16.0, 0.85, 3, seed + SO_VULCANO_STONE) * 0.5 + 0.5) * crater_factor > 0.4 + ? ((pnoise2d(U32(args->pos.x) / 16.0, U32(args->pos.y) / 16.0, 0.85, 3, seed + OFFSET_VULCANO_STONE) * 0.5 + 0.5) * crater_factor > 0.4 ? NODE_VULCANO_STONE : NODE_STONE) : NODE_SAND; @@ -200,14 +203,27 @@ static NodeType generate_ocean(BiomeArgsGenerate *args) // hills biome -static bool boulder_touching_ground(v3s32 pos, s32 diff) +typedef struct { + Tree boulder_visit; + bool boulder_success[CHUNK_SIZE][CHUNK_SIZE][CHUNK_SIZE]; +} HillsChunkData; + +static void before_chunk_hills(BiomeArgsChunk *args) { - for (s32 dir = diff > 0 ? -1 : +1; dir > 0 ? diff <= 0 : diff >= 0; pos.y += dir, diff += dir) { - if (smooth3d(U32(pos.x) / 12.0, U32(pos.y) / 6.0, U32(pos.z) / 12.0, 0, seed + SO_BOULDER) < 0.8) - return false; - } + HillsChunkData *chunk_data = args->chunk_data; + tree_ini(&chunk_data->boulder_visit); + memset(chunk_data->boulder_success, 0, sizeof chunk_data->boulder_success); +} - return true; +static void wrap_free(void *ptr) +{ + free(ptr); +} + +static void after_chunk_hills(BiomeArgsChunk *args) +{ + HillsChunkData *chunk_data = args->chunk_data; + tree_clr(&chunk_data->boulder_visit, &wrap_free, NULL, NULL, 0); } static s32 height_hills(BiomeArgsHeight *args) @@ -215,9 +231,30 @@ static s32 height_hills(BiomeArgsHeight *args) return args->height; } +static bool is_boulder(s32 diff, v3s32 pos) +{ + return diff < 16 && + smooth3d(U32(pos.x) / 16.0, U32(pos.y) / 12.0, U32(pos.z) / 16.0, 0, seed + OFFSET_BOULDER) > 0.8; +} + +static DepthSearchNodeType boulder_get_node_type(v3s32 pos) +{ + s32 diff = pos.y - terrain_gen_get_base_height((v2s32) {pos.x, pos.z}); + + if (diff <= 0) + return DEPTH_SEARCH_TARGET; + + return is_boulder(diff, pos) ? DEPTH_SEARCH_PATH : DEPTH_SEARCH_BLOCK; +} + static NodeType generate_hills(BiomeArgsGenerate *args) { - if (boulder_touching_ground(args->pos, args->diff)) + HillsChunkData *chunk_data = args->chunk_data; + + if (is_boulder(args->diff, args->pos) && (args->diff <= 0 || voxel_depth_search(args->pos, + &boulder_get_node_type, + &chunk_data->boulder_success[args->offset.x][args->offset.y][args->offset.z], + &chunk_data->boulder_visit))) return NODE_STONE; if (args->diff <= -5) @@ -233,38 +270,44 @@ static NodeType generate_hills(BiomeArgsGenerate *args) BiomeDef biomes[COUNT_BIOME] = { { .probability = 0.2, - .offset = SO_MOUNTAIN, + .offset = OFFSET_MOUNTAIN, .threshold = 1024.0, .snow = true, .height = &height_mountain, .generate = &generate_mountain, .chunk_data_size = 0, - .chunk = NULL, + .before_chunk = NULL, + .after_chunk = NULL, .row_data_size = 0, - .row = NULL, + .before_row = NULL, + .after_row = NULL, }, { .probability = 0.2, - .offset = SO_OCEAN, + .offset = OFFSET_OCEAN, .threshold = 2048.0, .snow = false, .height = &height_ocean, .generate = &generate_ocean, .chunk_data_size = sizeof(OceanChunkData), - .chunk = &chunk_ocean, + .before_chunk = &before_chunk_ocean, + .after_chunk = NULL, .row_data_size = sizeof(OceanRowData), - .row = &row_ocean, + .before_row = &before_row_ocean, + .after_row = NULL, }, { .probability = 1.0, - .offset = SO_NONE, + .offset = OFFSET_NONE, .threshold = 0.0, .snow = true, .height = &height_hills, .generate = &generate_hills, - .chunk_data_size = 0, - .chunk = NULL, + .chunk_data_size = sizeof(HillsChunkData), + .before_chunk = &before_chunk_hills, + .after_chunk = &after_chunk_hills, .row_data_size = 0, - .row = NULL, + .before_row = NULL, + .after_row = NULL, }, }; diff --git a/src/server/biomes.h b/src/server/biomes.h index 3994100..dce835d 100644 --- a/src/server/biomes.h +++ b/src/server/biomes.h @@ -34,6 +34,7 @@ typedef struct { } BiomeArgsHeight; typedef struct { + v3s32 offset; v3s32 pos; s32 diff; f64 humidity; @@ -53,9 +54,11 @@ typedef struct { s32 (*height)(BiomeArgsHeight *args); NodeType (*generate)(BiomeArgsGenerate *args); size_t chunk_data_size; - void (*chunk)(BiomeArgsChunk *args); + void (*before_chunk)(BiomeArgsChunk *args); + void (*after_chunk)(BiomeArgsChunk *args); size_t row_data_size; - void (*row)(BiomeArgsRow *args); + void (*before_row)(BiomeArgsRow *args); + void (*after_row)(BiomeArgsRow *args); } BiomeDef; extern BiomeDef biomes[]; diff --git a/src/server/terrain_gen.c b/src/server/terrain_gen.c index 5b0c1d1..b258b1d 100644 --- a/src/server/terrain_gen.c +++ b/src/server/terrain_gen.c @@ -7,6 +7,14 @@ #include "server/terrain_gen.h" #include "server/trees.h" +s32 terrain_gen_get_base_height(v2s32 pos) +{ + return 1.0 + * (pnoise2d(U32(pos.x) / 32.0, U32(pos.y) / 32.0, 0.45, 5, seed + OFFSET_HEIGHT) * 16.0 + 0.0) + * (pnoise2d(U32(pos.x) / 256.0, U32(pos.y) / 256.0, 0.45, 5, seed + OFFSET_HILLYNESS) * 0.5 + 0.5) + + 32.0; +} + // generate a chunk (does not manage chunk state or threading) void terrain_gen_chunk(TerrainChunk *chunk, List *changed_chunks) { @@ -28,12 +36,12 @@ void terrain_gen_chunk(TerrainChunk *chunk, List *changed_chunks) }; unsigned char *chunk_data[COUNT_BIOME] = {NULL}; - bool chunk_called[COUNT_BIOME] = {false}; + bool has_biome[COUNT_BIOME] = {false}; - for (u8 x = 0; x < CHUNK_SIZE; x++) { + for (s32 x = 0; x < CHUNK_SIZE; x++) { s32 pos_x = chunkp.x + x; - for (u8 z = 0; z < CHUNK_SIZE; z++) { + for (s32 z = 0; z < CHUNK_SIZE; z++) { row_args.pos = height_args.pos = (v2s32) {pos_x, chunkp.z + z}; condition_args.biome = get_biome(row_args.pos, &condition_args.factor); @@ -43,32 +51,32 @@ void terrain_gen_chunk(TerrainChunk *chunk, List *changed_chunks) = condition_args.factor; if (biome_def->chunk_data_size && !chunk_data[condition_args.biome]) - chunk_data[condition_args.biome] = malloc(biome_def->chunk_data_size); + chunk_data[condition_args.biome] = malloc(biome_def->chunk_data_size); chunk_args.chunk_data = row_args.chunk_data = height_args.chunk_data = generate_args.chunk_data = condition_args.chunk_data = chunk_data[condition_args.biome]; - if (biome_def->chunk && !chunk_called[condition_args.biome]) { - biome_def->chunk(&chunk_args); - chunk_called[condition_args.biome] = true; + if (!has_biome[condition_args.biome]) { + if (biome_def->before_chunk) + biome_def->before_chunk(&chunk_args); + + has_biome[condition_args.biome] = true; } unsigned char row_data[biome_def->row_data_size]; row_args.row_data = height_args.row_data = generate_args.row_data = condition_args.row_data = row_data; - if (biome_def->row) - biome_def->row(&row_args); - - height_args.height = 1.0 - * (pnoise2d(U32(height_args.pos.x) / 32.0, U32(height_args.pos.y) / 32.0, 0.45, 5, seed + SO_HEIGHT) * 16.0 + 0.0) - * (pnoise2d(U32(height_args.pos.x) / 256.0, U32(height_args.pos.y) / 256.0, 0.45, 5, seed + SO_HILLYNESS) * 0.5 + 0.5) - + 32.0; + if (biome_def->before_row) + biome_def->before_row(&row_args); + height_args.height = terrain_gen_get_base_height(height_args.pos); s32 height = biome_def->height(&height_args); - for (u8 y = 0; y < CHUNK_SIZE; y++) { + for (s32 y = 0; y < CHUNK_SIZE; y++) { + generate_args.offset = (v3s32) {x, y, z}; + generate_args.pos = condition_args.pos = (v3s32) {row_args.pos.x, chunkp.y + y, row_args.pos.y}; generate_args.diff = generate_args.pos.y - height; @@ -104,10 +112,21 @@ void terrain_gen_chunk(TerrainChunk *chunk, List *changed_chunks) } pthread_mutex_unlock(&chunk->mtx); } + + if (biome_def->after_row) + biome_def->after_row(&row_args); } } - for (Biome i = 0; i < COUNT_BIOME; i++) - if (chunk_data[i]) - free(chunk_data[i]); + for (Biome i = 0; i < COUNT_BIOME; i++) { + if (has_biome[i]) { + chunk_args.chunk_data = chunk_data[i]; + + if (biomes[i].after_chunk) + biomes[i].after_chunk(&chunk_args); + + if (chunk_args.chunk_data) + free(chunk_args.chunk_data); + } + } } diff --git a/src/server/terrain_gen.h b/src/server/terrain_gen.h index 76bf813..ce07148 100644 --- a/src/server/terrain_gen.h +++ b/src/server/terrain_gen.h @@ -4,6 +4,7 @@ #include "server/server_terrain.h" #include "terrain.h" +s32 terrain_gen_get_base_height(v2s32 pos); void terrain_gen_chunk(TerrainChunk *chunk, List *changed_chunks); // generate a chunk (does not manage chunk state or threading) #endif // _TERRAIN_GEN_H_ diff --git a/src/server/trees.c b/src/server/trees.c index 4de2285..2d165c2 100644 --- a/src/server/trees.c +++ b/src/server/trees.c @@ -2,7 +2,7 @@ #include "server/biomes.h" #include "server/server_terrain.h" #include "server/trees.h" -#include "server/voxelctx.h" +#include "server/voxel_procedural.h" // oak @@ -11,98 +11,98 @@ static bool oak_condition(TreeArgsCondition *args) return args->biome == BIOME_HILLS; } -static void oak_tree_leaf(Voxelctx *ctx) +static void oak_tree_leaf(VoxelProcedural *proc) { - if (!voxelctx_is_alive(ctx)) + if (!voxel_procedural_is_alive(proc)) return; - voxelctx_push(ctx); - voxelctx_cube(ctx, NODE_OAK_LEAVES, true); - voxelctx_pop(ctx); - - voxelctx_push(ctx); - voxelctx_x(ctx, 0.5f); - voxelctx_sx(ctx, 0.9f); - voxelctx_sy(ctx, 0.9f); - voxelctx_sz(ctx, 0.8f); - voxelctx_ry(ctx, 25.0f); - voxelctx_x(ctx, 0.4f); - oak_tree_leaf(ctx); - voxelctx_pop(ctx); + voxel_procedural_push(proc); + voxel_procedural_cube(proc, NODE_OAK_LEAVES, true); + voxel_procedural_pop(proc); + + voxel_procedural_push(proc); + voxel_procedural_x(proc, 0.5f); + voxel_procedural_sx(proc, 0.9f); + voxel_procedural_sy(proc, 0.9f); + voxel_procedural_sz(proc, 0.8f); + voxel_procedural_ry(proc, 25.0f); + voxel_procedural_x(proc, 0.4f); + oak_tree_leaf(proc); + voxel_procedural_pop(proc); } -static void oak_tree_top(Voxelctx *ctx) +static void oak_tree_top(VoxelProcedural *proc) { - if (!voxelctx_is_alive(ctx)) + if (!voxel_procedural_is_alive(proc)) return; - voxelctx_push(ctx); + voxel_procedural_push(proc); for (int i = 0; i < 8; i++) { - voxelctx_rz(ctx, 360.0f / 8.0f); - voxelctx_push(ctx); - voxelctx_life(ctx, 8); - voxelctx_sy(ctx, 2.0f); - voxelctx_z(ctx, voxelctx_random(ctx, 0.0f, 5.0f)); - voxelctx_s(ctx, 5.0f); - voxelctx_light(ctx, -0.4f); - voxelctx_sat(ctx, 0.5f); - voxelctx_hue(ctx, voxelctx_random(ctx, 60.0f, 20.0f)); - voxelctx_ry(ctx, -45.0f); - oak_tree_leaf(ctx); - voxelctx_pop(ctx); + voxel_procedural_rz(proc, 360.0f / 8.0f); + voxel_procedural_push(proc); + voxel_procedural_life(proc, 8); + voxel_procedural_sy(proc, 2.0f); + voxel_procedural_z(proc, voxel_procedural_random(proc, 0.0f, 5.0f)); + voxel_procedural_s(proc, 5.0f); + voxel_procedural_light(proc, -0.4f); + voxel_procedural_sat(proc, 0.5f); + voxel_procedural_hue(proc, voxel_procedural_random(proc, 60.0f, 20.0f)); + voxel_procedural_ry(proc, -45.0f); + oak_tree_leaf(proc); + voxel_procedural_pop(proc); } - voxelctx_pop(ctx); + voxel_procedural_pop(proc); } -static void oak_tree_part(Voxelctx *ctx, f32 n) +static void oak_tree_part(VoxelProcedural *proc, f32 n) { - if (!voxelctx_is_alive(ctx)) + if (!voxel_procedural_is_alive(proc)) return; - voxelctx_push(ctx); + voxel_procedural_push(proc); for (int i = 1; i <= n; i++) { - voxelctx_z(ctx, 1.0f); - voxelctx_rz(ctx, voxelctx_random(ctx, 30.0f, 10.0f)); - voxelctx_rx(ctx, voxelctx_random(ctx, 0.0f, 10.0f)); + voxel_procedural_z(proc, 1.0f); + voxel_procedural_rz(proc, voxel_procedural_random(proc, 30.0f, 10.0f)); + voxel_procedural_rx(proc, voxel_procedural_random(proc, 0.0f, 10.0f)); - voxelctx_push(ctx); - voxelctx_s(ctx, 4.0f); - voxelctx_x(ctx, 0.1f); - voxelctx_light(ctx, voxelctx_random(ctx, 0.0f, 0.1f)); - voxelctx_cylinder(ctx, NODE_OAK_WOOD, true); - voxelctx_pop(ctx); + voxel_procedural_push(proc); + voxel_procedural_s(proc, 4.0f); + voxel_procedural_x(proc, 0.1f); + voxel_procedural_light(proc, voxel_procedural_random(proc, 0.0f, 0.1f)); + voxel_procedural_cylinder(proc, NODE_OAK_WOOD, true); + voxel_procedural_pop(proc); if (i == (int) (n - 2.0f)) { - voxelctx_push(ctx); - oak_tree_top(ctx); - voxelctx_pop(ctx); + voxel_procedural_push(proc); + oak_tree_top(proc); + voxel_procedural_pop(proc); } } - voxelctx_pop(ctx); + voxel_procedural_pop(proc); } static void oak_tree(v3s32 pos, List *changed_chunks) { - Voxelctx *ctx = voxelctx_create(changed_chunks, STAGE_TREES, pos); + VoxelProcedural *proc = voxel_procedural_create(changed_chunks, STAGE_TREES, pos); - voxelctx_hue(ctx, 40.0f); - voxelctx_light(ctx, -0.5f); - voxelctx_sat(ctx, 0.5f); + voxel_procedural_hue(proc, 40.0f); + voxel_procedural_light(proc, -0.5f); + voxel_procedural_sat(proc, 0.5f); - f32 n = voxelctx_random(ctx, 40.0f, 10.0f); + f32 n = voxel_procedural_random(proc, 40.0f, 10.0f); - voxelctx_push(ctx); + voxel_procedural_push(proc); for (int i = 1; i <= 3; i++) { - voxelctx_rz(ctx, voxelctx_random(ctx, 120.0f, 45.0f)); - voxelctx_push(ctx); - voxelctx_y(ctx, 0.5f); - voxelctx_light(ctx, voxelctx_random(ctx, -0.3f, 0.05f)); - oak_tree_part(ctx, n); - voxelctx_pop(ctx); + voxel_procedural_rz(proc, voxel_procedural_random(proc, 120.0f, 45.0f)); + voxel_procedural_push(proc); + voxel_procedural_y(proc, 0.5f); + voxel_procedural_light(proc, voxel_procedural_random(proc, -0.3f, 0.05f)); + oak_tree_part(proc, n); + voxel_procedural_pop(proc); } - voxelctx_pop(ctx); + voxel_procedural_pop(proc); - voxelctx_delete(ctx); + voxel_procedural_delete(proc); } // pine @@ -114,9 +114,9 @@ static bool pine_condition(TreeArgsCondition *args) static void pine_tree(v3s32 pos, List *changed_chunks) { - s32 tree_top = (noise2d(pos.x, pos.z, 0, seed + SO_PINETREE_HEIGHT) * 0.5 + 0.5) * (35.0 - 20.0) + 20.0 + pos.y; + s32 tree_top = (noise2d(pos.x, pos.z, 0, seed + OFFSET_PINETREE_HEIGHT) * 0.5 + 0.5) * (35.0 - 20.0) + 20.0 + pos.y; for (v3s32 tree_pos = pos; tree_pos.y < tree_top; tree_pos.y++) { - f64 branch_length = noise3d(tree_pos.x, tree_pos.y, tree_pos.z, 0, seed + SO_PINETREE_BRANCH) * 3.0; + f64 branch_length = noise3d(tree_pos.x, tree_pos.y, tree_pos.z, 0, seed + OFFSET_PINETREE_BRANCH) * 3.0; v3s32 dirs[4] = { {+0, +0, +1}, @@ -125,7 +125,7 @@ static void pine_tree(v3s32 pos, List *changed_chunks) {-1, +0, +0}, }; - s32 dir = (noise3d(tree_pos.x, tree_pos.y, tree_pos.z, 0, seed + SO_PINETREE_BRANCH_DIR) * 0.5 + 0.5) * 4.0; + s32 dir = (noise3d(tree_pos.x, tree_pos.y, tree_pos.z, 0, seed + OFFSET_PINETREE_BRANCH_DIR) * 0.5 + 0.5) * 4.0; for (v3s32 branch_pos = tree_pos; branch_length > 0; branch_length--, branch_pos = v3s32_add(branch_pos, dirs[dir])) server_terrain_gen_node(branch_pos, @@ -147,58 +147,58 @@ static bool palm_condition(TreeArgsCondition *args) && ocean_get_node_at((v3s32) {args->pos.x, args->pos.y - 1, args->pos.z}, 0, args->row_data) == NODE_SAND; } -static void palm_branch(Voxelctx *ctx) +static void palm_branch(VoxelProcedural *proc) { - if (!voxelctx_is_alive(ctx)) + if (!voxel_procedural_is_alive(proc)) return; - voxelctx_cube(ctx, NODE_PALM_LEAVES, true); - voxelctx_push(ctx); - voxelctx_z(ctx, 0.5f); - voxelctx_s(ctx, 0.8f); - voxelctx_rx(ctx, voxelctx_random(ctx, 20.0f, 4.0f)); - voxelctx_z(ctx, 0.5f); - palm_branch(ctx); - voxelctx_pop(ctx); + voxel_procedural_cube(proc, NODE_PALM_LEAVES, true); + voxel_procedural_push(proc); + voxel_procedural_z(proc, 0.5f); + voxel_procedural_s(proc, 0.8f); + voxel_procedural_rx(proc, voxel_procedural_random(proc, 20.0f, 4.0f)); + voxel_procedural_z(proc, 0.5f); + palm_branch(proc); + voxel_procedural_pop(proc); } static void palm_tree(v3s32 pos, List *changed_chunks) { - Voxelctx *ctx = voxelctx_create(changed_chunks, STAGE_TREES, (v3s32) {pos.x, pos.y - 1, pos.z}); + VoxelProcedural *proc = voxel_procedural_create(changed_chunks, STAGE_TREES, (v3s32) {pos.x, pos.y - 1, pos.z}); - f32 s = voxelctx_random(ctx, 8.0f, 2.0f); + f32 s = voxel_procedural_random(proc, 8.0f, 2.0f); - voxelctx_push(ctx); + voxel_procedural_push(proc); for (int i = 1; i <= s; i++) { - voxelctx_z(ctx, 1.0f); - voxelctx_push(ctx); - voxelctx_s(ctx, 1.0f); - voxelctx_light(ctx, voxelctx_random(ctx, -0.8f, 0.1f)); - voxelctx_sat(ctx, 0.5f); - voxelctx_cube(ctx, NODE_PALM_WOOD, true); - voxelctx_pop(ctx); + voxel_procedural_z(proc, 1.0f); + voxel_procedural_push(proc); + voxel_procedural_s(proc, 1.0f); + voxel_procedural_light(proc, voxel_procedural_random(proc, -0.8f, 0.1f)); + voxel_procedural_sat(proc, 0.5f); + voxel_procedural_cube(proc, NODE_PALM_WOOD, true); + voxel_procedural_pop(proc); } - voxelctx_pop(ctx); + voxel_procedural_pop(proc); - voxelctx_z(ctx, s); - voxelctx_sat(ctx, 1.0f), - voxelctx_light(ctx, -0.5f); - voxelctx_hue(ctx, voxelctx_random(ctx, 50.0f, 30.0f)); + voxel_procedural_z(proc, s); + voxel_procedural_sat(proc, 1.0f), + voxel_procedural_light(proc, -0.5f); + voxel_procedural_hue(proc, voxel_procedural_random(proc, 50.0f, 30.0f)); - voxelctx_push(ctx); + voxel_procedural_push(proc); for (int i = 0; i < 6; i++) { - voxelctx_rz(ctx, 360.0f / 6.0f); - voxelctx_rz(ctx, voxelctx_random(ctx, 0.0f, 10.0f)); - voxelctx_push(ctx); - voxelctx_light(ctx, voxelctx_random(ctx, 0.0f, 0.3f)); - voxelctx_rx(ctx, 90.0f); - voxelctx_s(ctx, 2.0f); - palm_branch(ctx); - voxelctx_pop(ctx); + voxel_procedural_rz(proc, 360.0f / 6.0f); + voxel_procedural_rz(proc, voxel_procedural_random(proc, 0.0f, 10.0f)); + voxel_procedural_push(proc); + voxel_procedural_light(proc, voxel_procedural_random(proc, 0.0f, 0.3f)); + voxel_procedural_rx(proc, 90.0f); + voxel_procedural_s(proc, 2.0f); + palm_branch(proc); + voxel_procedural_pop(proc); } - voxelctx_pop(ctx); + voxel_procedural_pop(proc); - voxelctx_delete(ctx); + voxel_procedural_delete(proc); } TreeDef tree_definitions[NUM_TREES] = { @@ -207,8 +207,8 @@ TreeDef tree_definitions[NUM_TREES] = { .spread = 64.0f, .probability = 0.0005f, .area_probability = 0.3f, - .offset = SO_OAKTREE, - .area_offset = SO_OAKTREE_AREA, + .offset = OFFSET_OAKTREE, + .area_offset = OFFSET_OAKTREE_AREA, .condition = &oak_condition, .generate = &oak_tree, }, @@ -217,8 +217,8 @@ TreeDef tree_definitions[NUM_TREES] = { .spread = 256.0f, .probability = 0.01f, .area_probability = 0.1f, - .offset = SO_PINETREE, - .area_offset = SO_PINETREE_AREA, + .offset = OFFSET_PINETREE, + .area_offset = OFFSET_PINETREE_AREA, .condition = &pine_condition, .generate = &pine_tree, }, @@ -227,8 +227,8 @@ TreeDef tree_definitions[NUM_TREES] = { .spread = 16.0f, .probability = 0.005f, .area_probability = 0.5f, - .offset = SO_PALMTREE, - .area_offset = SO_PALMTREE_AREA, + .offset = OFFSET_PALMTREE, + .area_offset = OFFSET_PALMTREE_AREA, .condition = &palm_condition, .generate = &palm_tree, }, diff --git a/src/server/voxel_depth_search.c b/src/server/voxel_depth_search.c new file mode 100644 index 0000000..722aeda --- /dev/null +++ b/src/server/voxel_depth_search.c @@ -0,0 +1,37 @@ +#include +#include "voxel_depth_search.h" + +v3s32 dirs[6] = { + {+0, -1, +0}, // this is commonly used to find ground, search downwards first + {-1, +0, +0}, + {+0, +0, -1}, + {+1, +0, +0}, + {+0, +0, +1}, + {+0, +1, +0}, +}; + +static int cmp_depth_search_node(const DepthSearchNode *node, const v3s32 *pos) +{ + return v3s32_cmp(&node->pos, pos); +} + +bool voxel_depth_search(v3s32 pos, DepthSearchNodeType (*get_type)(v3s32 pos), bool *success, Tree *visit) +{ + TreeNode **tree_node = tree_nfd(visit, &pos, &cmp_depth_search_node); + if (*tree_node) + return *success = *((DepthSearchNode *) (*tree_node)->dat)->success; + + DepthSearchNode *node = malloc(sizeof *node); + tree_nmk(visit, tree_node, node); + node->type = get_type(pos); + node->pos = pos; + if ((*(node->success = success) = (node->type == DEPTH_SEARCH_TARGET))) + return true; + + if (node->type == DEPTH_SEARCH_PATH) + for (int i = 0; i < 6; i++) + if (voxel_depth_search(v3s32_add(pos, dirs[i]), get_type, success, visit)) + return true; + + return false; +} diff --git a/src/server/voxel_depth_search.h b/src/server/voxel_depth_search.h new file mode 100644 index 0000000..2712707 --- /dev/null +++ b/src/server/voxel_depth_search.h @@ -0,0 +1,22 @@ +#ifndef _VOXEL_DEPTH_SEARCH_ +#define _VOXEL_DEPTH_SEARCH_ + +#include +#include +#include "types.h" + +typedef enum { + DEPTH_SEARCH_TARGET, // goal has been reached + DEPTH_SEARCH_PATH, // can used this as path + DEPTH_SEARCH_BLOCK // cannot use this as paths +} DepthSearchNodeType; + +typedef struct { + v3s32 pos; + DepthSearchNodeType type; + bool *success; +} DepthSearchNode; + +bool voxel_depth_search(v3s32 pos, DepthSearchNodeType (*get_type)(v3s32 pos), bool *success, Tree *visit); + +#endif // _VOXEL_DEPTH_SEARCH_ diff --git a/src/server/voxel_procedural.c b/src/server/voxel_procedural.c new file mode 100644 index 0000000..ff61ea8 --- /dev/null +++ b/src/server/voxel_procedural.c @@ -0,0 +1,278 @@ +#include +#include +#include "color.h" +#include "perlin.h" +#include "server/terrain_gen.h" +#include "server/voxel_procedural.h" + +#define VOXEL_PROCEDURAL_STATE(proc) (*((VoxelProceduralState *) (proc)->state.fst->dat)) + +static VoxelProceduralState *create_state(VoxelProceduralState *old) +{ + VoxelProceduralState *state = malloc(sizeof *state); + + if (old) { + *state = *old; + } else { + state->pos[0] = 0.0f; + state->pos[1] = 0.0f; + state->pos[2] = 0.0f; + state->pos[3] = 0.0f; + state->scale[0] = 1.0f; + state->scale[1] = 1.0f; + state->scale[2] = 1.0f; + mat4x4_identity(state->mat); + state->h = 0.0f; + state->s = 0.0f; + state->l = 1.0f; + state->life = 0; + } + + return state; +} + +VoxelProcedural *voxel_procedural_create(List *changed_chunks, TerrainGenStage tgs, v3s32 pos) +{ + VoxelProcedural *proc = malloc(sizeof(VoxelProcedural)); + + proc->changed_chunks = changed_chunks; + proc->tgs = tgs; + proc->pos = pos; + proc->random = 0; + + list_ini(&proc->state); + list_apd(&proc->state, create_state(NULL)); + + return proc; +} + +void voxel_procedural_delete(VoxelProcedural *proc) +{ + list_clr(&proc->state, &free, NULL, NULL); + free(proc); +} + +static void move_value(f32 *x, f32 v, f32 range) +{ + f32 dst = v >= 0 ? range : 0; + v = fabs(v); + *x = f32_mix(*x, dst, v); +} + +void voxel_procedural_hue(VoxelProcedural *proc, f32 value) +{ + VOXEL_PROCEDURAL_STATE(proc).h += value; +} + +void voxel_procedural_sat(VoxelProcedural *proc, f32 value) +{ + move_value(&VOXEL_PROCEDURAL_STATE(proc).s, value, 1.0f); +} + +void voxel_procedural_light(VoxelProcedural *proc, f32 value) +{ + move_value(&VOXEL_PROCEDURAL_STATE(proc).l, value, 1.0f); +} + +void voxel_procedural_life(VoxelProcedural *proc, s32 value) +{ + VOXEL_PROCEDURAL_STATE(proc).life += value; +} + +static void apply_translation(VoxelProcedural *proc, v3f32 translate) +{ + vec4 dst, src = {translate.x, translate.y, translate.z, 0.0f}; + mat4x4_mul_vec4(dst, VOXEL_PROCEDURAL_STATE(proc).mat, src); + vec4_add(VOXEL_PROCEDURAL_STATE(proc).pos, VOXEL_PROCEDURAL_STATE(proc).pos, dst); +} + +void voxel_procedural_x(VoxelProcedural *proc, f32 value) +{ + apply_translation(proc, (v3f32) {value, 0.0f, 0.0f}); +} + +void voxel_procedural_y(VoxelProcedural *proc, f32 value) +{ + apply_translation(proc, (v3f32) {0.0f, value, 0.0f}); +} + +void voxel_procedural_z(VoxelProcedural *proc, f32 value) +{ + apply_translation(proc, (v3f32) {0.0f, 0.0f, value}); +} + +void voxel_procedural_rx(VoxelProcedural *proc, f32 value) +{ + mat4x4_rotate_X(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat, + value * M_PI / 180.0f); +} + +void voxel_procedural_ry(VoxelProcedural *proc, f32 value) +{ + mat4x4_rotate_Y(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat, + value * M_PI / 180.0f); +} + +void voxel_procedural_rz(VoxelProcedural *proc, f32 value) +{ + mat4x4_rotate_Z(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat, + value * M_PI / 180.0f); +} + +static void apply_scale(VoxelProcedural *proc, v3f32 scale) +{ + VOXEL_PROCEDURAL_STATE(proc).scale[0] *= scale.x; + VOXEL_PROCEDURAL_STATE(proc).scale[1] *= scale.y; + VOXEL_PROCEDURAL_STATE(proc).scale[2] *= scale.z; + + mat4x4_scale_aniso(VOXEL_PROCEDURAL_STATE(proc).mat, VOXEL_PROCEDURAL_STATE(proc).mat, + scale.x, scale.y, scale.z); +} + +void voxel_procedural_sx(VoxelProcedural *proc, f32 value) +{ + apply_scale(proc, (v3f32) {value, 1.0f, 1.0f}); +} + +void voxel_procedural_sy(VoxelProcedural *proc, f32 value) +{ + apply_scale(proc, (v3f32) {1.0f, value, 1.0f}); +} + +void voxel_procedural_sz(VoxelProcedural *proc, f32 value) +{ + apply_scale(proc, (v3f32) {1.0f, 1.0f, value}); +} + +void voxel_procedural_s(VoxelProcedural *proc, f32 value) +{ + apply_scale(proc, (v3f32) {value, value, value}); +} + +void voxel_procedural_pop(VoxelProcedural *proc) +{ + free(proc->state.fst->dat); + list_nrm(&proc->state, &proc->state.fst); +} + +void voxel_procedural_push(VoxelProcedural *proc) +{ + list_ppd(&proc->state, create_state(&VOXEL_PROCEDURAL_STATE(proc))); +} + +bool voxel_procedural_is_alive(VoxelProcedural *proc) +{ + if (VOXEL_PROCEDURAL_STATE(proc).life > 0 && --VOXEL_PROCEDURAL_STATE(proc).life <= 0) + return false; + + return + VOXEL_PROCEDURAL_STATE(proc).scale[0] >= 1.0f && + VOXEL_PROCEDURAL_STATE(proc).scale[1] >= 1.0f && + VOXEL_PROCEDURAL_STATE(proc).scale[2] >= 1.0f; +} + +void voxel_procedural_cube(VoxelProcedural *proc, NodeType node, bool use_color) +{ + if (!voxel_procedural_is_alive(proc)) + return; + + vec4 base_corners[8] = { + {0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 1.0f, 0.0f}, + {1.0f, 0.0f, 0.0f, 0.0f}, + {1.0f, 0.0f, 1.0f, 0.0f}, + {1.0f, 1.0f, 0.0f, 0.0f}, + {1.0f, 1.0f, 1.0f, 0.0f}, + }; + + vec4 corners[8]; + + s32 max_len = 0; + + vec4 center; + + mat4x4_mul_vec4(center, VOXEL_PROCEDURAL_STATE(proc).mat, (vec4) {0.5f, 0.5f, 0.5f}); + + for (int i = 0; i < 8; i++) { + mat4x4_mul_vec4(corners[i], VOXEL_PROCEDURAL_STATE(proc).mat, base_corners[i]); + + vec3 from_center; + vec3_sub(from_center, corners[i], center); + + s32 len = ceil(vec3_len(from_center)); + + if (max_len < len) + max_len = len; + } + + for (s32 x = -max_len; x <= +max_len; x++) + for (s32 y = -max_len; y <= +max_len; y++) + for (s32 z = -max_len; z <= +max_len; z++) { + s32 v[3]; + + for (int i = 0; i < 3; i++) { + f32 f = trunc( + + f32_mix(corners[0][i], corners[4][i], (f32) x / (f32) max_len / 2.0f) + + f32_mix(corners[0][i], corners[2][i], (f32) y / (f32) max_len / 2.0f) + + f32_mix(corners[0][i], corners[1][i], (f32) z / (f32) max_len / 2.0f)); + + v[i] = floor(VOXEL_PROCEDURAL_STATE(proc).pos[i] + f + 0.5f); + } + + Blob buffer = {0, NULL}; + + if (use_color) + ColorData_write(&buffer, &(ColorData) {hsl_to_rgb((v3f32) { + VOXEL_PROCEDURAL_STATE(proc).h / 360.0, + VOXEL_PROCEDURAL_STATE(proc).s, + VOXEL_PROCEDURAL_STATE(proc).l, + })}); + + server_terrain_gen_node( + v3s32_add(proc->pos, (v3s32) {v[0], v[2], v[1]}), + terrain_node_create(node, buffer), + proc->tgs, + proc->changed_chunks + ); + + Blob_free(&buffer); + } +} + + +void voxel_procedural_cylinder(VoxelProcedural *proc, NodeType node, bool use_color) +{ + voxel_procedural_cube(proc, node, use_color); +} + +/* +void voxel_procedural_cylinder(VoxelProcedural *proc, Node node, bool use_color) +{ + if (!voxel_procedural_is_alive(proc)) + return; + + return; + + f32 xf = VOXEL_PROCEDURAL_STATE(proc).scale[0] / 2.0f; + for (s32 x = round(-xf + 0.5f); x <= round(xf); x++) { + f32 yf = cos(x / VOXEL_PROCEDURAL_STATE(proc).scale[0] * M_PI) * VOXEL_PROCEDURAL_STATE(proc).scale[1] / 2.0f; + for (s32 y = round(-yf); y <= round(yf); y++) { + f32 zf = VOXEL_PROCEDURAL_STATE(proc).scale[2] / 2.0f; + for (s32 z = round(-zf + 0.5f); z <= round(zf); z++) { + mapgen_set_node((v3s32) { + proc->pos.x + round(VOXEL_PROCEDURAL_STATE(proc).pos[0] + x), + proc->pos.y + round(VOXEL_PROCEDURAL_STATE(proc).pos[2] + z), + proc->pos.z + round(VOXEL_PROCEDURAL_STATE(proc).pos[1] + y), + }, CREATE_NODE, proc->tgs, proc->changed_chunks); + } + } + } +} +*/ + +f32 voxel_procedural_random(VoxelProcedural *proc, f32 base, f32 vary) +{ + return base + noise3d(proc->pos.x, proc->pos.y, proc->pos.z, proc->random++, seed + OFFSET_VOXEL_PROCEDURAL) * vary; +} diff --git a/src/server/voxel_procedural.h b/src/server/voxel_procedural.h new file mode 100644 index 0000000..c953add --- /dev/null +++ b/src/server/voxel_procedural.h @@ -0,0 +1,50 @@ +#ifndef _VOXEL_PROCEDURAL_H_ +#define _VOXEL_PROCEDURAL_H_ + +#include +#include +#include "server/server_terrain.h" +#include "types.h" + +// Note: This is a close reimplementation of goxel procedural scripting capabilities + +typedef struct { + vec4 pos; + vec3 scale; + mat4x4 mat; + f32 h, s, l; + s32 life; +} VoxelProceduralState; + +typedef struct { + v3s32 pos; + List *changed_chunks; + TerrainGenStage tgs; + s32 random; + List state; +} VoxelProcedural; + +VoxelProcedural *voxel_procedural_create(List *changed_chunks, TerrainGenStage tgs, v3s32 pos); +void voxel_procedural_delete(VoxelProcedural *proc); +void voxel_procedural_hue(VoxelProcedural *proc, f32 value); +void voxel_procedural_sat(VoxelProcedural *proc, f32 value); +void voxel_procedural_light(VoxelProcedural *proc, f32 value); +void voxel_procedural_life(VoxelProcedural *proc, s32 value); +void voxel_procedural_x(VoxelProcedural *proc, f32 value); +void voxel_procedural_y(VoxelProcedural *proc, f32 value); +void voxel_procedural_z(VoxelProcedural *proc, f32 value); +void voxel_procedural_rx(VoxelProcedural *proc, f32 value); +void voxel_procedural_ry(VoxelProcedural *proc, f32 value); +void voxel_procedural_rz(VoxelProcedural *proc, f32 value); +void voxel_procedural_sx(VoxelProcedural *proc, f32 value); +void voxel_procedural_sy(VoxelProcedural *proc, f32 value); +void voxel_procedural_sz(VoxelProcedural *proc, f32 value); +void voxel_procedural_s(VoxelProcedural *proc, f32 value); +void voxel_procedural_pop(VoxelProcedural *proc); +void voxel_procedural_push(VoxelProcedural *proc); +bool voxel_procedural_is_alive(VoxelProcedural *proc); +void voxel_procedural_cube(VoxelProcedural *proc, NodeType node, bool use_color); +void voxel_procedural_cylinder(VoxelProcedural *proc, NodeType node, bool use_color); +f32 voxel_procedural_random(VoxelProcedural *proc, f32 base, f32 vary); + +#endif // _VOXEL_PROCEDURAL_H_ diff --git a/src/server/voxelctx.c b/src/server/voxelctx.c deleted file mode 100644 index 7148102..0000000 --- a/src/server/voxelctx.c +++ /dev/null @@ -1,272 +0,0 @@ -#include -#include -#include "color.h" -#include "perlin.h" -#include "server/terrain_gen.h" -#include "server/voxelctx.h" - -static VoxelctxState *create_state(VoxelctxState *old) -{ - VoxelctxState *state = malloc(sizeof *state); - - if (old) { - *state = *old; - } else { - state->pos[0] = 0.0f; - state->pos[1] = 0.0f; - state->pos[2] = 0.0f; - state->pos[3] = 0.0f; - state->scale[0] = 1.0f; - state->scale[1] = 1.0f; - state->scale[2] = 1.0f; - mat4x4_identity(state->mat); - state->h = 0.0f; - state->s = 0.0f; - state->l = 1.0f; - state->life = 0; - } - - return state; -} - -Voxelctx *voxelctx_create(List *changed_chunks, TerrainGenStage tgs, v3s32 pos) -{ - Voxelctx *ctx = malloc(sizeof(Voxelctx)); - - ctx->changed_chunks = changed_chunks; - ctx->tgs = tgs; - ctx->pos = pos; - list_ini(&ctx->statestack); - ctx->random = 0; - - list_apd(&ctx->statestack, create_state(NULL)); - - return ctx; -} - -void voxelctx_delete(Voxelctx *ctx) -{ - list_clr(&ctx->statestack, &free, NULL, NULL); - free(ctx); -} - -static void move_value(f32 *x, f32 v, f32 range) -{ - f32 dst = v >= 0 ? range : 0; - v = fabs(v); - *x = f32_mix(*x, dst, v); -} - -void voxelctx_hue(Voxelctx *ctx, f32 value) -{ - VOXELCTXSTATE(ctx).h += value; -} - -void voxelctx_sat(Voxelctx *ctx, f32 value) -{ - move_value(&VOXELCTXSTATE(ctx).s, value, 1.0f); -} - -void voxelctx_light(Voxelctx *ctx, f32 value) -{ - move_value(&VOXELCTXSTATE(ctx).l, value, 1.0f); -} - -void voxelctx_life(Voxelctx *ctx, s32 value) -{ - VOXELCTXSTATE(ctx).life += value; -} - -static void apply_translation(Voxelctx *ctx, v3f32 translate) -{ - vec4 translate_vec; - mat4x4_mul_vec4(translate_vec, VOXELCTXSTATE(ctx).mat, (vec4) {translate.x, translate.y, translate.z, 0.0f}); - vec4_add(VOXELCTXSTATE(ctx).pos, VOXELCTXSTATE(ctx).pos, translate_vec); -} - -void voxelctx_x(Voxelctx *ctx, f32 value) -{ - apply_translation(ctx, (v3f32) {value, 0.0f, 0.0f}); -} - -void voxelctx_y(Voxelctx *ctx, f32 value) -{ - apply_translation(ctx, (v3f32) {0.0f, value, 0.0f}); -} - -void voxelctx_z(Voxelctx *ctx, f32 value) -{ - apply_translation(ctx, (v3f32) {0.0f, 0.0f, value}); -} - -void voxelctx_rx(Voxelctx *ctx, f32 value) -{ - mat4x4_rotate_X(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, value * M_PI / 180.0f); -} - -void voxelctx_ry(Voxelctx *ctx, f32 value) -{ - mat4x4_rotate_Y(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, value * M_PI / 180.0f); -} - -void voxelctx_rz(Voxelctx *ctx, f32 value) -{ - mat4x4_rotate_Z(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, value * M_PI / 180.0f); -} - -static void apply_scale(Voxelctx *ctx, v3f32 scale) -{ - VOXELCTXSTATE(ctx).scale[0] *= scale.x; - VOXELCTXSTATE(ctx).scale[1] *= scale.y; - VOXELCTXSTATE(ctx).scale[2] *= scale.z; - - mat4x4_scale_aniso(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, scale.x, scale.y, scale.z); -} - -void voxelctx_sx(Voxelctx *ctx, f32 value) -{ - apply_scale(ctx, (v3f32) {value, 1.0f, 1.0f}); -} - -void voxelctx_sy(Voxelctx *ctx, f32 value) -{ - apply_scale(ctx, (v3f32) {1.0f, value, 1.0f}); -} - -void voxelctx_sz(Voxelctx *ctx, f32 value) -{ - apply_scale(ctx, (v3f32) {1.0f, 1.0f, value}); -} - -void voxelctx_s(Voxelctx *ctx, f32 value) -{ - apply_scale(ctx, (v3f32) {value, value, value}); -} - -void voxelctx_pop(Voxelctx *ctx) -{ - free(ctx->statestack.fst->dat); - list_nrm(&ctx->statestack, &ctx->statestack.fst); -} - -void voxelctx_push(Voxelctx *ctx) -{ - list_ppd(&ctx->statestack, create_state(&VOXELCTXSTATE(ctx))); -} - -bool voxelctx_is_alive(Voxelctx *ctx) -{ - if (VOXELCTXSTATE(ctx).life > 0) { - VOXELCTXSTATE(ctx).life--; - if (VOXELCTXSTATE(ctx).life <= 0) - return false; - } - - return VOXELCTXSTATE(ctx).scale[0] >= 1.0f && VOXELCTXSTATE(ctx).scale[1] >= 1.0f && VOXELCTXSTATE(ctx).scale[2] >= 1.0f; -} - -void voxelctx_cube(Voxelctx *ctx, NodeType node, bool use_color) -{ - if (!voxelctx_is_alive(ctx)) - return; - - vec4 base_corners[8] = { - {0.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - {0.0f, 1.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 1.0f, 0.0f}, - {1.0f, 0.0f, 0.0f, 0.0f}, - {1.0f, 0.0f, 1.0f, 0.0f}, - {1.0f, 1.0f, 0.0f, 0.0f}, - {1.0f, 1.0f, 1.0f, 0.0f}, - }; - - vec4 corners[8]; - - s32 max_len = 0; - - vec4 center; - - mat4x4_mul_vec4(center, VOXELCTXSTATE(ctx).mat, (vec4) {0.5f, 0.5f, 0.5f}); - - for (int i = 0; i < 8; i++) { - mat4x4_mul_vec4(corners[i], VOXELCTXSTATE(ctx).mat, base_corners[i]); - - vec3 from_center; - vec3_sub(from_center, corners[i], center); - - s32 len = ceil(vec3_len(from_center)); - - if (max_len < len) - max_len = len; - } - - for (s32 x = -max_len; x <= +max_len; x++) - for (s32 y = -max_len; y <= +max_len; y++) - for (s32 z = -max_len; z <= +max_len; z++) { - s32 v[3]; - - for (int i = 0; i < 3; i++) { - f32 f = trunc( - + f32_mix(corners[0][i], corners[4][i], (f32) x / (f32) max_len / 2.0f) - + f32_mix(corners[0][i], corners[2][i], (f32) y / (f32) max_len / 2.0f) - + f32_mix(corners[0][i], corners[1][i], (f32) z / (f32) max_len / 2.0f)); - - v[i] = floor(VOXELCTXSTATE(ctx).pos[i] + f + 0.5f); - } - - Blob buffer = {0, NULL}; - - if (use_color) - ColorData_write(&buffer, &(ColorData) {hsl_to_rgb((v3f32) { - VOXELCTXSTATE(ctx).h / 360.0, - VOXELCTXSTATE(ctx).s, - VOXELCTXSTATE(ctx).l, - })}); - - server_terrain_gen_node( - v3s32_add(ctx->pos, (v3s32) {v[0], v[2], v[1]}), - terrain_node_create(node, buffer), - ctx->tgs, - ctx->changed_chunks - ); - - Blob_free(&buffer); - } -} - - -void voxelctx_cylinder(Voxelctx *ctx, NodeType node, bool use_color) -{ - voxelctx_cube(ctx, node, use_color); -} - -/* -void voxelctx_cylinder(Voxelctx *ctx, Node node, bool use_color) -{ - if (!voxelctx_is_alive(ctx)) - return; - - return; - - f32 xf = VOXELCTXSTATE(ctx).scale[0] / 2.0f; - for (s32 x = round(-xf + 0.5f); x <= round(xf); x++) { - f32 yf = cos(x / VOXELCTXSTATE(ctx).scale[0] * M_PI) * VOXELCTXSTATE(ctx).scale[1] / 2.0f; - for (s32 y = round(-yf); y <= round(yf); y++) { - f32 zf = VOXELCTXSTATE(ctx).scale[2] / 2.0f; - for (s32 z = round(-zf + 0.5f); z <= round(zf); z++) { - mapgen_set_node((v3s32) { - ctx->pos.x + round(VOXELCTXSTATE(ctx).pos[0] + x), - ctx->pos.y + round(VOXELCTXSTATE(ctx).pos[2] + z), - ctx->pos.z + round(VOXELCTXSTATE(ctx).pos[1] + y), - }, CREATE_NODE, ctx->tgs, ctx->changed_chunks); - } - } - } -} -*/ - -f32 voxelctx_random(Voxelctx *ctx, f32 base, f32 vary) -{ - return base + noise3d(ctx->pos.x, ctx->pos.y, ctx->pos.z, ctx->random++, seed + SO_VOXELCTX) * vary; -} diff --git a/src/server/voxelctx.h b/src/server/voxelctx.h deleted file mode 100644 index 2469be0..0000000 --- a/src/server/voxelctx.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _VOXELCTX_H_ -#define _VOXELCTX_H_ - -#define VOXELCTXSTATE(ctx) (*((VoxelctxState *) (ctx)->statestack.fst->dat)) - -#include -#include -#include "server/server_terrain.h" -#include "types.h" - -typedef struct { - vec4 pos; - vec3 scale; - mat4x4 mat; - f32 h, s, l; - s32 life; -} VoxelctxState; - -typedef struct { - v3s32 pos; - List *changed_chunks; - TerrainGenStage tgs; - List statestack; - s32 random; -} Voxelctx; - -Voxelctx *voxelctx_create(List *changed_chunks, TerrainGenStage tgs, v3s32 pos); -void voxelctx_delete(Voxelctx *ctx); -void voxelctx_hue(Voxelctx *ctx, f32 value); -void voxelctx_sat(Voxelctx *ctx, f32 value); -void voxelctx_light(Voxelctx *ctx, f32 value); -void voxelctx_life(Voxelctx *ctx, s32 value); -void voxelctx_x(Voxelctx *ctx, f32 value); -void voxelctx_y(Voxelctx *ctx, f32 value); -void voxelctx_z(Voxelctx *ctx, f32 value); -void voxelctx_rx(Voxelctx *ctx, f32 value); -void voxelctx_ry(Voxelctx *ctx, f32 value); -void voxelctx_rz(Voxelctx *ctx, f32 value); -void voxelctx_sx(Voxelctx *ctx, f32 value); -void voxelctx_sy(Voxelctx *ctx, f32 value); -void voxelctx_sz(Voxelctx *ctx, f32 value); -void voxelctx_s(Voxelctx *ctx, f32 value); -void voxelctx_pop(Voxelctx *ctx); -void voxelctx_push(Voxelctx *ctx); -bool voxelctx_is_alive(Voxelctx *ctx); -void voxelctx_cube(Voxelctx *ctx, NodeType node, bool use_color); -void voxelctx_cylinder(Voxelctx *ctx, NodeType node, bool use_color); -f32 voxelctx_random(Voxelctx *ctx, f32 base, f32 vary); - -#endif // _VOXELCTX_H_ diff --git a/src/terrain.h b/src/terrain.h index 111e175..44098c7 100644 --- a/src/terrain.h +++ b/src/terrain.h @@ -9,9 +9,9 @@ #include "types.h" #define CHUNK_ITERATE \ - for (u8 x = 0; x < CHUNK_SIZE; x++) \ - for (u8 y = 0; y < CHUNK_SIZE; y++) \ - for (u8 z = 0; z < CHUNK_SIZE; z++) + for (s32 x = 0; x < CHUNK_SIZE; x++) \ + for (s32 y = 0; y < CHUNK_SIZE; y++) \ + for (s32 z = 0; z < CHUNK_SIZE; z++) typedef struct TerrainNode { NodeType type; -- 2.44.0