-Subproject commit e2b7d38971a714300ae0edfc0af7e2ef89e433cc
+Subproject commit 5cb6a0956cd87981071f7e3dd5669f9698ac6682
uniform vec3 cameraPos;
uniform sampler2D textures[MAX_TEXTURE_UNITS];
-vec3 hsv2rgb(vec3 c)
-{
- vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
- vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
- return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
-}
-
void main()
{
vec3 lightColor = vec3(1.0);
vec3 light = ambient + diffuse;
- outColor = texture(textures[int(fragmentTextureIndex + 0.5)], fragmentTextureCoords) * vec4(hsv2rgb(vec3(fragmentColor)), 1.0) * vec4(light, 1.0);
+ outColor = texture(textures[int(fragmentTextureIndex + 0.5)], fragmentTextureCoords) * vec4(fragmentColor, 1.0) * vec4(light, 1.0);
outColor.rgb = mix(outColor.rgb, ambientStrength * fogColor, clamp(length(fragmentPosition - cameraPos) / 255.0, 0.0, 1.0));
+
+ if (outColor.a == 0.0)
+ discard;
}
set(DEPS_DIR "${CMAKE_SOURCE_DIR}/../deps/")
-add_compile_definitions(DRAGONTYPE_ENDIAN_HEADER="${CMAKE_SOURCE_DIR}/../deps/endian.h/endian.h")
-
include_directories(SYSTEM
${DEPS_DIR}
)
${CMAKE_SOURCE_DIR}
)
-add_compile_options(-Wall -Wextra -Wpedantic -Werror)
+add_compile_options(-Wall -Wextra -Wpedantic -Werror -fmax-errors=4)
-set(SOURCES_COMMON
+set(DEPS_SOURCES
+ "${DEPS_DIR}/dragontype/array.c"
+ "${DEPS_DIR}/dragontype/bintree.c"
+ "${DEPS_DIR}/dragontype/list.c"
+ "${DEPS_DIR}/dragontype/number.c"
+ "${DEPS_DIR}/dragontype/queue.c"
+ "${DEPS_DIR}/dragonport/asprintf.c"
+ "${DEPS_DIR}/perlin/perlin.c"
+)
+
+set(COMMON_SOURCES
+ ${DEPS_SOURCES}
day.c
environment.c
map.c
perlin.c
signal_handlers.c
util.c
- "${DEPS_DIR}/dragontype/implementation.c"
- "${DEPS_DIR}/dragonport/asprintf.c"
- "${DEPS_DIR}/perlin/perlin.c"
)
add_executable(Dragonblocks
- ${SOURCES_COMMON}
+ ${COMMON_SOURCES}
client/blockmesh.c
client/camera.c
client/client.c
)
add_executable(DragonblocksServer
- ${SOURCES_COMMON}
+ ${COMMON_SOURCES}
server/biomes.c
server/database.c
server/mapgen.c
server/server.c
server/server_commands.c
server/server_map.c
+ server/trees.c
+ server/voxelctx.c
)
target_link_libraries(DragonblocksServer
ITERATE_MAPBLOCK {
MapNode *node = &block->data[x][y][z];
- ClientNodeDefintion *def = &client_node_definitions[node->type];
+ ClientNodeDefinition *def = &client_node_definitions[node->type];
if (def->visibility != NV_NONE) {
v3f32 offset = {
? block->data[npos.x][npos.y][npos.z]
: map_get_node(client_map.map, (v3s32) {npos.x + node_bp.x, npos.y + node_bp.y, npos.z + node_bp.z});
- bool transparency_edge = def->visibility != NV_TRANSPARENT || neighbor.type != node->type;
+ bool transparency_edge = def->visibility != NV_BLEND || neighbor.type != node->type;
- bool render_node = neighbor.type != NODE_UNLOADED
+ bool render_node = def->visibility == NV_CLIP || (neighbor.type != NODE_UNLOADED
&& client_node_definitions[neighbor.type].visibility != NV_SOLID
- && transparency_edge;
+ && transparency_edge);
object->visible = object->visible || render_node;
render_node = transparency_edge;
if (render_node) {
- object->transparent = object->transparent || def->visibility == NV_TRANSPARENT;
+ object->transparent = object->transparent || def->visibility == NV_BLEND;
object_set_texture(object, def->tiles.textures[f]);
for (int v = 0; v < 6; v++) {
obj->pos = (v3f32) {block->pos.x * MAPBLOCK_SIZE + half_block_size + 0.5f, block->pos.y * MAPBLOCK_SIZE + half_block_size + 0.5f, block->pos.z * MAPBLOCK_SIZE + half_block_size + 0.5f};
obj->scale = extra->obj ? extra->obj->scale : (v3f32) {0.1f, 0.1f, 0.1f};
obj->frustum_culling = true;
- obj->box = (aabb3f32) {{-half_block_size - 0.5f, -half_block_size - 0.5f, -half_block_size - 0.5f}, {half_block_size + 0.5f, half_block_size + 0.5f, half_block_size + 0.5f}};
+ obj->box = (aabb3f32) {{-half_block_size - 1.0f, -half_block_size - 1.0f, -half_block_size - 1.0f}, {half_block_size + 1.0f, half_block_size + 1.0f, half_block_size + 1.0f}};
obj->on_render = (obj->scale.x == 1.0f) ? NULL : &animate_mapblock_mesh;
obj->extra = block;
if (! read_v3s32(client->fd, &pos))
return false;
- size_t size;
+ u64 size;
if (! read_u64(client->fd, &size))
return false;
- if (size > sizeof(MapBlockData)) // guard to prevent malicious or malfunctioning packets from allocating huge unnecessary amounts of memory
+ if (size > 1 << 16)
+ return false;
+
+ u64 rawsize;
+
+ if (! read_u64(client->fd, &rawsize))
return false;
char data[size];
else
block = map_allocate_block(pos);
- bool ret = map_deserialize_block(block, data, size);
+ bool ret = map_deserialize_block(block, data, size, rawsize);
if (good)
client_map_block_received(block);
#define TILES_SIMPLE(path) {.paths = {path, NULL, NULL, NULL, NULL, NULL}, .indices = {0, 0, 0, 0, 0, 0}, .textures = {NULL}}
#define TILES_NONE {.paths = {NULL}, .indices = {0}, .textures = {NULL}}
+static f32 hue_to_rgb(f32 p, f32 q, f32 t)
+{
+ if (t < 0.0f)
+ t += 1.0f;
+
+ if (t > 1.0f)
+ t -= 1.0f;
+
+ if (t < 1.0f / 6.0f)
+ return p + (q - p) * 6.0f * t;
+
+ if (t < 1.0f / 2.0f)
+ return q;
+
+ if (t < 2.0f / 3.0f)
+ return p + (q - p) * (2.0f / 3.0f - t) * 6.0f;
+
+ return p;
+}
+
+static Vertex3DColor hsl_to_rgb(v3f32 hsl)
+{
+ Vertex3DColor rgb;
+
+ if (hsl.y == 0.0f) {
+ rgb = (Vertex3DColor) {hsl.z, hsl.z, hsl.z};
+ } else {
+ f32 q = hsl.z < 0.5f ? hsl.z * (1.0f + hsl.y) : hsl.z + hsl.y - hsl.z * hsl.y;
+ f32 p = 2.0f * hsl.z - q;
+
+ rgb.r = hue_to_rgb(p, q, hsl.x + 1.0f / 3.0f);
+ rgb.g = hue_to_rgb(p, q, hsl.x);
+ rgb.b = hue_to_rgb(p, q, hsl.x - 1.0f / 3.0f);
+ }
+
+ return rgb;
+}
+
static void render_grass(v3s32 pos, unused MapNode *node, Vertex3D *vertex, unused int f, unused int v)
{
f32 hum_min, hum_max, temp_max;
f32 temp_f = clamp(0.3f - get_temperature(pos), 0.0f, 0.3f) / 0.3f;
- vertex->color.h = (get_humidity(pos) * (hum_max - hum_min) + hum_min) * (1.0f - temp_f) + temp_max * temp_f;
- vertex->color.s = 1.0f;
- vertex->color.v = 1.0f;
+ vertex->color = hsl_to_rgb((v3f32) {(get_humidity(pos) * (hum_max - hum_min) + hum_min) * (1.0f - temp_f) + temp_max * temp_f, 1.0f, 0.5f});
}
static void render_stone(v3s32 pos, unused MapNode *node, Vertex3D *vertex, unused int f, unused int v)
vertex->textureCoordinates.t += noise2d(pos.x, pos.z, 0, seed + SO_TEXTURE_OFFSET_T);
}
-static void render_wood(unused v3s32 pos, unused MapNode *node, Vertex3D *vertex, int f, unused int v)
+static void render_hsl(unused v3s32 pos, MapNode *node, Vertex3D *vertex, unused int f, unused int v)
{
- vertex->color.h = f < 4 ? 0.1f : 0.11f;
- vertex->color.s = 1.0f;
- vertex->color.v = 1.0f;
+ vertex->color = hsl_to_rgb(((HSLData *) node->data)->color);
}
-ClientNodeDefintion client_node_definitions[NODE_UNLOADED] = {
+ClientNodeDefinition client_node_definitions[NODE_UNLOADED] = {
// unknown
{
.tiles = TILES_SIMPLE(RESSOURCEPATH "textures/unknown.png"),
.visibility = NV_SOLID,
+ .mipmap = true,
.render = NULL,
},
// air
{
.tiles = TILES_NONE,
.visibility = NV_NONE,
+ .mipmap = true,
.render = NULL,
},
// grass
{
.tiles = TILES_SIMPLE(RESSOURCEPATH "textures/grass.png"),
.visibility = NV_SOLID,
+ .mipmap = true,
.render = &render_grass,
},
// dirt
{
.tiles = TILES_SIMPLE(RESSOURCEPATH "textures/dirt.png"),
.visibility = NV_SOLID,
+ .mipmap = true,
.render = NULL,
},
// stone
{
.tiles = TILES_SIMPLE(RESSOURCEPATH "textures/stone.png"),
.visibility = NV_SOLID,
+ .mipmap = true,
.render = &render_stone,
},
// snow
{
.tiles = TILES_SIMPLE(RESSOURCEPATH "textures/snow.png"),
.visibility = NV_SOLID,
+ .mipmap = true,
.render = NULL,
},
- // wood
+ // oak wood
+ {
+ .tiles = {
+ .paths = {RESSOURCEPATH "textures/oak_wood.png", RESSOURCEPATH "textures/oak_wood_top.png", NULL, NULL, NULL, NULL},
+ .indices = {0, 0, 0, 0, 1, 1},
+ .textures = {NULL},
+ },
+ .visibility = NV_SOLID,
+ .mipmap = true,
+ .render = &render_hsl,
+ },
+ // oak leaves
+ {
+ .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/oak_leaves.png"),
+ .visibility = NV_SOLID,
+ .mipmap = true,
+ .render = &render_hsl,
+ },
+ // pine wood
+ {
+ .tiles = {
+ .paths = {RESSOURCEPATH "textures/pine_wood.png", RESSOURCEPATH "textures/pine_wood_top.png", NULL, NULL, NULL, NULL},
+ .indices = {0, 0, 0, 0, 1, 1},
+ .textures = {NULL},
+ },
+ .visibility = NV_SOLID,
+ .mipmap = true,
+ .render = &render_hsl,
+ },
+ // pine leaves
+ {
+ .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/pine_leaves.png"),
+ .visibility = NV_CLIP,
+ .mipmap = true,
+ .render = &render_hsl,
+ },
+ // palm wood
{
.tiles = {
- .paths = {RESSOURCEPATH "textures/wood.png", RESSOURCEPATH "textures/wood_top.png", NULL, NULL, NULL, NULL},
+ .paths = {RESSOURCEPATH "textures/palm_wood.png", RESSOURCEPATH "textures/palm_wood_top.png", NULL, NULL, NULL, NULL},
.indices = {0, 0, 0, 0, 1, 1},
.textures = {NULL},
},
.visibility = NV_SOLID,
- .render = &render_wood,
+ .mipmap = true,
+ .render = &render_hsl,
+ },
+ // palm leaves
+ {
+ .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/palm_leaves.png"),
+ .visibility = NV_SOLID,
+ .mipmap = true,
+ .render = &render_hsl,
},
// sand
{
.tiles = TILES_SIMPLE(RESSOURCEPATH "textures/sand.png"),
.visibility = NV_SOLID,
+ .mipmap = true,
.render = NULL,
},
// water
{
.tiles = TILES_SIMPLE(RESSOURCEPATH "textures/water.png"),
- .visibility = NV_TRANSPARENT,
+ .visibility = NV_BLEND,
+ .mipmap = true,
.render = NULL,
},
// lava
{
.tiles = TILES_SIMPLE(RESSOURCEPATH "textures/lava.png"),
- .visibility = NV_TRANSPARENT,
+ .visibility = NV_BLEND,
+ .mipmap = true,
.render = NULL,
},
// vulcano_stone
{
.tiles = TILES_SIMPLE(RESSOURCEPATH "textures/vulcano_stone.png"),
.visibility = NV_SOLID,
+ .mipmap = true,
.render = NULL,
},
};
void client_node_init()
{
for (Node node = NODE_UNKNOWN; node < NODE_UNLOADED; node++) {
- ClientNodeDefintion *def = &client_node_definitions[node];
+ ClientNodeDefinition *def = &client_node_definitions[node];
- if (client_node_definitions[node].visibility != NV_NONE) {
+ if (def->visibility != NV_NONE) {
Texture *textures[6];
for (int i = 0; i < 6; i++) {
char *path = def->tiles.paths[i];
if (path)
- textures[i] = texture_get(path);
+ textures[i] = texture_load(path, def->mipmap);
else
break;
}
typedef enum
{
NV_NONE,
- NV_TRANSPARENT,
+ NV_CLIP,
+ NV_BLEND,
NV_SOLID,
} NodeVisibility;
Texture *textures[6]; // output
} tiles;
NodeVisibility visibility;
+ bool mipmap;
void (*render)(v3s32 pos, MapNode *node, Vertex3D *vertex, int f, int v);
-} ClientNodeDefintion;
+} ClientNodeDefinition;
-extern ClientNodeDefintion client_node_definitions[];
+extern ClientNodeDefinition client_node_definitions[];
void client_node_init();
#endif
client_player.obj->scale = (v3f32) {0.6, 1.75, 0.6};
client_player.obj->visible = false;
- object_set_texture(client_player.obj, texture_get(RESSOURCEPATH "textures/player.png"));
+ object_set_texture(client_player.obj, texture_load(RESSOURCEPATH "textures/player.png", true));
for (int f = 0; f < 6; f++) {
for (int v = 0; v < 6; v++) {
Vertex3D cube_vertices[6][6] = {
{
- {{-0.5, -0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+0.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, +0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+1.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, -0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+1.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, +0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+1.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, -0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+0.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, +0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+0.0, +1.0}, {+0.0, +0.0, +1.0}},
+ {{-0.5, -0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+0.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, +0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+1.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, -0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+1.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, +0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+1.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, -0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+0.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, +0.5, -0.5}, {+0.0, +0.0, -1.0}, +0.0, {+0.0, +1.0}, {+1.0, +1.0, +1.0}},
},
{
- {{-0.5, -0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+0.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, -0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+1.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, +0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+1.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, +0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+1.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, +0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+0.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, -0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+0.0, +0.0}, {+0.0, +0.0, +1.0}},
+ {{-0.5, -0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+0.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, -0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+1.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, +0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+1.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, +0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+1.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, +0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+0.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, -0.5, +0.5}, {+0.0, +0.0, +1.0}, +0.0, {+0.0, +0.0}, {+1.0, +1.0, +1.0}},
},
{
- {{-0.5, +0.5, +0.5}, {-1.0, +0.0, +0.0}, +0.0, {+1.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, +0.5, -0.5}, {-1.0, +0.0, +0.0}, +0.0, {+0.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, -0.5, -0.5}, {-1.0, +0.0, +0.0}, +0.0, {+0.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, -0.5, -0.5}, {-1.0, +0.0, +0.0}, +0.0, {+0.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, -0.5, +0.5}, {-1.0, +0.0, +0.0}, +0.0, {+1.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, +0.5, +0.5}, {-1.0, +0.0, +0.0}, +0.0, {+1.0, +1.0}, {+0.0, +0.0, +1.0}},
+ {{-0.5, +0.5, +0.5}, {-1.0, +0.0, +0.0}, +0.0, {+1.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, +0.5, -0.5}, {-1.0, +0.0, +0.0}, +0.0, {+0.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, -0.5, -0.5}, {-1.0, +0.0, +0.0}, +0.0, {+0.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, -0.5, -0.5}, {-1.0, +0.0, +0.0}, +0.0, {+0.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, -0.5, +0.5}, {-1.0, +0.0, +0.0}, +0.0, {+1.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, +0.5, +0.5}, {-1.0, +0.0, +0.0}, +0.0, {+1.0, +1.0}, {+1.0, +1.0, +1.0}},
},
{
- {{+0.5, +0.5, +0.5}, {+1.0, +0.0, +0.0}, +0.0, {+1.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, -0.5, -0.5}, {+1.0, +0.0, +0.0}, +0.0, {+0.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, +0.5, -0.5}, {+1.0, +0.0, +0.0}, +0.0, {+0.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, -0.5, -0.5}, {+1.0, +0.0, +0.0}, +0.0, {+0.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, +0.5, +0.5}, {+1.0, +0.0, +0.0}, +0.0, {+1.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, -0.5, +0.5}, {+1.0, +0.0, +0.0}, +0.0, {+1.0, +0.0}, {+0.0, +0.0, +1.0}},
+ {{+0.5, +0.5, +0.5}, {+1.0, +0.0, +0.0}, +0.0, {+1.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, -0.5, -0.5}, {+1.0, +0.0, +0.0}, +0.0, {+0.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, +0.5, -0.5}, {+1.0, +0.0, +0.0}, +0.0, {+0.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, -0.5, -0.5}, {+1.0, +0.0, +0.0}, +0.0, {+0.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, +0.5, +0.5}, {+1.0, +0.0, +0.0}, +0.0, {+1.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, -0.5, +0.5}, {+1.0, +0.0, +0.0}, +0.0, {+1.0, +0.0}, {+1.0, +1.0, +1.0}},
},
{
- {{-0.5, -0.5, -0.5}, {+0.0, -1.0, +0.0}, +0.0, {+0.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, -0.5, -0.5}, {+0.0, -1.0, +0.0}, +0.0, {+1.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, -0.5, +0.5}, {+0.0, -1.0, +0.0}, +0.0, {+1.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, -0.5, +0.5}, {+0.0, -1.0, +0.0}, +0.0, {+1.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, -0.5, +0.5}, {+0.0, -1.0, +0.0}, +0.0, {+0.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, -0.5, -0.5}, {+0.0, -1.0, +0.0}, +0.0, {+0.0, +1.0}, {+0.0, +0.0, +1.0}},
+ {{-0.5, -0.5, -0.5}, {+0.0, -1.0, +0.0}, +0.0, {+0.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, -0.5, -0.5}, {+0.0, -1.0, +0.0}, +0.0, {+1.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, -0.5, +0.5}, {+0.0, -1.0, +0.0}, +0.0, {+1.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, -0.5, +0.5}, {+0.0, -1.0, +0.0}, +0.0, {+1.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, -0.5, +0.5}, {+0.0, -1.0, +0.0}, +0.0, {+0.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, -0.5, -0.5}, {+0.0, -1.0, +0.0}, +0.0, {+0.0, +1.0}, {+1.0, +1.0, +1.0}},
},
{
- {{-0.5, +0.5, -0.5}, {+0.0, +1.0, +0.0}, +0.0, {+0.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, +0.5, +0.5}, {+0.0, +1.0, +0.0}, +0.0, {+1.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, +0.5, -0.5}, {+0.0, +1.0, +0.0}, +0.0, {+1.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{+0.5, +0.5, +0.5}, {+0.0, +1.0, +0.0}, +0.0, {+1.0, +0.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, +0.5, -0.5}, {+0.0, +1.0, +0.0}, +0.0, {+0.0, +1.0}, {+0.0, +0.0, +1.0}},
- {{-0.5, +0.5, +0.5}, {+0.0, +1.0, +0.0}, +0.0, {+0.0, +0.0}, {+0.0, +0.0, +1.0}},
+ {{-0.5, +0.5, -0.5}, {+0.0, +1.0, +0.0}, +0.0, {+0.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, +0.5, +0.5}, {+0.0, +1.0, +0.0}, +0.0, {+1.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, +0.5, -0.5}, {+0.0, +1.0, +0.0}, +0.0, {+1.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{+0.5, +0.5, +0.5}, {+0.0, +1.0, +0.0}, +0.0, {+1.0, +0.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, +0.5, -0.5}, {+0.0, +1.0, +0.0}, +0.0, {+0.0, +1.0}, {+1.0, +1.0, +1.0}},
+ {{-0.5, +0.5, +0.5}, {+0.0, +1.0, +0.0}, +0.0, {+0.0, +0.0}, {+1.0, +1.0, +1.0}},
},
};
};
} else {
font.chars[c] = (Character) {
- .texture = texture_create(font.face->glyph->bitmap.buffer, font.face->glyph->bitmap.width, font.face->glyph->bitmap.rows, GL_RED),
+ .texture = texture_create(font.face->glyph->bitmap.buffer, font.face->glyph->bitmap.width, font.face->glyph->bitmap.rows, GL_RED, false),
.bearing = {font.face->glyph->bitmap_left, font.face->glyph->bitmap_top},
.advance = font.face->glyph->advance.x,
};
.scale_type = GST_IMAGE,
.affect_parent_scale = false,
.text = NULL,
- .image = texture_get(RESSOURCEPATH "textures/crosshair.png"),
+ .image = texture_load(RESSOURCEPATH "textures/crosshair.png", false),
.text_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.0f},
.bg_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.0f},
});
glEnable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glAlphaFunc(GL_GREATER, 0.0f);
+ glAlphaFunc(GL_GREATER, 0.1f);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
return false;
if (obj->frustum_culling) {
- aabb3f32 box = {v3f32_add(obj->box.min, obj->pos), v3f32_add(obj->box.max, obj->pos), };
+ aabb3f32 box = {v3f32_add(obj->box.min, obj->pos), v3f32_add(obj->box.max, obj->pos)};
if (! frustum_is_visible(box))
return false;
} __attribute__((packed)) Vertex3DTextureCoordinates;
typedef struct {
- GLfloat h, s, v;
+ GLfloat r, g, b;
} __attribute__((packed)) Vertex3DColor;
typedef struct
bool scene_init()
{
scene.objects = list_create(NULL);
- scene.render_objects = bintree_create(sizeof(f32), &bintree_compare_f32);
+ scene.transparent_objects = bintree_create(sizeof(f32), &bintree_compare_f32);
pthread_mutex_init(&scene.mtx, NULL);
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &scene.max_texture_units);
f32 distance = sqrt(pow(obj->pos.x - camera.eye[0], 2) + pow(obj->pos.y - camera.eye[1], 2) + pow(obj->pos.z - camera.eye[2], 2));
if (distance < scene.render_distance && object_before_render(obj, dtime)) {
if (obj->transparent)
- bintree_insert(&scene.render_objects, &distance, obj);
+ bintree_insert(&scene.transparent_objects, &distance, obj);
else
object_render(obj);
}
}
}
- bintree_traverse(&scene.render_objects, BTT_INORDER, &bintree_render_object, NULL);
- bintree_clear(&scene.render_objects, NULL, NULL);
+ bintree_traverse(&scene.transparent_objects, BTT_INORDER, &bintree_render_object, NULL);
+ bintree_clear(&scene.transparent_objects, NULL, NULL);
}
void scene_on_resize(int width, int height)
extern struct Scene
{
List objects;
- Bintree render_objects;
+ Bintree transparent_objects;
pthread_mutex_t mtx;
GLuint prog;
GLint loc_model;
sky.sun_loc_MVP = glGetUniformLocation(sky.sun_prog, "MVP");
- sky.sun_texture = texture_get(RESSOURCEPATH "textures/sun.png");
+ sky.sun_texture = texture_load(RESSOURCEPATH "textures/sun.png", false);
sky.sun_mesh = mesh_create();
sky.sun_mesh->textures = &sky.sun_texture->id;
list_clear_func(&textures, &list_delete_texture, NULL);
}
-Texture *texture_create(unsigned char *data, int width, int height, GLenum format)
+Texture *texture_create(unsigned char *data, int width, int height, GLenum format, bool mipmap)
{
Texture *texture = malloc(sizeof(Texture));
texture->width = width;
glBindTexture(GL_TEXTURE_2D, texture->id);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmap ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
free(texture);
}
-static void *create_image_texture(void *key)
+Texture *texture_load(char *path, bool mipmap)
{
int width, height, channels;
- unsigned char *data = stbi_load(key, &width, &height, &channels, 0);
+ unsigned char *data = stbi_load(path, &width, &height, &channels, 0);
if (! data) {
- fprintf(stderr, "Failed to load texture %s\n", (char *) key);
- return 0;
+ fprintf(stderr, "Failed to load texture %s\n", path);
+ return NULL;
}
- Texture *texture = texture_create(data, width, height, GL_RGBA);
+ Texture *texture = texture_create(data, width, height, GL_RGBA, mipmap);
stbi_image_free(data);
- return texture;
-}
+ list_put(&textures, texture, NULL);
-Texture *texture_get(char *path)
-{
- return list_get_cached(&textures, path, &create_image_texture);
+ return texture;
}
int width, height;
} Texture;
-Texture *texture_create(unsigned char *data, int width, int height, GLenum format);
+Texture *texture_create(unsigned char *data, int width, int height, GLenum format, bool mipmap);
GLuint texture_create_cubemap(char *path);
void texture_delete(Texture *texture);
-Texture *texture_get(char *path);
+Texture *texture_load(char *path, bool mipmap);
#endif
" > $DEBUG_DIR/client_script
echo "$COMMON
+set print thread-events off
run 4000
" > $DEBUG_DIR/server_script
-konsole -e bash -c "
+kitty --detach -e bash -c "
echo \$\$ > $DEBUG_DIR/server_pid
exec gdb --command $DEBUG_DIR/server_script ./DragonblocksServer
-" & sleep 0.5
+"
+sleep 0.5
gdb --command $DEBUG_DIR/client_script ./Dragonblocks
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&block->mtx, &attr);
+
+ ITERATE_MAPBLOCK block->data[x][y][z] = map_node_create(NODE_UNKNOWN, NULL, 0);
+
return block;
}
void map_free_block(MapBlock *block)
{
+ ITERATE_MAPBLOCK map_node_delete(block->data[x][y][z]);
+
pthread_mutex_destroy(&block->mtx);
free(block);
}
-bool map_deserialize_node(int fd, MapNode *node)
+void map_serialize_block(MapBlock *block, char **dataptr, size_t *sizeptr, size_t *rawsizeptr)
{
- Node type;
-
- if (! read_u32(fd, &type))
- return false;
+ unsigned char *uncompressed = NULL;
+ size_t uncompressed_size = 0;
- if (type >= NODE_UNLOADED)
- type = NODE_UNKNOWN;
+ ITERATE_MAPBLOCK {
+ MapNode node = block->data[x][y][z];
+ NodeDefinition *def = &node_definitions[node.type];
- *node = map_node_create(type);
+ u32 type = htobe32(node.type);
+ buffer_write(&uncompressed, &uncompressed_size, &type, sizeof(u32));
- return true;
-}
+ unsigned char *data_buffer = NULL;
+ size_t data_bufsiz = 0;
-void map_serialize_block(MapBlock *block, char **dataptr, size_t *sizeptr)
-{
- MapBlockData uncompressed;
- ITERATE_MAPBLOCK {
- MapNode node = block->data[x][y][z];
+ if (def->serialize)
+ def->serialize(&node, &data_buffer, &data_bufsiz);
- if (node_definitions[node.type].serialize)
- node_definitions[node.type].serialize(&node);
+ u16 data_size = htobe16(data_bufsiz);
+ buffer_write(&uncompressed, &uncompressed_size, &data_size, sizeof(u16));
+ buffer_write(&uncompressed, &uncompressed_size, data_buffer, data_bufsiz);
- node.type = htobe32(node.type);
- uncompressed[x][y][z] = node;
+ if (data_buffer)
+ free(data_buffer);
}
- my_compress(&uncompressed, sizeof(MapBlockData), dataptr, sizeptr);
+ my_compress(uncompressed, uncompressed_size, dataptr, sizeptr);
+ *rawsizeptr = uncompressed_size;
+
+ if (uncompressed)
+ free(uncompressed);
}
-bool map_deserialize_block(MapBlock *block, const char *data, size_t size)
+bool map_deserialize_block(MapBlock *block, const char *data, size_t size, size_t rawsize)
{
- MapBlockData decompressed;
+ unsigned char decompressed[rawsize];
+ size_t decompressed_size = rawsize;
- if (! my_decompress(data, size, &decompressed, sizeof(MapBlockData)))
+ if (! my_decompress(data, size, decompressed, decompressed_size))
return false;
+ unsigned char *ptr = decompressed;
+
ITERATE_MAPBLOCK {
- MapNode node = decompressed[x][y][z];
- node.type = be32toh(node.type);
+ // node type
+ u32 *type_ptr = buffer_read(&ptr, &decompressed_size, sizeof(u32));
- if (node.type >= NODE_UNLOADED)
- node.type = NODE_UNKNOWN;
+ if (! type_ptr)
+ return false;
- if (node_definitions[node.type].deserialize)
- node_definitions[node.type].deserialize(&node);
+ u32 type = be32toh(*type_ptr);
- block->data[x][y][z] = node;
+ // data size
+ u16 *data_size_ptr = buffer_read(&ptr, &decompressed_size, sizeof(u16));
+
+ if (! data_size_ptr)
+ return false;
+
+ u16 data_size = be16toh(*data_size_ptr);
+
+ // data
+ void *data = buffer_read(&ptr, &decompressed_size, data_size);
+
+ if (! data && data_size)
+ return false;
+
+ // set node
+ block->data[x][y][z] = map_node_create(type, data, data_size);
}
return true;
v3s32 blockpos = map_node_to_block_pos(pos, &offset);
MapBlock *block = map_get_block(map, blockpos, false);
if (! block)
- return map_node_create(NODE_UNLOADED);
+ return map_node_create(NODE_UNLOADED, NULL, 0);
return block->data[offset.x][offset.y][offset.z];
}
block->data[offset.x][offset.y][offset.z] = node;
if (map->callbacks.after_set_node)
map->callbacks.after_set_node(block, offset, arg);
+ } else {
+ map_node_delete(node);
}
pthread_mutex_unlock(&block->mtx);
}
}
-MapNode map_node_create(Node type)
+MapNode map_node_create(Node type, void *data, size_t size)
{
+ if (type >= NODE_UNLOADED)
+ type = NODE_UNKNOWN;
+
+ NodeDefinition *def = &node_definitions[type];
+
MapNode node;
node.type = type;
+ node.data = def->data_size ? malloc(def->data_size) : NULL;
- if (node.type != NODE_UNLOADED && node_definitions[node.type].create)
- node_definitions[node.type].create(&node);
+ if (def->create)
+ def->create(&node);
+
+ if (def->deserialize && size)
+ def->deserialize(&node, data, size);
return node;
}
+
+void map_node_delete(MapNode node)
+{
+ NodeDefinition *def = &node_definitions[node.type];
+
+ if (def->delete)
+ def->delete(&node);
+
+ if (node.data)
+ free(node.data);
+}
typedef struct MapNode
{
Node type;
+ void *data;
} MapNode;
typedef MapNode MapBlockData[MAPBLOCK_SIZE][MAPBLOCK_SIZE][MAPBLOCK_SIZE];
MapBlock *map_allocate_block(v3s32 pos);
void map_free_block(MapBlock *block);
-bool map_deserialize_node(int fd, MapNode *buf);
-void map_serialize_block(MapBlock *block, char **dataptr, size_t *sizeptr);
-bool map_deserialize_block(MapBlock *block, const char *data, size_t size);
+void map_serialize_block(MapBlock *block, char **dataptr, size_t *sizeptr, size_t *rawsizeptr);
+bool map_deserialize_block(MapBlock *block, const char *data, size_t size, size_t rawsize);
v3s32 map_node_to_block_pos(v3s32 pos, v3u8 *offset);
MapNode map_get_node(Map *map, v3s32 pos);
void map_set_node(Map *map, v3s32 pos, MapNode node, bool create, void *arg);
-MapNode map_node_create(Node type);
-void map_node_clear(MapNode *node);
+
+MapNode map_node_create(Node type, void *data, size_t size);
+void map_node_delete(MapNode node);
#endif
#include "map.h"
#include "node.h"
#include "util.h"
+#include <stdio.h>
-NodeDefintion node_definitions[NODE_UNLOADED] = {
+static void serialize_hsl(MapNode *node, unsigned char **buffer, size_t *bufsiz)
+{
+ HSLData *node_data = node->data;
+ buffer_write(buffer, bufsiz, (f32 []) {node_data->color.x, node_data->color.y, node_data->color.z}, sizeof(f32) * 3);
+}
+
+static void deserialize_hsl(MapNode *node, unsigned char *data, size_t size)
+{
+ HSLData *node_data = node->data;
+
+ f32 *color = buffer_read(&data, &size, sizeof(f32) * 3);
+
+ if (! color)
+ return;
+
+ *node_data = (HSLData) {.color = {color[0], color[1], color[2]}};
+}
+
+NodeDefinition node_definitions[NODE_UNLOADED] = {
// unknown
{
.solid = true,
+ .data_size = 0,
.create = NULL,
+ .delete = NULL,
.serialize = NULL,
.deserialize = NULL,
},
// air
{
.solid = false,
+ .data_size = 0,
.create = NULL,
+ .delete = NULL,
.serialize = NULL,
.deserialize = NULL,
},
// grass
{
.solid = true,
+ .data_size = 0,
.create = NULL,
+ .delete = NULL,
.serialize = NULL,
.deserialize = NULL,
},
// dirt
{
.solid = true,
+ .data_size = 0,
.create = NULL,
+ .delete = NULL,
.serialize = NULL,
.deserialize = NULL,
},
// stone
{
.solid = true,
+ .data_size = 0,
.create = NULL,
+ .delete = NULL,
.serialize = NULL,
.deserialize = NULL,
},
// snow
{
.solid = true,
+ .data_size = 0,
.create = NULL,
+ .delete = NULL,
.serialize = NULL,
.deserialize = NULL,
},
- // wood
+ // oak wood
{
.solid = true,
+ .data_size = sizeof(HSLData),
.create = NULL,
- .serialize = NULL,
- .deserialize = NULL,
+ .delete = NULL,
+ .serialize = &serialize_hsl,
+ .deserialize = &deserialize_hsl,
+ },
+ // oak leaves
+ {
+ .solid = true,
+ .data_size = sizeof(HSLData),
+ .create = NULL,
+ .delete = NULL,
+ .serialize = &serialize_hsl,
+ .deserialize = &deserialize_hsl,
+ },
+ // pine wood
+ {
+ .solid = true,
+ .data_size = sizeof(HSLData),
+ .create = NULL,
+ .delete = NULL,
+ .serialize = &serialize_hsl,
+ .deserialize = &deserialize_hsl,
+ },
+ // pine leaves
+ {
+ .solid = true,
+ .data_size = sizeof(HSLData),
+ .create = NULL,
+ .delete = NULL,
+ .serialize = &serialize_hsl,
+ .deserialize = &deserialize_hsl,
+ },
+ // palm wood
+ {
+ .solid = true,
+ .data_size = sizeof(HSLData),
+ .create = NULL,
+ .delete = NULL,
+ .serialize = &serialize_hsl,
+ .deserialize = &deserialize_hsl,
+ },
+ // palm leaves
+ {
+ .solid = true,
+ .data_size = sizeof(HSLData),
+ .create = NULL,
+ .delete = NULL,
+ .serialize = &serialize_hsl,
+ .deserialize = &deserialize_hsl,
},
// sand
{
.solid = true,
+ .data_size = 0,
.create = NULL,
+ .delete = NULL,
.serialize = NULL,
.deserialize = NULL,
},
// water
{
.solid = false,
+ .data_size = 0,
.create = NULL,
+ .delete = NULL,
.serialize = NULL,
.deserialize = NULL,
},
// lava
{
.solid = false,
+ .data_size = 0,
.create = NULL,
+ .delete = NULL,
.serialize = NULL,
.deserialize = NULL,
},
// vulcanostone
{
.solid = true,
+ .data_size = 0,
.create = NULL,
+ .delete = NULL,
.serialize = NULL,
.deserialize = NULL,
},
#include <stdbool.h>
#include <dragontype/number.h>
+#define NODE_DEFINITION(type) ((type) < NODE_UNLOADED ? &node_definitions[NODE_UNKNOWN] : &node_definitions[(type)]);
+
typedef enum
{
NODE_UNKNOWN, // Used for unknown nodes received from server (caused by outdated clients)
NODE_DIRT,
NODE_STONE,
NODE_SNOW,
- NODE_WOOD,
+ NODE_OAK_WOOD,
+ NODE_OAK_LEAVES,
+ NODE_PINE_WOOD,
+ NODE_PINE_LEAVES,
+ NODE_PALM_WOOD,
+ NODE_PALM_LEAVES,
NODE_SAND,
NODE_WATER,
NODE_LAVA,
typedef struct
{
bool solid;
+ size_t data_size;
void (*create)(struct MapNode *node);
- void (*serialize)(struct MapNode *node);
- void (*deserialize)(struct MapNode *node);
-} NodeDefintion;
+ void (*delete)(struct MapNode *node);
+ void (*serialize)(struct MapNode *node, unsigned char **buffer, size_t *bufsiz);
+ void (*deserialize)(struct MapNode *node, unsigned char *data, size_t size);
+} NodeDefinition;
+
+typedef struct {
+ v3f32 color;
+} HSLData;
-extern NodeDefintion node_definitions[];
+extern NodeDefinition node_definitions[];
#endif
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,
} SeedOffset;
extern s32 seed;
// mountain biome
-static s32 height_mountain(v2s32 pos, f64 factor, s32 height, unused void *row_data, unused void *block_data)
+static s32 height_mountain(v2s32 pos, f64 factor, f32 height, unused void *row_data, unused void *block_data)
{
return pow((height + 96) * pow(((smooth2d(U32(pos.x) / 48.0, U32(pos.y) / 48.0, 0, seed + SO_MOUNTAIN_HEIGHT) + 1.0) * 256.0 + 128.0), factor), 1.0 / (factor + 1.0)) - 96;
}
data->vulcano_pos = (v2s32) {vulcano_pos.x * MAPBLOCK_SIZE, vulcano_pos.y * MAPBLOCK_SIZE};
}
-static void preprocess_row_ocean(v2s32 pos, unused s32 height, unused f64 factor, void *row_data, void *block_data)
+static void preprocess_row_ocean(v2s32 pos, unused f64 factor, void *row_data, void *block_data)
{
OceanRowData *rdata = row_data;
OceanBlockData *bdata = block_data;
}
}
-static s32 height_ocean(unused v2s32 pos, f64 factor, s32 height, void *row_data, unused void *block_data)
+static s32 height_ocean(unused v2s32 pos, f64 factor, f32 height, void *row_data, unused void *block_data)
{
OceanRowData *rdata = row_data;
s32 ocean_floor = calculate_ocean_floor(factor, height);
return rdata->vulcano ? max(ocean_floor, rdata->vulcano_height) : ocean_floor;
}
-static Node generate_ocean(v3s32 pos, s32 diff, unused f64 humidity, unused f64 temperature, unused f64 factor, unused MapBlock *block, unused List *changed_blocks, void *row_data, unused void *block_data)
+Node ocean_get_node_at(v3s32 pos, s32 diff, void *row_data)
{
OceanRowData *rdata = row_data;
return NODE_AIR;
}
+static Node generate_ocean(v3s32 pos, s32 diff, unused f64 humidity, unused f64 temperature, unused f64 factor, unused MapBlock *block, unused List *changed_blocks, void *row_data, unused void *block_data)
+{
+ return ocean_get_node_at(pos, diff, row_data);
+}
+
// hills biome
static bool boulder_touching_ground(v3s32 pos, s32 diff)
return true;
}
-static s32 height_hills(unused v2s32 pos, unused f64 factor, s32 height, unused void *row_data, unused void *block_data)
+static s32 height_hills(unused v2s32 pos, unused f64 factor, f32 height, unused void *row_data, unused void *block_data)
{
return height;
}
SeedOffset offset;
f64 threshold;
bool snow;
- s32 (*height)(v2s32 pos, f64 factor, s32 height, void *row_data, void *block_data);
+ s32 (*height)(v2s32 pos, f64 factor, f32 height, void *row_data, void *block_data);
Node (*generate)(v3s32 pos, s32 diff, f64 humidity, f64 temperature, f64 factor, MapBlock *block, List *changed_blocks, void *row_data, void *block_data);
size_t block_data_size;
void (*preprocess_block)(MapBlock *block, List *changed_blocks, void *block_data);
size_t row_data_size;
- void (*preprocess_row)(v2s32 pos, s32 height, f64 factor, void *row_data, void *block_data);
+ void (*preprocess_row)(v2s32 pos, f64 factor, void *row_data, void *block_data);
} BiomeDef;
-extern BiomeDef biomes[BIOME_COUNT];
+extern BiomeDef biomes[];
Biome get_biome(v2s32 pos, f64 *factor);
+Node ocean_get_node_at(v3s32 pos, s32 diff, void *row_data);
#endif
}
const char *init_stmts[3]= {
- "CREATE TABLE IF NOT EXISTS map (pos BLOB PRIMARY KEY, generated INTEGER, size INTEGER, data BLOB, mgsb_size INTEGER, mgsb_data BLOB);",
+ "CREATE TABLE IF NOT EXISTS map (pos BLOB PRIMARY KEY, generated INTEGER, size INTEGER, rawsize INTEGER, data BLOB, mgsb_size INTEGER, mgsb_data BLOB);",
"CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value INTEGER);",
"CREATE TABLE IF NOT EXISTS players (name TEXT PRIMARY KEY, pos BLOB);"
};
{
sqlite3_stmt *stmt;
- if (! (stmt = prepare_block_statement(block, "loading", "SELECT generated, size, data, mgsb_size, mgsb_data FROM map WHERE pos=?")))
+ if (! (stmt = prepare_block_statement(block, "loading", "SELECT generated, size, rawsize, data, mgsb_size, mgsb_data FROM map WHERE pos=?")))
return false;
int rc = sqlite3_step(stmt);
extra->state = sqlite3_column_int(stmt, 0) ? MBS_READY : MBS_CREATED;
extra->size = sqlite3_column_int64(stmt, 1);
+ extra->rawsize = sqlite3_column_int64(stmt, 2);
extra->data = malloc(extra->size);
- memcpy(extra->data, sqlite3_column_blob(stmt, 2), extra->size);
+ memcpy(extra->data, sqlite3_column_blob(stmt, 3), extra->size);
MapgenStageBuffer decompressed_mgsb;
- my_decompress(sqlite3_column_blob(stmt, 4), sqlite3_column_int64(stmt, 3), &decompressed_mgsb, sizeof(MapgenStageBuffer));
+ my_decompress(sqlite3_column_blob(stmt, 5), sqlite3_column_int64(stmt, 4), &decompressed_mgsb, sizeof(MapgenStageBuffer));
ITERATE_MAPBLOCK extra->mgs_buffer[x][y][z] = be32toh(decompressed_mgsb[x][y][z]);
- if (! map_deserialize_block(block, extra->data, extra->size))
+ if (! map_deserialize_block(block, extra->data, extra->size, extra->rawsize))
printf("Error with deserializing block at (%d, %d, %d)\n", block->pos.x, block->pos.y, block->pos.z);
} else if (rc != SQLITE_DONE) {
print_block_error(block, "loading");
{
sqlite3_stmt *stmt;
- if (! (stmt = prepare_block_statement(block, "saving", "REPLACE INTO map (pos, generated, size, data, mgsb_size, mgsb_data) VALUES(?1, ?2, ?3, ?4, ?5, ?6)")))
+ if (! (stmt = prepare_block_statement(block, "saving", "REPLACE INTO map (pos, generated, size, rawsize, data, mgsb_size, mgsb_data) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7)")))
return;
MapBlockExtraData *extra = block->extra;
sqlite3_bind_int(stmt, 2, extra->state > MBS_CREATED);
sqlite3_bind_int64(stmt, 3, extra->size);
- sqlite3_bind_blob(stmt, 4, extra->data, extra->size, SQLITE_TRANSIENT);
- sqlite3_bind_int64(stmt, 5, mgsb_size);
- sqlite3_bind_blob(stmt, 6, mgsb_data, mgsb_size, &free);
+ sqlite3_bind_int64(stmt, 4, extra->rawsize);
+ sqlite3_bind_blob(stmt, 5, extra->data, extra->size, SQLITE_TRANSIENT);
+ sqlite3_bind_int64(stmt, 6, mgsb_size);
+ sqlite3_bind_blob(stmt, 7, mgsb_data, mgsb_size, &free);
if (sqlite3_step(stmt) != SQLITE_DONE)
print_block_error(block, "saving");
#include <math.h>
#include <stdlib.h>
+#include <stdio.h>
#include "environment.h"
#include "perlin.h"
#include "server/biomes.h"
#include "server/mapgen.h"
#include "server/server_map.h"
+#include "server/trees.h"
#include "util.h"
void mapgen_set_node(v3s32 pos, MapNode node, MapgenStage mgs, List *changed_blocks)
for (u8 z = 0; z < MAPBLOCK_SIZE; z++) {
v2s32 pos_horizontal = {pos_x, block_node_pos.z + z};
- s32 height = (pnoise2d(U32(pos_horizontal.x) / 32.0, U32(pos_horizontal.y) / 32.0, 0.45, 5, seed + SO_HEIGHT) * 16.0)
+ s32 default_height = (pnoise2d(U32(pos_horizontal.x) / 32.0, U32(pos_horizontal.y) / 32.0, 0.45, 5, seed + SO_HEIGHT) * 16.0)
* (pnoise2d(U32(pos_horizontal.x) / 256.0, U32(pos_horizontal.y) / 256.0, 0.45, 5, seed + SO_HILLYNESS) * 0.5 + 0.5)
- + 32;
+ + 32.0;
f64 factor;
Biome biome = get_biome(pos_horizontal, &factor);
char row_data[biome_def->row_data_size];
if (biome_def->preprocess_row)
- biome_def->preprocess_row(pos_horizontal, height, factor, row_data, block_data[biome]);
+ biome_def->preprocess_row(pos_horizontal, factor, row_data, block_data[biome]);
- height = biome_def->height(pos_horizontal, factor, height, row_data, block_data[biome]);
+ s32 height = biome_def->height(pos_horizontal, factor, default_height, row_data, block_data[biome]);
for (u8 y = 0; y < MAPBLOCK_SIZE; y++) {
v3s32 pos = {pos_horizontal.x, block_node_pos.y + y, pos_horizontal.y};
if (biome_def->snow && diff <= 1 && temperature < 0.0 && node == NODE_AIR)
node = NODE_SNOW;
+ if (diff == 1) {
+ for (int i = 0; i < NUM_TREES; i++) {
+ TreeDef *def = &tree_definitions[i];
+
+ if (def->condition(pos, humidity, temperature, biome, factor, block, row_data, block_data)
+ && noise2d(pos.x, pos.z, 0, seed + def->offset) * 0.5 + 0.5 < def->probability
+ && smooth2d(U32(pos.x) / def->spread, U32(pos.z) / def->spread, 0, seed + def->area_offset) * 0.5 + 0.5 < def->area_probability) {
+ def->generate(pos, changed_blocks);
+ break;
+ }
+ }
+ }
+
pthread_mutex_lock(&block->mtx);
if (extra->mgs_buffer[x][y][z] <= MGS_TERRAIN) {
- block->data[x][y][z] = map_node_create(node);
+ block->data[x][y][z] = map_node_create(node, NULL, 0);
extra->mgs_buffer[x][y][z] = MGS_TERRAIN;
}
pthread_mutex_unlock(&block->mtx);
if (! read_v3s32(client->fd, &pos))
return false;
- MapNode node;
+ Node node;
- if (! map_deserialize_node(client->fd, &node))
+ if (! read_u32(client->fd, &node))
return false;
if (good)
- map_set_node(server_map.map, pos, node, false, NULL);
+ map_set_node(server_map.map, pos, map_node_create(node, NULL, 0), false, NULL);
return true;
}
SERVER_COMMAND_NULL, // invalid command
SC_DISCONNECT, // client notifies server about disconnecting
SC_AUTH, // client wants to authentify [body: name (zero terminated string)]
- SC_SETNODE, // player placed a node [body: pos (v3s32), node (MapNode)]
+ SC_SETNODE, // player placed a node [body: pos (v3s32), node (Node)]
SC_POS, // player moved [body: pos (v3f)]
SC_REQUEST_BLOCK, // request to send a block [body: pos (v3s32)]
SERVER_COMMAND_COUNT, // count of available commands
+#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
pthread_mutex_lock(&client->mtx);
if (client->state == CS_ACTIVE)
- (void) (write_u32(client->fd, CC_BLOCK) && write_v3s32(client->fd, block->pos) && write_u64(client->fd, extra->size) && write(client->fd, extra->data, extra->size) != -1);
+ (void) (write_u32(client->fd, CC_BLOCK)
+ && write_v3s32(client->fd, block->pos)
+ && write_u64(client->fd, extra->size)
+ && write_u64(client->fd, extra->rawsize)
+ && write(client->fd, extra->data, extra->size) != -1);
pthread_mutex_unlock(&client->mtx);
}
if (extra->data)
free(extra->data);
- map_serialize_block(block, &extra->data, &extra->size);
+ map_serialize_block(block, &extra->data, &extra->size, &extra->rawsize);
database_save_block(block);
if (extra->state == MBS_CREATED)
extra->data = NULL;
ITERATE_MAPBLOCK {
- block->data[x][y][z] = map_node_create(NODE_AIR);
+ block->data[x][y][z] = map_node_create(NODE_AIR, NULL, 0);
extra->mgs_buffer[x][y][z] = MGS_VOID;
}
}
for (s32 x = -4; x <= +4; x++) {
for (s32 y = 0; y <= 3; y++) {
for (s32 z = -3; z <= +2; z++) {
- mapgen_set_node((v3s32) {x, server_map.spawn_height + y, z}, (MapNode) {NODE_AIR}, MGS_PLAYER, &changed_blocks);
+ mapgen_set_node((v3s32) {x, server_map.spawn_height + y, z}, map_node_create(NODE_AIR, NULL, 0), MGS_PLAYER, &changed_blocks);
}
}
}
for (s32 x = -5; x <= +5; x++) {
for (s32 z = -4; z <= +3; z++) {
- mapgen_set_node((v3s32) {x, server_map.spawn_height - 1, z}, (MapNode) {NODE_WOOD}, MGS_PLAYER, &changed_blocks);
- mapgen_set_node((v3s32) {x, server_map.spawn_height + 4, z}, (MapNode) {NODE_WOOD}, MGS_PLAYER, &changed_blocks);
+ mapgen_set_node((v3s32) {x, server_map.spawn_height - 1, z}, map_node_create(NODE_OAK_WOOD, NULL, 0), MGS_PLAYER, &changed_blocks);
+ mapgen_set_node((v3s32) {x, server_map.spawn_height + 4, z}, map_node_create(NODE_OAK_WOOD, NULL, 0), MGS_PLAYER, &changed_blocks);
}
}
for (s32 y = 0; y <= 3; y++) {
for (s32 x = -5; x <= +5; x++) {
- mapgen_set_node((v3s32) {x, server_map.spawn_height + y, -4}, (MapNode) {((y == 1 || y == 2) && ((x >= -3 && x <= -1) || (x >= +1 && x <= +2))) ? NODE_AIR : NODE_WOOD}, MGS_PLAYER, &changed_blocks);
- mapgen_set_node((v3s32) {x, server_map.spawn_height + y, +3}, (MapNode) {((y == 1 || y == 2) && ((x >= -3 && x <= -2) || (x >= +1 && x <= +3))) ? NODE_AIR : NODE_WOOD}, MGS_PLAYER, &changed_blocks);
+ mapgen_set_node((v3s32) {x, server_map.spawn_height + y, -4}, map_node_create(((y == 1 || y == 2) && ((x >= -3 && x <= -1) || (x >= +1 && x <= +2))) ? NODE_AIR : NODE_OAK_WOOD, NULL, 0), MGS_PLAYER, &changed_blocks);
+ mapgen_set_node((v3s32) {x, server_map.spawn_height + y, +3}, map_node_create(((y == 1 || y == 2) && ((x >= -3 && x <= -2) || (x >= +1 && x <= +3))) ? NODE_AIR : NODE_OAK_WOOD, NULL, 0), MGS_PLAYER, &changed_blocks);
}
}
for (s32 y = 0; y <= 3; y++) {
for (s32 z = -3; z <= +2; z++) {
- mapgen_set_node((v3s32) {-5, server_map.spawn_height + y, z}, (MapNode) {NODE_WOOD}, MGS_PLAYER, &changed_blocks);
- mapgen_set_node((v3s32) {+5, server_map.spawn_height + y, z}, (MapNode) {((y != 3) && (z == -1 || z == +0)) ? NODE_AIR : NODE_WOOD}, MGS_PLAYER, &changed_blocks);
+ mapgen_set_node((v3s32) {-5, server_map.spawn_height + y, z}, map_node_create(NODE_OAK_WOOD, NULL, 0), MGS_PLAYER, &changed_blocks);
+ mapgen_set_node((v3s32) {+5, server_map.spawn_height + y, z}, map_node_create(((y != 3) && (z == -1 || z == +0)) ? NODE_AIR : NODE_OAK_WOOD, NULL, 0), MGS_PLAYER, &changed_blocks);
}
}
if (node_definitions[node].solid)
break;
- mapgen_set_node(pos, (MapNode) {node == NODE_LAVA ? NODE_VULCANO_STONE : NODE_WOOD}, MGS_PLAYER, &changed_blocks);
+ mapgen_set_node(pos, map_node_create(node == NODE_LAVA ? NODE_VULCANO_STONE : NODE_OAK_WOOD, NULL, 0), MGS_PLAYER, &changed_blocks);
}
}
{
char *data; // cached serialized data
size_t size; // size of data
+ size_t rawsize; // size of decompressed data
MapBlockState state; // generation state of the block
pthread_t mapgen_thread; // thread that is generating block
MapgenStageBuffer mgs_buffer; // buffer to make sure mapgen only overrides things it should
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include "server/biomes.h"
+#include "server/mapgen.h"
+#include "server/trees.h"
+#include "server/voxelctx.h"
+#include "util.h"
+
+// oak
+
+static bool oak_condition(unused v3s32 pos, unused f64 humidity, unused f64 temperature, Biome biome, unused f64 factor, unused MapBlock *block, unused void *row_data, unused void *block_data)
+{
+ return biome == BIOME_HILLS;
+}
+
+static void oak_tree_leaf(Voxelctx *ctx)
+{
+ if (! voxelctx_is_alive(ctx))
+ 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);
+}
+
+static void oak_tree_top(Voxelctx *ctx)
+{
+ if (! voxelctx_is_alive(ctx))
+ return;
+
+ voxelctx_push(ctx);
+ 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);
+ }
+ voxelctx_pop(ctx);
+}
+
+static void oak_tree_part(Voxelctx *ctx, f32 n)
+{
+ if (! voxelctx_is_alive(ctx))
+ return;
+
+ voxelctx_push(ctx);
+ 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));
+
+ 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_cube(ctx, NODE_OAK_WOOD, true);
+ voxelctx_pop(ctx);
+
+ if (i == (int) (n - 2.0f)) {
+ voxelctx_push(ctx);
+ oak_tree_top(ctx);
+ voxelctx_pop(ctx);
+ }
+ }
+ voxelctx_pop(ctx);
+}
+
+static void oak_tree(v3s32 pos, List *changed_blocks)
+{
+ Voxelctx *ctx = voxelctx_create(changed_blocks, MGS_TREES, pos);
+
+ voxelctx_hue(ctx, 40.0f);
+ voxelctx_light(ctx, -0.5f);
+ voxelctx_sat(ctx, 0.5f);
+
+ /*voxelctx_s(ctx, 50);
+ voxelctx_ry(ctx, 45);
+
+ voxelctx_push(ctx);
+ voxelctx_cube(ctx, NODE_OAK_LEAVES, true);
+ voxelctx_pop(ctx);
+
+ voxelctx_delete(ctx);
+ if (true)
+ return;*/
+
+ f32 n = voxelctx_random(ctx, 40.0f, 10.0f);
+
+ voxelctx_push(ctx);
+ 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);
+ }
+ voxelctx_pop(ctx);
+
+ voxelctx_delete(ctx);
+}
+
+// pine
+
+static bool pine_condition(unused v3s32 pos, unused f64 humidity, unused f64 temperature, Biome biome, unused f64 factor, unused MapBlock *block, unused void *row_data, unused void *block_data)
+{
+ return biome == BIOME_MOUNTAIN;
+}
+
+static void pine_tree(v3s32 pos, List *changed_blocks)
+{
+ 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;
+ 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;
+
+ v3s32 dirs[4] = {
+ {+0, +0, +1},
+ {+1, +0, +0},
+ {+0, +0, -1},
+ {-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;
+
+ for (v3s32 branch_pos = tree_pos; branch_length > 0; branch_length--, branch_pos = v3s32_add(branch_pos, dirs[dir]))
+ mapgen_set_node(branch_pos, map_node_create(NODE_PINE_WOOD, NULL, 0), MGS_TREES, changed_blocks);
+
+ mapgen_set_node(tree_pos, map_node_create(NODE_PINE_WOOD, NULL, 0), MGS_TREES, changed_blocks);
+ }
+}
+
+// palm
+
+static bool palm_condition(v3s32 pos, unused f64 humidity, unused f64 temperature, Biome biome, unused f64 factor, unused MapBlock *block, void *row_data, unused void *block_data)
+{
+ return biome == BIOME_OCEAN
+ && ocean_get_node_at((v3s32) {pos.x, pos.y - 0, pos.z}, 1, row_data) == NODE_AIR
+ && ocean_get_node_at((v3s32) {pos.x, pos.y - 1, pos.z}, 0, row_data) == NODE_SAND;
+}
+
+static void palm_branch(Voxelctx *ctx)
+{
+ if (! voxelctx_is_alive(ctx))
+ 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);
+}
+
+static void palm_tree(v3s32 pos, List *changed_blocks)
+{
+ Voxelctx *ctx = voxelctx_create(changed_blocks, MGS_TREES, (v3s32) {pos.x, pos.y - 1, pos.z});
+
+ f32 s = voxelctx_random(ctx, 8.0f, 2.0f);
+
+ voxelctx_push(ctx);
+ 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);
+ }
+ voxelctx_pop(ctx);
+
+ voxelctx_z(ctx, s);
+ voxelctx_sat(ctx, 1.0f),
+ voxelctx_light(ctx, -0.5f);
+ voxelctx_hue(ctx, voxelctx_random(ctx, 50.0f, 30.0f));
+
+ voxelctx_push(ctx);
+ 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);
+ }
+ voxelctx_pop(ctx);
+
+ voxelctx_delete(ctx);
+}
+
+TreeDef tree_definitions[NUM_TREES] = {
+ // oak
+ {
+ .spread = 64.0f,
+ .probability = 0.0005f,
+ .area_probability = 0.3f,
+ .offset = SO_OAKTREE,
+ .area_offset = SO_OAKTREE_AREA,
+ .condition = &oak_condition,
+ .generate = &oak_tree,
+ },
+ // pine
+ {
+ .spread = 256.0f,
+ .probability = 0.01f,
+ .area_probability = 0.1f,
+ .offset = SO_PINETREE,
+ .area_offset = SO_PINETREE_AREA,
+ .condition = &pine_condition,
+ .generate = &pine_tree,
+ },
+ // palm
+ {
+ .spread = 16.0f,
+ .probability = 0.005f,
+ .area_probability = 0.5f,
+ .offset = SO_PALMTREE,
+ .area_offset = SO_PALMTREE_AREA,
+ .condition = &palm_condition,
+ .generate = &palm_tree,
+ },
+};
+
--- /dev/null
+#ifndef _TREES_H_
+#define _TREES_H_
+
+#include <dragontype/list.h>
+#include <dragontype/number.h>
+#include "perlin.h"
+
+#define NUM_TREES 3
+
+typedef struct
+{
+ f32 spread;
+ f32 probability;
+ f32 area_probability;
+ SeedOffset offset;
+ SeedOffset area_offset;
+ bool (*condition)(v3s32 pos, f64 humidity, f64 temperature, Biome biome, f64 factor, MapBlock *block, void *row_data, void *block_data);
+ void (*generate)(v3s32 pos, List *changed_blocks);
+} TreeDef;
+
+extern TreeDef tree_definitions[];
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "server/mapgen.h"
+#include "server/voxelctx.h"
+#include "perlin.h"
+#include "util.h"
+
+#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)
+
+static VoxelctxState *create_state(VoxelctxState *old)
+{
+ VoxelctxState *state = malloc(sizeof(VoxelctxState));
+
+ if (old) {
+ *state = *old;
+ state->strs = array_create(sizeof(char *));
+
+ for (size_t i = 0; i < old->strs.siz; i++) {
+ char *s = strdup(((char **) old->strs.ptr)[i]);
+ array_append(&state->strs, &s);
+ }
+ } else {
+ state->pos[0] = 0.0f;
+ state->pos[1] = 0.0f;
+ state->pos[2] = 0.0f;
+ state->pos[3] = 1.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;
+
+ state->strs = array_create(sizeof(char *));
+ char *s = format_string("glm.mat4()\n");
+ array_append(&state->strs, &s);
+ }
+
+ return state;
+}
+
+Voxelctx *voxelctx_create(List *changed_blocks, MapgenStage mgs, v3s32 pos)
+{
+ Voxelctx *ctx = malloc(sizeof(Voxelctx));
+
+ ctx->changed_blocks = changed_blocks;
+ ctx->mgs = mgs;
+ ctx->pos = pos;
+ ctx->statestack = list_create(NULL);
+ ctx->random = 0;
+
+ list_put(&ctx->statestack, create_state(NULL), NULL);
+
+ return ctx;
+}
+
+static void delete_state(VoxelctxState *state)
+{
+ for (size_t i = 0; i < state->strs.siz; i++)
+ free(((char **) state->strs.ptr)[i]);
+
+ free(state->strs.ptr);
+}
+
+static void list_delete_state(void *key, unused void *value, unused void *arg)
+{
+ delete_state(key);
+ free(key);
+}
+
+void voxelctx_delete(Voxelctx *ctx)
+{
+ list_clear_func(&ctx->statestack, &list_delete_state, NULL);
+ free(ctx);
+}
+
+static inline f32 mix(f32 x, f32 y, f32 t)
+{
+ return (1.0 - t) * x + t * y;
+}
+
+static void move_value(f32 *x, f32 v, f32 range)
+{
+ f32 dst = v >= 0 ? range : 0;
+ v = fabs(v);
+ *x = 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;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+ mat4x4_mul_vec4(translate_vec, VOXELCTXSTATE(ctx).mat, (vec4) {translate.x, translate.y, translate.z, 0.0f});
+#pragma GCC diagnostic pop
+ 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});
+}
+
+// swap y and z
+void voxelctx_z(Voxelctx *ctx, f32 value)
+{
+ apply_translation(ctx, (v3f32) {0.0f, value, 0.0f});
+}
+
+void voxelctx_y(Voxelctx *ctx, f32 value)
+{
+ apply_translation(ctx, (v3f32) {0.0f, 0.0f, value});
+}
+
+void voxelctx_rx(Voxelctx *ctx, f32 value)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+ mat4x4_rotate_X(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, value * M_PI / 180.0f);
+#pragma GCC diagnostic pop
+}
+
+// swap y and z
+void voxelctx_rz(Voxelctx *ctx, f32 value)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+
+ mat4x4_rotate_Y(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, value * M_PI / 180.0f);
+#pragma GCC diagnostic pop
+}
+
+void voxelctx_ry(Voxelctx *ctx, f32 value)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+ mat4x4_rotate_Z(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, value * M_PI / 180.0f);
+#pragma GCC diagnostic pop
+}
+
+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;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+ mat4x4_scale_aniso(VOXELCTXSTATE(ctx).mat, VOXELCTXSTATE(ctx).mat, scale.x, scale.y, scale.z);
+#pragma GCC diagnostic pop
+}
+
+void voxelctx_sx(Voxelctx *ctx, f32 value)
+{
+ apply_scale(ctx, (v3f32) {value, 1.0f, 1.0f});
+}
+
+// swap y and z
+void voxelctx_sz(Voxelctx *ctx, f32 value)
+{
+ apply_scale(ctx, (v3f32) {1.0f, value, 1.0f});
+}
+
+void voxelctx_sy(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)
+{
+ ListPair *next = ctx->statestack.first->next;
+ delete_state(ctx->statestack.first->key);
+ free(ctx->statestack.first->key);
+ free(ctx->statestack.first);
+ ctx->statestack.first = next;
+}
+
+void voxelctx_push(Voxelctx *ctx)
+{
+ ListPair *pair = malloc(sizeof(ListPair));
+ pair->key = create_state(&VOXELCTXSTATE(ctx));
+ pair->value = NULL;
+ pair->next = ctx->statestack.first;
+
+ ctx->statestack.first = pair;
+}
+
+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, Node 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;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+ mat4x4_mul_vec4(center, VOXELCTXSTATE(ctx).mat, (vec4) {0.5f, 0.5f, 0.5f});
+#pragma GCC diagnostic pop
+
+ for (int i = 0; i < 8; i++) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+ mat4x4_mul_vec4(corners[i], VOXELCTXSTATE(ctx).mat, base_corners[i]);
+#pragma GCC diagnostic pop
+
+ 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++)
+ v[i] = floor(VOXELCTXSTATE(ctx).pos[0] + 0.5f
+ + mix(corners[0][i], corners[4][i], (f32) x / (f32) max_len / 2.0f)
+ + mix(corners[0][i], corners[2][i], (f32) y / (f32) max_len / 2.0f)
+ + mix(corners[0][i], corners[1][i], (f32) z / (f32) max_len / 2.0f));
+
+ mapgen_set_node(v3s32_add(ctx->pos, (v3s32) {v[0], v[1], v[2]}), CREATE_NODE, ctx->mgs, ctx->changed_blocks);
+ }
+}
+
+/*
+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->mgs, ctx->changed_blocks);
+ }
+ }
+ }
+}
+*/
+
+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;
+}
--- /dev/null
+#ifndef _VOXELCTX_H_
+#define _VOXELCTX_H_
+
+#define VOXELCTXSTATE(ctx) (*((VoxelctxState *) (ctx)->statestack.first->key))
+
+#include <linmath.h/linmath.h>
+#include <dragontype/list.h>
+#include <dragontype/number.h>
+#include "server/server_map.h"
+
+
+
+#include <dragontype/array.h>
+
+
+typedef struct
+{
+ vec4 pos;
+ vec3 scale;
+ mat4x4 mat;
+ f32 h, s, l;
+ s32 life;
+ Array strs;
+} VoxelctxState;
+
+typedef struct
+{
+ v3s32 pos;
+ List *changed_blocks;
+ MapgenStage mgs;
+ List statestack;
+ s32 random;
+} Voxelctx;
+
+Voxelctx *voxelctx_create(List *changed_blocks, MapgenStage mgs, 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, Node node, bool use_hsl);
+void voxelctx_cylinder(Voxelctx *ctx, Node node, bool use_hsl);
+f32 voxelctx_random(Voxelctx *ctx, f32 base, f32 vary);
+
+#endif
va_end(args);
return ptr;
}
+
+void *buffer_read(unsigned char **buffer, size_t *bufsiz, size_t size)
+{
+ if (size == 0)
+ return NULL;
+
+ if (*bufsiz < size)
+ return NULL;
+
+ void *old_buffer = *buffer;
+
+ *bufsiz -= size;
+ *buffer += size;
+
+ return old_buffer;
+}
+
+void buffer_write(unsigned char **buffer, size_t *bufsiz, void *data, size_t size)
+{
+ if (size == 0)
+ return;
+
+ size_t old_bufsiz = *bufsiz;
+
+ *bufsiz += size;
+ *buffer = realloc(*buffer, *bufsiz);
+
+ memcpy(*buffer + old_bufsiz, data, size);
+}
bool within_simulation_distance(v3f64 player_pos, v3s32 block_pos, u32 simulation_distance); // return true if a player is close enough to a block to access it
f64 clamp(f64 v, f64 min, f64 max);
char *format_string(const char *format, ...);
+void *buffer_read(unsigned char **buffer, size_t *bufsiz, size_t size);
+void buffer_write(unsigned char **buffer, size_t *bufsiz, void *data, size_t size);
#endif