]> git.lizzy.rs Git - dragonblocks_alpha.git/commitdiff
Redesign file structure and graphics pipeline; add font rendering
authorElias Fleckenstein <eliasfleckenstein@web.de>
Thu, 15 Jul 2021 19:41:59 +0000 (21:41 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Thu, 15 Jul 2021 19:41:59 +0000 (21:41 +0200)
112 files changed:
BUILDING.md
README.md
fonts/Ubuntu.ttf [new file with mode: 0644]
shaders/3d/fragment.glsl [new file with mode: 0755]
shaders/3d/vertex.glsl [new file with mode: 0755]
shaders/fragment.glsl [deleted file]
shaders/hud/font/fragment.glsl [new file with mode: 0755]
shaders/hud/font/vertex.glsl [new file with mode: 0644]
shaders/hud/image/fragment.glsl [new file with mode: 0755]
shaders/hud/image/vertex.glsl [new file with mode: 0755]
shaders/vertex.glsl [deleted file]
src/Makefile
src/blockmesh.c [deleted file]
src/blockmesh.h [deleted file]
src/camera.c [deleted file]
src/camera.h [deleted file]
src/client.c [deleted file]
src/client.h [deleted file]
src/client/blockmesh.c [new file with mode: 0644]
src/client/blockmesh.h [new file with mode: 0644]
src/client/camera.c [new file with mode: 0644]
src/client/camera.h [new file with mode: 0644]
src/client/client.c [new file with mode: 0644]
src/client/client.h [new file with mode: 0644]
src/client/client_commands.c [new file with mode: 0644]
src/client/client_commands.h [new file with mode: 0644]
src/client/client_map.c [new file with mode: 0644]
src/client/client_map.h [new file with mode: 0644]
src/client/client_node.c [new file with mode: 0644]
src/client/client_node.h [new file with mode: 0644]
src/client/client_player.c [new file with mode: 0644]
src/client/client_player.h [new file with mode: 0644]
src/client/cube.c [new file with mode: 0644]
src/client/cube.h [new file with mode: 0644]
src/client/font.c [new file with mode: 0644]
src/client/font.h [new file with mode: 0644]
src/client/game.c [new file with mode: 0644]
src/client/game.h [new file with mode: 0644]
src/client/hud.c [new file with mode: 0644]
src/client/hud.h [new file with mode: 0644]
src/client/input.c [new file with mode: 0644]
src/client/input.h [new file with mode: 0644]
src/client/mesh.c [new file with mode: 0644]
src/client/mesh.h [new file with mode: 0644]
src/client/object.c [new file with mode: 0644]
src/client/object.h [new file with mode: 0644]
src/client/scene.c [new file with mode: 0644]
src/client/scene.h [new file with mode: 0644]
src/client/shader.c [new file with mode: 0644]
src/client/shader.h [new file with mode: 0644]
src/client/texture.c [new file with mode: 0644]
src/client/texture.h [new file with mode: 0644]
src/client/vertex.c [new file with mode: 0644]
src/client/vertex.h [new file with mode: 0644]
src/client/window.c [new file with mode: 0644]
src/client/window.h [new file with mode: 0644]
src/clientcommands.c [deleted file]
src/clientcommands.h [deleted file]
src/clientmap.c [deleted file]
src/clientmap.h [deleted file]
src/clientnode.c [deleted file]
src/clientnode.h [deleted file]
src/clientplayer.c [deleted file]
src/clientplayer.h [deleted file]
src/cube.c [deleted file]
src/cube.h [deleted file]
src/facecache.c [deleted file]
src/facecache.h [deleted file]
src/hud.c [deleted file]
src/hud.h [deleted file]
src/input.c [deleted file]
src/input.h [deleted file]
src/map.c
src/mapdb.c [deleted file]
src/mapdb.h [deleted file]
src/mapgen.c [deleted file]
src/mapgen.h [deleted file]
src/mesh.c [deleted file]
src/mesh.h [deleted file]
src/network.h
src/perlin.c [deleted file]
src/perlin.h [deleted file]
src/queue.c
src/queue.h
src/scene.c [deleted file]
src/scene.h [deleted file]
src/server.c [deleted file]
src/server.h [deleted file]
src/server/facecache.c [new file with mode: 0644]
src/server/facecache.h [new file with mode: 0644]
src/server/mapdb.c [new file with mode: 0644]
src/server/mapdb.h [new file with mode: 0644]
src/server/mapgen.c [new file with mode: 0644]
src/server/mapgen.h [new file with mode: 0644]
src/server/perlin.c [new file with mode: 0644]
src/server/perlin.h [new file with mode: 0644]
src/server/server.c [new file with mode: 0644]
src/server/server.h [new file with mode: 0644]
src/server/server_commands.c [new file with mode: 0644]
src/server/server_commands.h [new file with mode: 0644]
src/server/server_map.c [new file with mode: 0644]
src/server/server_map.h [new file with mode: 0644]
src/servercommands.c [deleted file]
src/servercommands.h [deleted file]
src/servermap.c [deleted file]
src/servermap.h [deleted file]
src/shaders.c [deleted file]
src/shaders.h [deleted file]
src/signal.c
src/signal.h
src/texture.c [deleted file]
src/texture.h [deleted file]

index cf02dc3bbbcc2961b44d7ed4a642509737660557..d253f990c1794cb626625906697cc74d281585f9 100644 (file)
@@ -9,10 +9,10 @@ To build anything you need gcc and GNU make. The ZLib development library is nee
 sudo apt install build-essential make zlib1g-dev
 ```
 
-The development versions of OpenGL, GLFW3, GLEW are required to build the client.
+The development versions of OpenGL, GLFW3, GLEW and Freetype are required to build the client.
 
 ```bash
-sudo apt install libgl1-mesa-dev libglfw3-dev libglew-dev
+sudo apt install libgl1-mesa-dev libglfw3-dev libglew-dev libfreetype-dev
 ```
 
 For building the server the SQLite3 development library is required.
index 777df2f6ff721e564fef3aaf4a2fbe3c489a9aa2..3e1ca257dcaef030e298e03e1d2b55ad7792aba9 100644 (file)
--- a/README.md
+++ b/README.md
@@ -25,10 +25,10 @@ Use W, A, S and D to move forward / left / backward / right and Space to jump.
 
 ## Dependencies
 
-The client depends on GLFW3, OpenGL and GLEW.
+The client depends on GLFW3, OpenGL, GLEW and Freetype.
 
 ```bash
-sudo apt install libgl1-mesa-dri libglfw3 libglew2.1
+sudo apt install libgl1-mesa-dri libglfw3 libglew2.1 libfreetype6
 ```
 
 The server depends on SQLite3.
diff --git a/fonts/Ubuntu.ttf b/fonts/Ubuntu.ttf
new file mode 100644 (file)
index 0000000..45a038b
Binary files /dev/null and b/fonts/Ubuntu.ttf differ
diff --git a/shaders/3d/fragment.glsl b/shaders/3d/fragment.glsl
new file mode 100755 (executable)
index 0000000..1b6a237
--- /dev/null
@@ -0,0 +1,22 @@
+#version 330 core
+
+in vec2 fragmentTextureCoords;
+in vec3 fragmentColor;
+
+out vec4 outColor;
+
+uniform sampler2D texture0;
+
+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()
+{
+       outColor = texture(texture0, fragmentTextureCoords) * vec4(hsv2rgb(vec3(fragmentColor)), 1.0);
+       if (outColor.a == 0.0)
+        discard;
+}
diff --git a/shaders/3d/vertex.glsl b/shaders/3d/vertex.glsl
new file mode 100755 (executable)
index 0000000..5eccd55
--- /dev/null
@@ -0,0 +1,20 @@
+#version 330 core
+
+layout(location = 0) in vec3 vertexPosition;
+layout(location = 1) in vec2 vertexTextureCoords;
+layout(location = 2) in vec3 vertexColor;
+
+out vec2 fragmentTextureCoords;
+out vec3 fragmentColor;
+
+uniform mat4 model;
+uniform mat4 view;
+uniform mat4 projection;
+
+void main()
+{
+    gl_Position = projection * view * model * vec4(vertexPosition, 1.0);
+    fragmentTextureCoords = vertexTextureCoords;
+       fragmentColor = vertexColor;
+}
+
diff --git a/shaders/fragment.glsl b/shaders/fragment.glsl
deleted file mode 100755 (executable)
index 1b6a237..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#version 330 core
-
-in vec2 fragmentTextureCoords;
-in vec3 fragmentColor;
-
-out vec4 outColor;
-
-uniform sampler2D texture0;
-
-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()
-{
-       outColor = texture(texture0, fragmentTextureCoords) * vec4(hsv2rgb(vec3(fragmentColor)), 1.0);
-       if (outColor.a == 0.0)
-        discard;
-}
diff --git a/shaders/hud/font/fragment.glsl b/shaders/hud/font/fragment.glsl
new file mode 100755 (executable)
index 0000000..b3c3f01
--- /dev/null
@@ -0,0 +1,15 @@
+#version 330 core
+
+in vec2 fragmentTextureCoords;
+
+out vec4 outColor;
+
+uniform sampler2D texture0;
+uniform vec3 textColor;
+
+void main()
+{
+       outColor = vec4(1.0, 1.0, 1.0, texture(texture0, fragmentTextureCoords).r) * vec4(textColor, 1.0);
+       if (outColor.a == 0.0)
+        discard;
+}
diff --git a/shaders/hud/font/vertex.glsl b/shaders/hud/font/vertex.glsl
new file mode 100644 (file)
index 0000000..00eac0f
--- /dev/null
@@ -0,0 +1,15 @@
+#version 330 core
+
+layout(location = 0) in vec2 vertexPosition;
+layout(location = 1) in vec2 vertexTextureCoords;
+
+out vec2 fragmentTextureCoords;
+
+uniform mat4 projection;
+uniform mat4 model;
+
+void main()
+{
+    gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
+    fragmentTextureCoords = vertexTextureCoords;
+}
diff --git a/shaders/hud/image/fragment.glsl b/shaders/hud/image/fragment.glsl
new file mode 100755 (executable)
index 0000000..13793e9
--- /dev/null
@@ -0,0 +1,14 @@
+#version 330 core
+
+in vec2 fragmentTextureCoords;
+
+out vec4 outColor;
+
+uniform sampler2D texture0;
+
+void main()
+{
+       outColor = texture(texture0, fragmentTextureCoords);
+       if (outColor.a == 0.0)
+        discard;
+}
diff --git a/shaders/hud/image/vertex.glsl b/shaders/hud/image/vertex.glsl
new file mode 100755 (executable)
index 0000000..162dd8a
--- /dev/null
@@ -0,0 +1,16 @@
+#version 330 core
+
+layout(location = 0) in vec2 vertexPosition;
+layout(location = 1) in vec2 vertexTextureCoords;
+
+out vec2 fragmentTextureCoords;
+
+uniform mat4 model;
+uniform mat4 projection;
+
+void main()
+{
+    gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
+    fragmentTextureCoords = vertexTextureCoords;
+}
+
diff --git a/shaders/vertex.glsl b/shaders/vertex.glsl
deleted file mode 100755 (executable)
index 5eccd55..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#version 330 core
-
-layout(location = 0) in vec3 vertexPosition;
-layout(location = 1) in vec2 vertexTextureCoords;
-layout(location = 2) in vec3 vertexColor;
-
-out vec2 fragmentTextureCoords;
-out vec3 fragmentColor;
-
-uniform mat4 model;
-uniform mat4 view;
-uniform mat4 projection;
-
-void main()
-{
-    gl_Position = projection * view * model * vec4(vertexPosition, 1.0);
-    fragmentTextureCoords = vertexTextureCoords;
-       fragmentColor = vertexColor;
-}
-
index cdb6c042338b5d0f2802d695aa5e08dff34a5786..604ee1e011a0581ccfe8549c0c02a59465e287ea 100644 (file)
@@ -1,6 +1,35 @@
 COMMON = array.o bintree.o list.o map.o signal.o util.o types.o node.o queue.o
-SERVER = $(COMMON) server.o servercommands.o servermap.o perlin.o facecache.o mapgen.o mapdb.o
-CLIENT = $(COMMON) camera.o client.o clientcommands.o clientmap.o clientnode.o clientplayer.o cube.o hud.o input.o mesh.o scene.o shaders.o blockmesh.o texture.o
+
+SERVER = $(COMMON) \
+       server/facecache.o \
+       server/mapdb.o \
+       server/mapgen.o \
+       server/perlin.o \
+       server/server.o \
+       server/server_commands.o  \
+       server/server_map.o \
+
+CLIENT = $(COMMON) \
+       client/blockmesh.o \
+       client/camera.o \
+       client/client.o \
+       client/client_commands.o \
+       client/client_map.o \
+       client/client_node.o \
+       client/client_player.o \
+       client/cube.o \
+       client/font.o \
+       client/game.o \
+       client/hud.o \
+       client/input.o \
+       client/mesh.o \
+       client/object.o \
+       client/scene.o \
+       client/shader.o \
+       client/texture.o \
+       client/vertex.o \
+       client/window.o \
+
 LIBRARIES = -lpthread -lm -lz
 FLAGS = -g -fmax-errors=4
 
@@ -8,19 +37,27 @@ ifdef RELEASE
 FLAGS = -O3 -DRELEASE
 endif
 
+CFLAGS = -Wall -Wextra -Wpedantic -Werror -iquote . -isystem ../deps
+
 all: Dragonblocks DragonblocksServer
 
 Dragonblocks: $(CLIENT)
-       cc $(FLAGS) -o Dragonblocks $(CLIENT) $(LIBRARIES) -lGL -lGLEW -lglfw
+       cc $(FLAGS) -o Dragonblocks $(CLIENT) $(LIBRARIES) -lGL -lGLEW -lglfw -lfreetype
 
 DragonblocksServer: $(SERVER)
        cc $(FLAGS) -o DragonblocksServer $(SERVER) $(LIBRARIES) -lsqlite3
 
 %.o: %.c
-       cc $(FLAGS) -Wall -Wextra -Wpedantic -Werror -isystem ../deps -c -o $@ $<
+       cc $(FLAGS) $(CFLAGS) -c -o $@ $<
+
+server/%.o: server/%.c
+       cc $(FLAGS) $(CFLAGS) -c -o $@ $<
+
+client/%.o: client/%.c
+       cc $(FLAGS) $(CFLAGS) -isystem /usr/include/freetype2 -c -o $@ $<
 
 clean:
-       rm -rf *.o
+       rm -rf *.o client/*.o server/*.o
 
 clobber: clean
        rm -rf Dragonblocks DragonblocksServer
diff --git a/src/blockmesh.c b/src/blockmesh.c
deleted file mode 100644 (file)
index 15babb3..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#include "blockmesh.h"
-#include "clientnode.h"
-#include "cube.h"
-
-static v3s8 fdir[6] = {
-       {+0, +0, -1},
-       {+0, +0, +1},
-       {-1, +0, +0},
-       {+1, +0, +0},
-       {+0, -1, +0},
-       {+0, +1, +0},
-};
-
-static VertexBuffer make_vertices(MapBlock *block, Map *map)
-{
-       VertexBuffer buffer = vertexbuffer_create();
-
-       ITERATE_MAPBLOCK {
-               MapNode *node = &block->data[x][y][z];
-
-               if (node_definitions[node->type].visible) {
-                       v3f offset = {x + 8.0f, y + 8.0f, z + 8.0f};
-
-                       ClientNodeDefintion *client_def = &client_node_definitions[node->type];
-                       vertexbuffer_set_texture(&buffer, client_def->texture);
-
-                       for (int f = 0; f < 6; f++) {
-                               v3s8 npos = {
-                                       x + fdir[f].x,
-                                       y + fdir[f].y,
-                                       z + fdir[f].z,
-                               };
-
-                               Node neighbor;
-
-                               if (npos.x >= 0 && npos.x < 16 && npos.y >= 0 && npos.y < 16 && npos.z >= 0 && npos.z < 16)
-                                       neighbor = block->data[npos.x][npos.y][npos.z].type;
-                               else
-                                       neighbor = map_get_node(map, (v3s32) {npos.x + block->pos.x * 16, npos.y + block->pos.y * 16, npos.z + block->pos.z * 16}).type;
-
-                               if (neighbor != NODE_UNLOADED && ! node_definitions[neighbor].visible) {
-                                       for (int v = 0; v < 6; v++) {
-                                               Vertex vertex = cube_vertices[f][v];
-                                               vertex.x += offset.x;
-                                               vertex.y += offset.y;
-                                               vertex.z += offset.z;
-
-                                               if (client_def->render)
-                                                       client_def->render(node, &vertex);
-
-                                               vertexbuffer_add_vertex(&buffer, &vertex);
-                                       }
-                               }
-                       }
-               }
-       }
-
-       return buffer;
-}
-
-#undef GNODDEF
-#undef VALIDPOS
-
-void make_block_mesh(MapBlock *block, Map *map, Scene *scene)
-{
-       MeshObject *old = block->extra;
-       block->extra = meshobject_create(make_vertices(block, map), scene, (v3f) {block->pos.x * 16.0f - 8.0f, block->pos.y * 16.0f - 8.0f, block->pos.z * 16.0f - 8.0f});
-       if (old)
-               old->remove = true;
-}
diff --git a/src/blockmesh.h b/src/blockmesh.h
deleted file mode 100644 (file)
index 099caa0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _BLOCKMESH_H_
-#define _BLOCKMESH_H_
-
-#include "map.h"
-#include "scene.h"
-
-void make_block_mesh(MapBlock *block, Map *map, Scene *scene);
-
-#endif
diff --git a/src/camera.c b/src/camera.c
deleted file mode 100644 (file)
index 6964f0a..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-#include <math.h>
-#include "client.h"
-#include "camera.h"
-
-static struct
-{
-       mat4x4 view, projection;
-       GLFWwindow *window;
-       ShaderProgram *prog;
-
-       vec3 eye, front, right, up;
-} camera;
-
-static vec3 world_up = {0.0f, 1.0f, 0.0f};
-
-struct movement_dirs movement_dirs;
-
-static void update_camera()
-{
-       vec3 center;
-       vec3_add(center, camera.eye, camera.front);
-
-       mat4x4_look_at(camera.view, camera.eye, center, camera.up);
-}
-
-void camera_enable()
-{
-       glUniformMatrix4fv(camera.prog->loc_view, 1, GL_FALSE, camera.view[0]);
-       glUniformMatrix4fv(camera.prog->loc_projection, 1, GL_FALSE, camera.projection[0]);
-}
-
-void set_camera_position(v3f pos)
-{
-       camera.eye[0] = pos.x;
-       camera.eye[1] = pos.y;
-       camera.eye[2] = pos.z;
-
-       update_camera();
-}
-
-void set_camera_angle(f32 yaw, f32 pitch)
-{
-       camera.front[0] = movement_dirs.front[0] = cos(yaw) * cos(pitch);
-       camera.front[1] = sin(pitch);
-       camera.front[2] = movement_dirs.front[2] = sin(yaw) * cos(pitch);
-
-       vec3_norm(camera.front, camera.front);
-       vec3_norm(movement_dirs.front, movement_dirs.front);
-
-       vec3_mul_cross(camera.right, camera.front, world_up);
-       movement_dirs.right[0] = camera.right[0];
-       movement_dirs.right[2] = camera.right[2];
-
-       vec3_norm(camera.right, camera.right);
-       vec3_norm(movement_dirs.right, movement_dirs.right);
-
-       vec3_mul_cross(camera.up, camera.right, camera.front);
-       vec3_norm(camera.up, camera.up);
-
-       update_camera();
-}
-
-void camera_on_resize(int width, int height)
-{
-       mat4x4_perspective(camera.projection, 86.1f / 180.0f * M_PI, (float) width / (float) height, 0.01f, 1000.0f);
-}
-
-void init_camera(GLFWwindow *window, ShaderProgram *prog)
-{
-       camera.window = window;
-       camera.prog = prog;
-}
diff --git a/src/camera.h b/src/camera.h
deleted file mode 100644 (file)
index affdbcf..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _CAMERA_H_
-#define _CAMERA_H_
-
-#include <GL/glew.h>
-#include <GLFW/glfw3.h>
-#include <linmath.h/linmath.h>
-#include "shaders.h"
-#include "types.h"
-
-void init_camera(GLFWwindow *window, ShaderProgram *prog);
-void set_camera_position(v3f pos);
-void set_camera_angle(f32 yaw, f32 pitch);
-void camera_on_resize(int width, int height);
-void camera_enable();
-
-extern struct movement_dirs
-{
-       vec3 front;
-       vec3 right;
-} movement_dirs;
-
-#endif
diff --git a/src/client.c b/src/client.c
deleted file mode 100644 (file)
index b4c17fb..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <math.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <errno.h>
-#include <netdb.h>
-#include <GL/glew.h>
-#include <GL/gl.h>
-#include <GLFW/glfw3.h>
-#include "camera.h"
-#include "client.h"
-#include "clientmap.h"
-#include "clientnode.h"
-#include "cube.h"
-#include "hud.h"
-#include "input.h"
-#include "signal.h"
-#include "shaders.h"
-#include "util.h"
-
-Client client;
-
-void client_disconnect(bool send, const char *detail)
-{
-       pthread_mutex_lock(&client.mtx);
-       if (client.state != CS_DISCONNECTED) {
-               if (send)
-                       write_u32(client.fd, SC_DISCONNECT);
-
-               client.state = CS_DISCONNECTED;
-               printf("Disconnected %s%s%s\n", INBRACES(detail));
-               close(client.fd);
-       }
-       pthread_mutex_unlock(&client.mtx);
-}
-
-#include "network.c"
-
-static void *reciever_thread(__attribute__((unused)) void *unused)
-{
-       handle_packets(&client);
-
-       if (errno != EINTR)
-               client_disconnect(false, "network error");
-
-       return NULL;
-}
-
-static void framebuffer_size_callback(__attribute__((unused)) GLFWwindow* window, int width, int height)
-{
-       glViewport(0, 0, width, height);
-
-       camera_on_resize(width, height);
-       hud_on_resize(width, height);
-       input_on_resize(width, height);
-}
-
-static void cursor_pos_callback(__attribute__((unused)) GLFWwindow* window, double current_x, double current_y)
-{
-       input_on_cursor_pos(current_x, current_y);
-}
-
-static void window_pos_callback(__attribute__((unused)) GLFWwindow* window, int x, int y)
-{
-       input_on_window_pos(x, y);
-}
-
-static void client_loop()
-{
-       if(! glfwInit()) {
-               printf("Failed to initialize GLFW\n");
-               return;
-       }
-
-       glfwWindowHint(GLFW_SAMPLES, 8);
-       glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
-       glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
-       glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-
-       int width, height;
-       width = 1250;
-       height = 750;
-
-       GLFWwindow *window = glfwCreateWindow(width, height, "Dragonblocks", NULL, NULL);
-
-       if (! window) {
-               fprintf(stderr, "Failed to create window\n");
-               glfwTerminate();
-               return;
-       }
-
-       glfwMakeContextCurrent(window);
-       if (glewInit() != GLEW_OK) {
-               fprintf(stderr, "Failed to initialize GLEW\n");
-               return;
-       }
-
-       glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
-
-       ShaderProgram *prog = create_shader_program(RESSOURCEPATH "shaders");
-       if (! prog) {
-               fprintf(stderr, "Failed to create shader program\n");
-               return;
-       }
-
-       init_client_node_definitions();
-       clientmap_start_meshgen();
-
-       glUseProgram(prog->id);
-
-       init_camera(window, prog);
-
-       set_camera_position((v3f) {0.0f, 0.0f, 0.0f});
-       set_camera_angle(0.0f, 0.0f);
-
-       camera_on_resize(width, height);
-
-       hud_init(prog);
-       hud_on_resize(width, height);
-
-       hud_add(RESSOURCEPATH "textures/crosshair.png", (v3f) {0.0f, 0.0f, 0.0f}, (v2f) {1.0f, 1.0f}, HUD_SCALE_TEXTURE);
-
-       init_input(&client, window);
-       input_on_resize(width, height);
-
-       clientplayer_add_to_scene(&client.player);
-
-       glfwSetFramebufferSizeCallback(window, &framebuffer_size_callback);
-       glfwSetCursorPosCallback(window, &cursor_pos_callback);
-       glfwSetWindowPosCallback(window, &window_pos_callback);
-
-       struct timespec ts, ts_old;
-       clock_gettime(CLOCK_REALTIME, &ts_old);
-
-       while (! glfwWindowShouldClose(window) && client.state != CS_DISCONNECTED && ! interrupted) {
-               clock_gettime(CLOCK_REALTIME, &ts);
-               f64 dtime = (f64) (ts.tv_sec - ts_old.tv_sec) + (f64) (ts.tv_nsec - ts_old.tv_nsec) / 1000000000.0;
-               ts_old = ts;
-
-               glEnable(GL_DEPTH_TEST);
-               glEnable(GL_BLEND);
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-               glClearColor(0.52941176470588f, 0.8078431372549f, 0.92156862745098f, 1.0f);
-
-               process_input();
-               clientplayer_tick(&client.player, dtime);
-
-               camera_enable();
-               scene_render(client.scene, prog);
-
-               hud_render();
-
-               glfwSwapBuffers(window);
-               glfwPollEvents();
-       }
-
-       delete_shader_program(prog);
-       hud_deinit();
-}
-
-static bool client_name_prompt()
-{
-       printf("Enter name: ");
-       fflush(stdout);
-       char name[NAME_MAX];
-       if (scanf("%s", name) == EOF)
-               return false;
-       client.name = strdup(name);
-       pthread_mutex_lock(&client.mtx);
-       if (write_u32(client.fd, SC_AUTH) && write(client.fd, client.name, strlen(client.name) + 1)) {
-               client.state = CS_AUTH;
-               printf("Authenticating...\n");
-       }
-       pthread_mutex_unlock(&client.mtx);
-       return true;
-}
-
-static bool client_authenticate()
-{
-       for ever {
-               switch (client.state) {
-                       case CS_CREATED:
-                               if (client_name_prompt())
-                                       break;
-                               else
-                                       return false;
-                       case CS_AUTH:
-                               if (interrupted)
-                                       return false;
-                               else
-                                       sched_yield();
-                               break;
-                       case CS_ACTIVE:
-                               return true;
-                       case CS_DISCONNECTED:
-                               return false;
-               }
-       }
-       return false;
-}
-
-static void client_start(int fd)
-{
-       client.fd = fd;
-       pthread_mutex_init(&client.mtx, NULL);
-       client.state = CS_CREATED;
-       client.name = NULL;
-       client.map = map_create();
-       client.scene = scene_create();
-
-       clientplayer_init(&client);
-       clientmap_init(&client);
-
-       pthread_t recv_thread;
-       pthread_create(&recv_thread, NULL, &reciever_thread, NULL);
-
-       if (client_authenticate())
-               client_loop();
-
-       if (client.state != CS_DISCONNECTED)
-               client_disconnect(true, NULL);
-
-       if (client.name)
-               free(client.name);
-
-       clientmap_deinit();
-
-       map_delete(client.map);
-       scene_delete(client.scene);
-
-       pthread_mutex_destroy(&client.mtx);
-}
-
-int main(int argc, char **argv)
-{
-       program_name = argv[0];
-
-       if (argc < 3)
-               internal_error("missing address or port");
-
-       struct addrinfo hints = {
-               .ai_family = AF_UNSPEC,
-               .ai_socktype = SOCK_STREAM,
-               .ai_protocol = 0,
-               .ai_flags = AI_NUMERICSERV,
-       };
-
-       struct addrinfo *info = NULL;
-
-       int gai_state = getaddrinfo(argv[1], argv[2], &hints, &info);
-
-       if (gai_state != 0)
-               internal_error(gai_strerror(gai_state));
-
-       int fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
-
-       if (fd == -1)
-               syscall_error("socket");
-
-       if (connect(fd, info->ai_addr, info->ai_addrlen) == -1)
-               syscall_error("connect");
-
-       char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
-       printf("Connected to %s\n", addrstr);
-       free(addrstr);
-
-       freeaddrinfo(info);
-
-       init_signal_handlers();
-       client_start(fd);
-
-       return EXIT_SUCCESS;
-}
diff --git a/src/client.h b/src/client.h
deleted file mode 100644 (file)
index 8e7e28f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _CLIENT_H_
-#define _CLIENT_H_
-
-#include <stdbool.h>
-#include <pthread.h>
-#include "servercommands.h"
-#include "clientcommands.h"
-#include "clientplayer.h"
-#include "map.h"
-#include "network.h"
-#include "scene.h"
-
-#ifdef RELEASE
-       #define RESSOURCEPATH ""
-#else
-       #define RESSOURCEPATH "../"
-#endif
-
-typedef struct Client
-{
-       int fd;
-       pthread_mutex_t mtx;
-       ClientState state;
-       char *name;
-       Map *map;
-       Scene *scene;
-       ClientPlayer player;
-} Client;
-
-void client_disconnect(bool send, const char *detail);
-
-#endif
diff --git a/src/client/blockmesh.c b/src/client/blockmesh.c
new file mode 100644 (file)
index 0000000..ef76424
--- /dev/null
@@ -0,0 +1,73 @@
+#include "client/blockmesh.h"
+#include "client/client_node.h"
+#include "client/cube.h"
+
+static v3s8 fdir[6] = {
+       {+0, +0, -1},
+       {+0, +0, +1},
+       {-1, +0, +0},
+       {+1, +0, +0},
+       {+0, -1, +0},
+       {+0, +1, +0},
+};
+
+static void make_vertices(Object *object, MapBlock *block, Map *map)
+{
+       ITERATE_MAPBLOCK {
+               MapNode *node = &block->data[x][y][z];
+
+               if (node_definitions[node->type].visible) {
+                       v3f offset = {x + 8.0f, y + 8.0f, z + 8.0f};
+
+                       ClientNodeDefintion *client_def = &client_node_definitions[node->type];
+                       object_set_texture(object, client_def->texture);
+
+                       for (int f = 0; f < 6; f++) {
+                               v3s8 npos = {
+                                       x + fdir[f].x,
+                                       y + fdir[f].y,
+                                       z + fdir[f].z,
+                               };
+
+                               Node neighbor;
+
+                               if (npos.x >= 0 && npos.x < 16 && npos.y >= 0 && npos.y < 16 && npos.z >= 0 && npos.z < 16)
+                                       neighbor = block->data[npos.x][npos.y][npos.z].type;
+                               else
+                                       neighbor = map_get_node(map, (v3s32) {npos.x + block->pos.x * 16, npos.y + block->pos.y * 16, npos.z + block->pos.z * 16}).type;
+
+                               if (neighbor != NODE_UNLOADED && ! node_definitions[neighbor].visible) {
+                                       for (int v = 0; v < 6; v++) {
+                                               Vertex3D vertex = cube_vertices[f][v];
+                                               vertex.position.x += offset.x;
+                                               vertex.position.y += offset.y;
+                                               vertex.position.z += offset.z;
+
+                                               if (client_def->render)
+                                                       client_def->render(node, &vertex);
+
+                                               object_add_vertex(object, &vertex);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+void blockmesh_make(MapBlock *block, Map *map)
+{
+       Object *obj = object_create();
+       obj->pos = (v3f) {block->pos.x * 16.0f - 8.0f, block->pos.y * 16.0f - 8.0f, block->pos.z * 16.0f - 8.0f};
+
+       make_vertices(obj, block, map);
+
+       if (! object_add_to_scene(obj)) {
+               object_delete(obj);
+               obj = NULL;
+       }
+
+       if (block->extra)
+               ((Object *) block->extra)->remove = true;
+
+       block->extra = obj;
+}
diff --git a/src/client/blockmesh.h b/src/client/blockmesh.h
new file mode 100644 (file)
index 0000000..d2c3840
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _BLOCKMESH_H_
+#define _BLOCKMESH_H_
+
+#include "client/scene.h"
+#include "map.h"
+
+void blockmesh_make(MapBlock *block, Map *map);
+
+#endif
diff --git a/src/client/camera.c b/src/client/camera.c
new file mode 100644 (file)
index 0000000..eda29f0
--- /dev/null
@@ -0,0 +1,57 @@
+#include <math.h>
+#include "client/client.h"
+#include "client/camera.h"
+
+static struct
+{
+       mat4x4 view;
+       vec3 eye, front, right, up;
+} camera;
+
+static vec3 world_up = {0.0f, 1.0f, 0.0f};
+
+struct camera_movement_dirs camera_movement_dirs;
+
+static void camera_update()
+{
+       vec3 center;
+       vec3_add(center, camera.eye, camera.front);
+
+       mat4x4_look_at(camera.view, camera.eye, center, camera.up);
+}
+
+void camera_enable(GLint loc_view)
+{
+       glUniformMatrix4fv(loc_view, 1, GL_FALSE, camera.view[0]);
+}
+
+void camera_set_position(v3f pos)
+{
+       camera.eye[0] = pos.x;
+       camera.eye[1] = pos.y;
+       camera.eye[2] = pos.z;
+
+       camera_update();
+}
+
+void camera_set_angle(f32 yaw, f32 pitch)
+{
+       camera.front[0] = camera_movement_dirs.front[0] = cos(yaw) * cos(pitch);
+       camera.front[1] = sin(pitch);
+       camera.front[2] = camera_movement_dirs.front[2] = sin(yaw) * cos(pitch);
+
+       vec3_norm(camera.front, camera.front);
+       vec3_norm(camera_movement_dirs.front, camera_movement_dirs.front);
+
+       vec3_mul_cross(camera.right, camera.front, world_up);
+       camera_movement_dirs.right[0] = camera.right[0];
+       camera_movement_dirs.right[2] = camera.right[2];
+
+       vec3_norm(camera.right, camera.right);
+       vec3_norm(camera_movement_dirs.right, camera_movement_dirs.right);
+
+       vec3_mul_cross(camera.up, camera.right, camera.front);
+       vec3_norm(camera.up, camera.up);
+
+       camera_update();
+}
diff --git a/src/client/camera.h b/src/client/camera.h
new file mode 100644 (file)
index 0000000..319a5fb
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _CAMERA_H_
+#define _CAMERA_H_
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+#include <linmath.h/linmath.h>
+#include "types.h"
+
+void camera_set_position(v3f pos);
+void camera_set_angle(f32 yaw, f32 pitch);
+void camera_on_resize(int width, int height);
+void camera_enable(GLint loc_view);
+
+extern struct camera_movement_dirs
+{
+       vec3 front;
+       vec3 right;
+} camera_movement_dirs;
+
+#endif
diff --git a/src/client/client.c b/src/client/client.c
new file mode 100644 (file)
index 0000000..6d31cc5
--- /dev/null
@@ -0,0 +1,161 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include "client/client.h"
+#include "client/client_map.h"
+#include "client/client_player.h"
+#include "client/game.h"
+#include "client/input.h"
+#include "signal.h"
+#include "util.h"
+
+Client client;
+
+void client_disconnect(bool send, const char *detail)
+{
+       pthread_mutex_lock(&client.mtx);
+       if (client.state != CS_DISCONNECTED) {
+               if (send)
+                       write_u32(client.fd, SC_DISCONNECT);
+
+               client.state = CS_DISCONNECTED;
+               printf("Disconnected %s%s%s\n", INBRACES(detail));
+               close(client.fd);
+       }
+       pthread_mutex_unlock(&client.mtx);
+}
+
+void client_send_position(v3f pos)
+{
+       pthread_mutex_lock(&client.mtx);
+       (void) (write_u32(client.fd, SC_POS) && write_v3f32(client.fd, pos));
+       pthread_mutex_unlock(&client.mtx);
+}
+
+#include "network.c"
+
+static void *reciever_thread(__attribute__((unused)) void *unused)
+{
+       handle_packets(&client);
+
+       if (errno != EINTR)
+               client_disconnect(false, "network error");
+
+       return NULL;
+}
+
+static bool client_name_prompt()
+{
+       printf("Enter name: ");
+       fflush(stdout);
+       char name[PLAYER_NAME_MAX];
+       if (scanf("%s", name) == EOF)
+               return false;
+       client.name = strdup(name);
+       pthread_mutex_lock(&client.mtx);
+       if (write_u32(client.fd, SC_AUTH) && write(client.fd, client.name, strlen(client.name) + 1)) {
+               client.state = CS_AUTH;
+               printf("Authenticating...\n");
+       }
+       pthread_mutex_unlock(&client.mtx);
+       return true;
+}
+
+static bool client_authenticate()
+{
+       for ever {
+               switch (client.state) {
+                       case CS_CREATED:
+                               if (client_name_prompt())
+                                       break;
+                               else
+                                       return false;
+                       case CS_AUTH:
+                               if (interrupted)
+                                       return false;
+                               else
+                                       sched_yield();
+                               break;
+                       case CS_ACTIVE:
+                               return true;
+                       case CS_DISCONNECTED:
+                               return false;
+               }
+       }
+       return false;
+}
+
+static void client_start(int fd)
+{
+       client.fd = fd;
+       pthread_mutex_init(&client.mtx, NULL);
+       client.state = CS_CREATED;
+       client.name = NULL;
+       client.map = map_create();
+
+       client_player_init(client.map);
+       client_map_init(client.map);
+
+       pthread_t recv_thread;
+       pthread_create(&recv_thread, NULL, &reciever_thread, NULL);
+
+       if (client_authenticate())
+               game(&client);
+
+       if (client.state != CS_DISCONNECTED)
+               client_disconnect(true, NULL);
+
+       if (client.name)
+               free(client.name);
+
+       client_map_deinit();
+
+       map_delete(client.map);
+
+       pthread_mutex_destroy(&client.mtx);
+}
+
+int main(int argc, char **argv)
+{
+       program_name = argv[0];
+
+       if (argc < 3)
+               internal_error("missing address or port");
+
+       struct addrinfo hints = {
+               .ai_family = AF_UNSPEC,
+               .ai_socktype = SOCK_STREAM,
+               .ai_protocol = 0,
+               .ai_flags = AI_NUMERICSERV,
+       };
+
+       struct addrinfo *info = NULL;
+
+       int gai_state = getaddrinfo(argv[1], argv[2], &hints, &info);
+
+       if (gai_state != 0)
+               internal_error(gai_strerror(gai_state));
+
+       int fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
+
+       if (fd == -1)
+               syscall_error("socket");
+
+       if (connect(fd, info->ai_addr, info->ai_addrlen) == -1)
+               syscall_error("connect");
+
+       char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
+       printf("Connected to %s\n", addrstr);
+       free(addrstr);
+
+       freeaddrinfo(info);
+
+       signal_handlers_init();
+       client_start(fd);
+
+       return EXIT_SUCCESS;
+}
diff --git a/src/client/client.h b/src/client/client.h
new file mode 100644 (file)
index 0000000..badac31
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _CLIENT_H_
+#define _CLIENT_H_
+
+#include <stdbool.h>
+#include <pthread.h>
+#include "client/client_commands.h"
+#include "client/scene.h"
+#include "server/server_commands.h"
+#include "map.h"
+#include "network.h"
+#include "types.h"
+
+#ifdef RELEASE
+       #define RESSOURCEPATH ""
+#else
+       #define RESSOURCEPATH "../"
+#endif
+
+typedef struct Client
+{
+       int fd;
+       pthread_mutex_t mtx;
+       ClientState state;
+       char *name;
+       Map *map;
+} Client;
+
+void client_disconnect(bool send, const char *detail);
+void client_send_position(v3f pos);
+
+#endif
diff --git a/src/client/client_commands.c b/src/client/client_commands.c
new file mode 100644 (file)
index 0000000..5581c0f
--- /dev/null
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <unistd.h>
+#include "client/client.h"
+#include "client/client_map.h"
+#include "types.h"
+
+static bool disconnect_handler(__attribute__((unused)) Client *client, bool good)
+{
+       if (good)
+               client_disconnect(false, NULL);
+       return true;
+}
+
+static bool auth_handler(Client *client, bool good)
+{
+       u8 success;
+       if (! read_u8(client->fd, &success))
+               return false;
+
+       if (! good)
+               return true;
+
+       if (success) {
+               printf("Authenticated successfully\n");
+               client->state = CS_ACTIVE;
+       } else {
+               printf("Authentication failed, please try again\n");
+               client->state = CS_CREATED;
+       }
+
+       return true;
+}
+
+static bool block_handler(Client *client, bool good)
+{
+       v3s32 pos;
+
+       if (! read_v3s32(client->fd, &pos))
+               return false;
+
+       MapBlockHeader header;
+
+       if (! read_u32(client->fd, &header))
+               return false;
+
+       char data[header];
+       if (! read_full(client->fd, data, header))
+               return false;
+
+       MapBlock *block;
+
+       if (good)
+               block = map_get_block(client->map, pos, true);
+       else
+               block = map_allocate_block(pos);
+
+       if (block->state != MBS_CREATED)
+               map_clear_meta(block);
+
+       bool ret = map_deserialize_block(block, data, header);
+
+       if (good)
+               client_map_block_changed(block);
+       else
+               map_free_block(block);
+
+       return ret;
+}
+
+CommandHandler command_handlers[CLIENT_COMMAND_COUNT] = {
+       {0},
+       {&disconnect_handler, "DISCONNECT", CS_CREATED | CS_AUTH | CS_ACTIVE},
+       {&auth_handler, "AUTH", CS_AUTH},
+       {&block_handler, "BLOCK", CS_ACTIVE},
+};
diff --git a/src/client/client_commands.h b/src/client/client_commands.h
new file mode 100644 (file)
index 0000000..58bb9e4
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _CLIENT_COMMANDS_H_
+#define _CLIENT_COMMANDS_H_
+
+typedef enum
+{
+       CLIENT_COMMAND_NULL,
+       CC_DISCONNECT,
+       CC_AUTH,
+       CC_BLOCK,
+       CLIENT_COMMAND_COUNT
+} ClientCommand;
+
+#ifdef _SERVER_H_
+typedef ClientCommand RemoteCommand;
+#endif
+
+#ifdef _CLIENT_H_
+typedef ClientCommand HostCommand;
+#define HOST_COMMAND_COUNT CLIENT_COMMAND_COUNT
+#endif
+
+#endif
diff --git a/src/client/client_map.c b/src/client/client_map.c
new file mode 100644 (file)
index 0000000..843cbdd
--- /dev/null
@@ -0,0 +1,75 @@
+#include <stdlib.h>
+#include <pthread.h>
+#include "client/blockmesh.h"
+#include "client/client_map.h"
+#include "queue.h"
+
+static struct
+{
+       Map *map;
+       Queue *queue;
+       pthread_t thread;
+       bool cancel;
+} client_map;
+
+static void set_block_ready(void *block)
+{
+       ((MapBlock *) block)->state = MBS_READY;
+}
+
+static void *meshgen_thread(__attribute__((unused)) void *unused)
+{
+       while (! client_map.cancel) {
+               MapBlock *block;
+               if ((block = queue_dequeue_callback(client_map.queue, &set_block_ready)))
+                       blockmesh_make(block, client_map.map);
+               else
+                       sched_yield();
+       }
+
+       return NULL;
+}
+
+void client_map_init(Map *map)
+{
+       client_map.map = map;
+       client_map.queue = queue_create();
+}
+
+void client_map_start_meshgen()
+{
+       pthread_create(&client_map.thread, NULL, &meshgen_thread, NULL);
+}
+
+void client_map_deinit()
+{
+       client_map.cancel = true;
+       queue_delete(client_map.queue);
+       if (client_map.thread)
+               pthread_join(client_map.thread, NULL);
+}
+
+static void schedule_update_block(MapBlock *block)
+{
+       if (! block)
+               return;
+
+       pthread_mutex_lock(&block->mtx);
+       if (block->state != MBS_PROCESSING) {
+               block->state = MBS_PROCESSING;
+               queue_enqueue(client_map.queue, block);
+       }
+       pthread_mutex_unlock(&block->mtx);
+}
+
+void client_map_block_changed(MapBlock *block)
+{
+       schedule_update_block(block);
+
+       schedule_update_block(map_get_block(client_map.map, (v3s32) {block->pos.x + 1, block->pos.y + 0, block->pos.z + 0}, false));
+       schedule_update_block(map_get_block(client_map.map, (v3s32) {block->pos.x + 0, block->pos.y + 1, block->pos.z + 0}, false));
+       schedule_update_block(map_get_block(client_map.map, (v3s32) {block->pos.x + 0, block->pos.y + 0, block->pos.z + 1}, false));
+       schedule_update_block(map_get_block(client_map.map, (v3s32) {block->pos.x - 1, block->pos.y - 0, block->pos.z - 0}, false));
+       schedule_update_block(map_get_block(client_map.map, (v3s32) {block->pos.x - 0, block->pos.y - 1, block->pos.z - 0}, false));
+       schedule_update_block(map_get_block(client_map.map, (v3s32) {block->pos.x - 0, block->pos.y - 0, block->pos.z - 1}, false));
+}
diff --git a/src/client/client_map.h b/src/client/client_map.h
new file mode 100644 (file)
index 0000000..40949cc
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _CLIENT_MAP_H_
+#define _CLIENT_MAP_H_
+
+#include "map.h"
+
+void client_map_init(Map *map);
+void client_map_start_meshgen();
+void client_map_deinit();
+void client_map_block_changed(MapBlock *block);
+
+#endif
diff --git a/src/client/client_node.c b/src/client/client_node.c
new file mode 100644 (file)
index 0000000..739e7c6
--- /dev/null
@@ -0,0 +1,58 @@
+#include "client/client.h"
+#include "client/client_node.h"
+#include "node.h"
+
+static void render_state_biome(MapNode *node, Vertex3D *vertex)
+{
+       vertex->color.h = node->state.biome.x;
+       vertex->color.s = node->state.biome.y;
+       vertex->color.v = node->state.biome.z;
+}
+
+ClientNodeDefintion client_node_definitions[NODE_UNLOADED] = {
+       // invalid
+       {
+               .texture_path = RESSOURCEPATH "textures/invalid.png",
+               .texture = NULL,
+               .render = NULL,
+       },
+       // air
+       {
+               .texture_path = NULL,
+               .texture = NULL,
+               .render = NULL,
+       },
+       // grass
+       {
+               .texture_path = RESSOURCEPATH "textures/grass.png",
+               .texture = NULL,
+               .render = &render_state_biome,
+       },
+       // dirt
+       {
+               .texture_path = RESSOURCEPATH "textures/dirt.png",
+               .texture = NULL,
+               .render = NULL,
+       },
+       // stone
+       {
+               .texture_path = RESSOURCEPATH "textures/stone.png",
+               .texture = NULL,
+               .render = NULL,
+       },
+       // snow
+       {
+               .texture_path = RESSOURCEPATH "textures/snow.png",
+               .texture = NULL,
+               .render = NULL,
+       },
+};
+
+void client_node_init()
+{
+       for (Node node = NODE_INVALID; node < NODE_UNLOADED; node++) {
+               ClientNodeDefintion *def = &client_node_definitions[node];
+               if (def->texture_path)
+                       def->texture = texture_get(def->texture_path);
+       }
+}
diff --git a/src/client/client_node.h b/src/client/client_node.h
new file mode 100644 (file)
index 0000000..0ab64c9
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _CLIENT_NODE_H_
+#define _CLIENT_NODE_H_
+
+#include "client/object.h"
+#include "client/texture.h"
+#include "map.h"
+
+typedef struct
+{
+       char *texture_path;
+       Texture *texture;
+       void (*render)(MapNode *node, Vertex3D *vertex);
+} ClientNodeDefintion;
+
+extern ClientNodeDefintion client_node_definitions[];
+void client_node_init();
+
+#endif
diff --git a/src/client/client_player.c b/src/client/client_player.c
new file mode 100644 (file)
index 0000000..e4a3a6c
--- /dev/null
@@ -0,0 +1,147 @@
+#include "client/camera.h"
+#include "client/client.h"
+#include "client/client_player.h"
+#include "client/cube.h"
+#include "client/texture.h"
+
+struct ClientPlayer client_player;
+
+static void update_pos()
+{
+       camera_set_position((v3f) {client_player.pos.x, client_player.pos.y + client_player.eye_height, client_player.pos.z});
+       client_send_position(client_player.pos);
+
+       client_player.obj->pos = client_player.pos;
+       object_transform(client_player.obj);
+}
+
+void client_player_init(Map *map)
+{
+       client_player.map = map;
+       client_player.pos = (v3f) {0.0f, 200.0f, 0.0f};
+       client_player.velocity = (v3f) {0.0f, 0.0f, 0.0f};
+       client_player.box = (aabb3f) {{-0.3f, 0.0f, -0.3f}, {0.3f, 1.75f, 0.3f}};
+       client_player.yaw = client_player.pitch = 0.0f;
+       client_player.eye_height = 1.5f;
+}
+
+void client_player_add_to_scene()
+{
+       client_player.obj = object_create();
+       client_player.obj->scale = (v3f) {0.6f, 1.75f, 0.6f};
+       client_player.obj->visible = false;
+
+       object_set_texture(client_player.obj, texture_get(RESSOURCEPATH "textures/player.png"));
+
+       for (int f = 0; f < 6; f++) {
+               for (int v = 0; v < 6; v++) {
+                       Vertex3D vertex = cube_vertices[f][v];
+                       vertex.position.y += 0.5;
+                       object_add_vertex(client_player.obj, &vertex);
+               }
+       }
+
+       update_pos();
+}
+
+static aabb3f get_box()
+{
+       return (aabb3f) {
+               {client_player.box.min.x + client_player.pos.x, client_player.box.min.y + client_player.pos.y, client_player.box.min.z + client_player.pos.z},
+               {client_player.box.max.x + client_player.pos.x, client_player.box.max.y + client_player.pos.y, client_player.box.max.z + client_player.pos.z},
+       };
+}
+
+static aabb3s32 round_box(aabb3f box)
+{
+       return (aabb3s32) {
+               {floor(box.min.x + 0.5f), floor(box.min.y + 0.5f), floor(box.min.z + 0.5f)},
+               {ceil(box.max.x - 0.5f), ceil(box.max.y - 0.5f), ceil(box.max.z - 0.5f)},
+       };
+}
+
+static bool is_solid(s32 x, s32 y, s32 z)
+{
+       Node node = map_get_node(client_player.map, (v3s32) {x, y, z}).type;
+       return node == NODE_UNLOADED || node_definitions[node].solid;
+}
+
+static bool can_jump()
+{
+       aabb3f fbox = get_box();
+       fbox.min.y -= 0.5f;
+
+       aabb3s32 box = round_box(fbox);
+
+       if (fbox.min.y - (f32) box.min.y > 0.01f)
+               return false;
+
+       for (s32 x = box.min.x; x <= box.max.x; x++)
+               for (s32 z = box.min.z; z <= box.max.z; z++)
+                       if (is_solid(x, box.min.y, z))
+                               return true;
+
+       return false;
+}
+
+void client_player_jump()
+{
+       if (can_jump())
+               client_player.velocity.y += 10.0f;
+}
+
+void client_player_tick(f64 dtime)
+{
+       v3f old_pos = client_player.pos;
+       v3f old_velocity = client_player.velocity;
+
+       client_player.velocity.y -= 32.0f * dtime;
+
+#define GETS(vec, comp) *(s32 *) ((char *) &vec + offsetof(v3s32, comp))
+#define GETF(vec, comp) *(f32 *) ((char *) &vec + offsetof(v3f32, comp))
+#define PHYSICS(a, b, c) { \
+               f32 v = (GETF(client_player.velocity, a) + GETF(old_velocity, a)) / 2.0f; \
+               if (v == 0.0f) \
+                       goto a ## _physics_done; \
+               aabb3s32 box = round_box(get_box()); \
+               v3f old_pos = client_player.pos; \
+               GETF(client_player.pos, a) += v * dtime; \
+               s32 dir; \
+               f32 offset; \
+               if (v > 0.0f) { \
+                       dir = +1; \
+                       offset = GETF(client_player.box.max, a); \
+                       GETS(box.min, a) = ceil(GETF(old_pos, a) + offset + 0.5f); \
+                       GETS(box.max, a) = floor(GETF(client_player.pos, a) + offset + 0.5f); \
+               } else { \
+                       dir = -1; \
+                       offset = GETF(client_player.box.min, a); \
+                       GETS(box.min, a) = floor(GETF(old_pos, a) + offset - 0.5f); \
+                       GETS(box.max, a) = ceil(GETF(client_player.pos, a) + offset - 0.5f); \
+               } \
+               GETS(box.max, a) += dir; \
+               for (s32 a = GETS(box.min, a); a != GETS(box.max, a); a += dir) { \
+                       for (s32 b = GETS(box.min, b); b <= GETS(box.max, b); b++) { \
+                               for (s32 c = GETS(box.min, c); c <= GETS(box.max, c); c++) { \
+                                       if (is_solid(x, y, z)) { \
+                                               GETF(client_player.pos, a) = (f32) a - offset - 0.5f * (f32) dir; \
+                                               GETF(client_player.velocity, a) = 0.0f; \
+                                               goto a ## _physics_done; \
+                                       } \
+                               } \
+                       } \
+               } \
+               a ## _physics_done: (void) 0;\
+       }
+
+       PHYSICS(x, y, z)
+       PHYSICS(y, x, z)
+       PHYSICS(z, x, y)
+
+#undef GETS
+#undef GETF
+#undef PHYSICS
+
+       if (old_pos.x != client_player.pos.x || old_pos.y != client_player.pos.y || old_pos.z != client_player.pos.z)
+               update_pos();
+}
diff --git a/src/client/client_player.h b/src/client/client_player.h
new file mode 100644 (file)
index 0000000..890ff2d
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _CLIENT_PLAYER_H_
+#define _CLIENT_PLAYER_H_
+
+#include "client/client.h"
+#include "client/object.h"
+#include "types.h"
+
+extern struct ClientPlayer
+{
+       v3f pos;
+       v3f velocity;
+       aabb3f box;
+       f32 yaw, pitch;
+       f32 eye_height;
+       Object *obj;
+       Map *map;
+} client_player;
+
+void client_player_init(Map *map);
+void client_player_add_to_scene();
+void client_player_jump();
+void client_player_tick(f64 dtime);
+
+#endif
diff --git a/src/client/cube.c b/src/client/cube.c
new file mode 100644 (file)
index 0000000..c3fd961
--- /dev/null
@@ -0,0 +1,53 @@
+#include "client/cube.h"
+
+Vertex3D cube_vertices[6][6] = {
+       {
+               {{-0.5, -0.5, -0.5}, {+0.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, -0.5, -0.5}, {+1.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, +0.5, -0.5}, {+1.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, +0.5, -0.5}, {+1.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, +0.5, -0.5}, {+0.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, -0.5, -0.5}, {+0.0, +0.0}, {+1.0, +0.0, +1.0}},
+       },
+       {
+               {{-0.5, -0.5, +0.5}, {+0.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, +0.5, +0.5}, {+1.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, -0.5, +0.5}, {+1.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, +0.5, +0.5}, {+1.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, -0.5, +0.5}, {+0.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, +0.5, +0.5}, {+0.0, +1.0}, {+1.0, +0.0, +1.0}},
+       },
+       {
+               {{-0.5, +0.5, +0.5}, {+1.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, -0.5, -0.5}, {+0.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, +0.5, -0.5}, {+0.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, -0.5, -0.5}, {+0.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, +0.5, +0.5}, {+1.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, -0.5, +0.5}, {+1.0, +0.0}, {+1.0, +0.0, +1.0}},
+       },
+       {
+               {{+0.5, +0.5, +0.5}, {+1.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, +0.5, -0.5}, {+0.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, -0.5, -0.5}, {+0.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, -0.5, -0.5}, {+0.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, -0.5, +0.5}, {+1.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, +0.5, +0.5}, {+1.0, +1.0}, {+1.0, +0.0, +1.0}},
+       },
+       {
+               {{-0.5, -0.5, -0.5}, {+0.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, -0.5, -0.5}, {+1.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, -0.5, +0.5}, {+1.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, -0.5, +0.5}, {+1.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, -0.5, +0.5}, {+0.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, -0.5, -0.5}, {+0.0, +1.0}, {+1.0, +0.0, +1.0}},
+       },
+       {
+               {{-0.5, +0.5, -0.5}, {+0.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, +0.5, -0.5}, {+1.0, +1.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, +0.5, +0.5}, {+1.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{+0.5, +0.5, +0.5}, {+1.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, +0.5, +0.5}, {+0.0, +0.0}, {+1.0, +0.0, +1.0}},
+               {{-0.5, +0.5, -0.5}, {+0.0, +1.0}, {+1.0, +0.0, +1.0}},
+       },
+};
+
diff --git a/src/client/cube.h b/src/client/cube.h
new file mode 100644 (file)
index 0000000..e467be9
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _CUBE_H_
+#define _CUBE_H_
+
+#include "client/object.h"
+
+extern Vertex3D cube_vertices[6][6];
+
+#endif
diff --git a/src/client/font.c b/src/client/font.c
new file mode 100644 (file)
index 0000000..25ad0e0
--- /dev/null
@@ -0,0 +1,171 @@
+#include <string.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "client/client.h"
+#include "client/font.h"
+#include "client/hud.h"
+
+#define NUM_CHARS 128
+
+
+typedef struct
+{
+       Texture *texture;
+       v2s32 bearing;
+       u32 advance;
+} Character;
+
+static struct
+{
+       FT_Library library;
+       FT_Face face;
+       Character chars[NUM_CHARS];
+       GLfloat height;
+} font;
+
+typedef struct
+{
+       GLfloat x, y;
+} __attribute__((packed)) VertexFontPosition;
+
+typedef struct
+{
+       GLfloat s, t;
+} __attribute__((packed)) VertexFontTextureCoordinates;
+
+typedef struct
+{
+       VertexFontPosition position;
+       VertexFontTextureCoordinates textureCoordinates;
+} __attribute__((packed)) VertexFont;
+
+static VertexAttribute vertex_attributes[2] = {
+       // position
+       {
+               .type = GL_FLOAT,
+               .length = 2,
+               .size = sizeof(VertexFontPosition),
+       },
+       // textureCoordinates
+       {
+               .type = GL_FLOAT,
+               .length = 2,
+               .size = sizeof(VertexFontTextureCoordinates),
+       },
+};
+
+static VertexLayout vertex_layout = {
+       .attributes = vertex_attributes,
+       .count = 2,
+       .size = sizeof(VertexFont),
+};
+
+bool font_init()
+{
+       if (FT_Init_FreeType(&font.library)) {
+               fprintf(stderr, "Failed to initialize Freetype\n");
+               return false;
+       }
+
+       if (FT_New_Face(font.library, RESSOURCEPATH "fonts/Ubuntu.ttf", 0, &font.face)) {
+               fprintf(stderr, "Failed to load Ubuntu.ttf\n");
+               return false;
+       }
+
+       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+       FT_Set_Pixel_Sizes(font.face, 0, 24);
+
+       for (unsigned char c = 0; c < NUM_CHARS; c++) {
+               if (FT_Load_Char(font.face, c, FT_LOAD_RENDER)) {
+                       fprintf(stderr, "Failed to load glyph %c\n", c);
+
+                       font.chars[c] = (Character) {
+                               .texture = NULL,
+                               .bearing = {0, 0},
+                               .advance = 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),
+                               .bearing = {font.face->glyph->bitmap_left, font.face->glyph->bitmap_top},
+                               .advance = font.face->glyph->advance.x,
+                       };
+               }
+       }
+
+       font.height = font.chars['|'].texture->height;
+
+       FT_Done_Face(font.face);
+       FT_Done_FreeType(font.library);
+
+       return true;
+}
+
+void font_deinit()
+{
+       for (unsigned char c = 0; c < NUM_CHARS; c++) {
+               if (font.chars[c].texture)
+                       texture_delete(font.chars[c].texture);
+       }
+}
+
+Font *font_create(char *text)
+{
+       Font *fnt = malloc(sizeof(fnt));
+
+       size_t len = strlen(text);
+
+       fnt->meshes = malloc(sizeof(Mesh *) * len);
+       fnt->meshes_count = len;
+
+       GLfloat offset = 0.0f;
+
+       for (size_t i = 0; i < len; i++) {
+               unsigned char c = text[i];
+
+               if (c >= NUM_CHARS || ! font.chars[c].texture)
+                       c = '?';
+
+               Character *ch = &font.chars[c];
+
+               GLfloat width = ch->texture->width;
+        GLfloat height = ch->texture->height;
+
+               GLfloat x = ch->bearing.x + offset;
+        GLfloat y = font.height - ch->bearing.y;
+
+        VertexFont vertices[6] = {
+            {{x,         y         }, {0.0f, 0.0f}},
+            {{x,         y + height}, {0.0f, 1.0f}},
+            {{x + width, y + height}, {1.0f, 1.0f}},
+            {{x,         y         }, {0.0f, 0.0f}},
+            {{x + width, y + height}, {1.0f, 1.0f}},
+            {{x + width, y         }, {1.0f, 0.0f}},
+        };
+
+               Mesh *mesh = fnt->meshes[i] = mesh_create();
+               mesh->texture = ch->texture->id;
+               mesh->layout = &vertex_layout;
+               mesh->vertices = vertices;
+               mesh->vertices_count = 6;
+               mesh_configure(mesh);
+
+               offset += ch->advance >> 6;
+       }
+
+       return fnt;
+}
+
+void font_delete(Font *fnt)
+{
+       for (size_t i = 0; i < fnt->meshes_count; i++)
+               mesh_delete(fnt->meshes[i]);
+
+       free(fnt);
+}
+
+void font_render(Font *fnt)
+{
+       for (size_t i = 0; i < fnt->meshes_count; i++)
+               mesh_render(fnt->meshes[i]);
+}
diff --git a/src/client/font.h b/src/client/font.h
new file mode 100644 (file)
index 0000000..e8d42e6
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _FONT_H_
+#define _FONT_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include "client/mesh.h"
+
+typedef struct
+{
+       Mesh **meshes;
+       size_t meshes_count;
+} Font;
+
+bool font_init();
+void font_deinit();
+Font *font_create(char *text);
+void font_delete(Font *fnt);
+void font_render(Font *fnt);
+
+#endif
diff --git a/src/client/game.c b/src/client/game.c
new file mode 100644 (file)
index 0000000..c843ebb
--- /dev/null
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <GLFW/glfw3.h>
+#include "client/camera.h"
+#include "client/client.h"
+#include "client/client_map.h"
+#include "client/client_node.h"
+#include "client/client_player.h"
+#include "client/hud.h"
+#include "client/input.h"
+#include "client/font.h"
+#include "client/window.h"
+#include "signal.h"
+
+static void game_loop(Client *client)
+{
+       struct timespec ts, ts_old;
+       clock_gettime(CLOCK_REALTIME, &ts_old);
+
+       while (! glfwWindowShouldClose(window.handle) && client->state != CS_DISCONNECTED && ! interrupted) {
+               clock_gettime(CLOCK_REALTIME, &ts);
+               f64 dtime = (f64) (ts.tv_sec - ts_old.tv_sec) + (f64) (ts.tv_nsec - ts_old.tv_nsec) / 1000000000.0;
+               ts_old = ts;
+
+               glEnable(GL_DEPTH_TEST);
+               glEnable(GL_BLEND);
+               glEnable(GL_MULTISAMPLE);
+               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+               glClearColor(0.52941176470588f, 0.8078431372549f, 0.92156862745098f, 1.0f);
+
+               input_tick();
+               client_player_tick(dtime);
+
+               scene_render();
+               hud_render();
+               // font_render();
+
+               glfwSwapBuffers(window.handle);
+               glfwPollEvents();
+       }
+}
+
+void game(Client *client)
+{
+       int width, height;
+       width = 1250;
+       height = 750;
+
+       if (! window_init(width, height))
+               return;
+
+       if (! font_init())
+               return;
+
+       if (! scene_init())
+               return;
+
+       scene_on_resize(width, height);
+
+       client_node_init();
+       client_map_start_meshgen();
+
+       camera_set_position((v3f) {0.0f, 0.0f, 0.0f});
+       camera_set_angle(0.0f, 0.0f);
+
+       hud_init();
+       hud_on_resize(width, height);
+
+       hud_add((HUDElementDefinition) {
+               .type = HUD_IMAGE,
+               .pos = {0.0f, 0.0f, 0.0f},
+               .offset = {0, 0},
+               .type_def = {
+                       .image = {
+                               .texture = texture_get(RESSOURCEPATH "textures/crosshair.png"),
+                               .scale = {1.0f, 1.0f},
+                               .scale_type = HUD_SCALE_TEXTURE,
+                       },
+               },
+       });
+
+       hud_add((HUDElementDefinition) {
+               .type = HUD_TEXT,
+               .pos = {-1.0f, -1.0f, 0.0f},
+               .offset = {5, 0},
+               .type_def = {
+                       .text = {
+                               .text = "Dragonblocks Alpha",
+                               .color = {1.0f, 1.0f, 1.0f},
+                       },
+               },
+       });
+
+       input_init();
+
+       client_player_add_to_scene();
+
+       game_loop(client);
+
+       font_deinit();
+       hud_deinit();
+       scene_deinit();
+}
diff --git a/src/client/game.h b/src/client/game.h
new file mode 100644 (file)
index 0000000..9d713eb
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _GAME_H_
+#define _GAME_H_
+
+#include "client/client.h"
+
+void game(Client *client);
+
+#endif
diff --git a/src/client/hud.c b/src/client/hud.c
new file mode 100644 (file)
index 0000000..825cc6a
--- /dev/null
@@ -0,0 +1,218 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include "client/client.h"
+#include "client/cube.h"
+#include "client/hud.h"
+#include "client/mesh.h"
+#include "client/shader.h"
+#include "client/vertex.h"
+
+static struct
+{
+       List elements;
+
+       GLuint image_prog;
+       GLint image_loc_model;
+       GLint image_loc_projection;
+       Mesh *image_mesh;
+
+       GLuint font_prog;
+       GLint font_loc_model;
+       GLint font_loc_projection;
+       GLint font_loc_text_color;
+
+       mat4x4 projection;
+       int width, height;
+} hud;
+
+typedef struct
+{
+       GLfloat x, y;
+} __attribute__((packed)) VertexImagePosition;
+
+typedef struct
+{
+       GLfloat s, t;
+} __attribute__((packed)) VertexImageTextureCoordinates;
+
+typedef struct
+{
+       VertexImagePosition position;
+       VertexImageTextureCoordinates textureCoordinates;
+} __attribute__((packed)) VertexImage;
+
+static VertexAttribute image_vertex_attributes[2] = {
+       // position
+       {
+               .type = GL_FLOAT,
+               .length = 2,
+               .size = sizeof(VertexImagePosition),
+       },
+       // textureCoordinates
+       {
+               .type = GL_FLOAT,
+               .length = 2,
+               .size = sizeof(VertexImageTextureCoordinates),
+       },
+};
+
+static VertexLayout image_vertex_layout = {
+       .attributes = image_vertex_attributes,
+       .count = 2,
+       .size = sizeof(VertexImage),
+};
+
+static VertexImage image_vertices[6] = {
+       {{-0.5, -0.5}, {+0.0, +0.0}},
+       {{+0.5, -0.5}, {+1.0, +0.0}},
+       {{+0.5, +0.5}, {+1.0, +1.0}},
+       {{+0.5, +0.5}, {+1.0, +1.0}},
+       {{-0.5, +0.5}, {+0.0, +1.0}},
+       {{-0.5, -0.5}, {+0.0, +0.0}},
+};
+
+bool hud_init()
+{
+       if (! shader_program_create(RESSOURCEPATH "shaders/hud/image", &hud.image_prog)) {
+               fprintf(stderr, "Failed to create HUD image shader program\n");
+               return false;
+       }
+
+       hud.image_loc_model = glGetUniformLocation(hud.image_prog, "model");
+       hud.image_loc_projection = glGetUniformLocation(hud.image_prog, "projection");
+
+       if (! shader_program_create(RESSOURCEPATH "shaders/hud/font", &hud.font_prog)) {
+               fprintf(stderr, "Failed to create HUD font shader program\n");
+               return false;
+       }
+
+       hud.font_loc_model = glGetUniformLocation(hud.font_prog, "model");
+       hud.font_loc_projection = glGetUniformLocation(hud.font_prog, "projection");
+       hud.font_loc_text_color = glGetUniformLocation(hud.font_prog, "textColor");
+
+
+       hud.elements = list_create(NULL);
+
+       hud.image_mesh = mesh_create();
+       hud.image_mesh->vertices = image_vertices;
+       hud.image_mesh->vertices_count = 6;
+       hud.image_mesh->layout = &image_vertex_layout;
+
+       return true;
+}
+
+static void free_element(void *key, __attribute__((unused)) void *value, __attribute__((unused)) void *arg)
+{
+       HUDElement *element = key;
+
+       if (element->def.type == HUD_TEXT)
+               font_delete(element->type_data.text);
+
+       free(element);
+}
+
+void hud_deinit()
+{
+       glDeleteProgram(hud.image_prog);
+       glDeleteProgram(hud.font_prog);
+       mesh_delete(hud.image_mesh);
+       list_clear_func(&hud.elements, &free_element, NULL);
+}
+
+static void element_transform(HUDElement *element)
+{
+       v3f pos = {
+               (f32) element->def.offset.x + (1.0f + element->def.pos.x) / 2.0f * (f32) hud.width,
+               (f32) element->def.offset.y + (1.0f + element->def.pos.y) / 2.0f * (f32) hud.height,
+               element->def.pos.z,
+       };
+
+       mat4x4_translate(element->transform, pos.x, pos.y, pos.z);
+
+       if (element->def.type == HUD_IMAGE) {
+               v2f scale = element->def.type_def.image.scale;
+
+               switch (element->def.type_def.image.scale_type) {
+                       case HUD_SCALE_TEXTURE:
+                               scale.x *= element->def.type_def.image.texture->width;
+                               scale.y *= element->def.type_def.image.texture->height;
+
+                               break;
+
+                       case HUD_SCALE_SCREEN:
+                               scale.x *= hud.width * 2.0f;
+                               scale.y *= hud.height * 2.0f;
+
+                               break;
+
+                       default:
+                               break;
+               }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+               mat4x4_scale_aniso(element->transform, element->transform, scale.x, scale.y, 1.0f);
+       }
+#pragma GCC diagnostic pop
+}
+
+void hud_on_resize(int width, int height)
+{
+       hud.width = width;
+       hud.height = height;
+
+       mat4x4_ortho(hud.projection, 0, width, height, 0, -1.0f, 1.0f);
+       glProgramUniformMatrix4fv(hud.image_prog, hud.image_loc_projection, 1, GL_FALSE, hud.projection[0]);
+       glProgramUniformMatrix4fv(hud.font_prog, hud.font_loc_projection, 1, GL_FALSE, hud.projection[0]);
+
+       for (ListPair *pair = hud.elements.first; pair != NULL; pair = pair->next)
+               element_transform(pair->key);
+}
+
+void hud_render()
+{
+       glActiveTexture(GL_TEXTURE0);
+
+       for (ListPair *pair = hud.elements.first; pair != NULL; pair = pair->next) {
+               HUDElement *element = pair->key;
+
+               if (element->visible) {
+                       switch (element->def.type) {
+                               case HUD_IMAGE:
+                                       glUseProgram(hud.image_prog);
+                                       glUniformMatrix4fv(hud.image_loc_model, 1, GL_FALSE, element->transform[0]);
+                                       hud.image_mesh->texture = element->def.type_def.image.texture->id;
+                                       mesh_render(hud.image_mesh);
+
+                                       break;
+
+                               case HUD_TEXT:
+                                       glUseProgram(hud.font_prog);
+                                       glUniformMatrix4fv(hud.font_loc_model, 1, GL_FALSE, element->transform[0]);
+                                       glUniform3f(hud.font_loc_text_color, element->def.type_def.text.color.x, element->def.type_def.text.color.y, element->def.type_def.text.color.z);
+                                       font_render(element->type_data.text);
+
+                                       break;
+                       };
+               }
+       }
+}
+
+HUDElement *hud_add(HUDElementDefinition def)
+{
+       HUDElement *element = malloc(sizeof(HUDElement));
+       element->def = def;
+       element->visible = true;
+
+       element_transform(element);
+
+       if (element->def.type == HUD_TEXT)
+               element->type_data.text = font_create(element->def.type_def.text.text);
+
+       list_set(&hud.elements, element, NULL);
+
+       return element;
+}
diff --git a/src/client/hud.h b/src/client/hud.h
new file mode 100644 (file)
index 0000000..d59c638
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef _HUD_H_
+#define _HUD_H_
+
+#include <stdbool.h>
+#include <linmath.h/linmath.h>
+#include "client/font.h"
+#include "client/texture.h"
+#include "types.h"
+
+typedef enum
+{
+       HUD_SCALE_TEXTURE,
+       HUD_SCALE_SCREEN,
+       HUD_SCALE_NONE,
+} HUDImageScaleType;
+
+typedef enum
+{
+       HUD_IMAGE,
+       HUD_TEXT,
+} HUDElementType;
+
+typedef struct
+{
+       HUDElementType type;
+       v3f pos;
+       v2s32 offset;
+       union
+       {
+               struct {
+                       Texture *texture;
+                       v2f scale;
+                       HUDImageScaleType scale_type;
+               } image;
+               struct {
+                       char *text;
+                       v3f color;
+               } text;
+       } type_def;
+} HUDElementDefinition;
+
+typedef struct
+{
+       HUDElementDefinition def;
+       bool visible;
+       mat4x4 transform;
+       union
+       {
+               Font *text;
+       } type_data;
+} HUDElement;
+
+bool hud_init();
+void hud_deinit();
+void hud_on_resize(int width, int height);
+void hud_render();
+HUDElement *hud_add(HUDElementDefinition def);
+
+#endif
diff --git a/src/client/input.c b/src/client/input.c
new file mode 100644 (file)
index 0000000..0820886
--- /dev/null
@@ -0,0 +1,142 @@
+#include <math.h>
+#include "client/camera.h"
+#include "client/client.h"
+#include "client/client_player.h"
+#include "client/hud.h"
+#include "client/input.h"
+#include "client/window.h"
+
+typedef struct
+{
+       int key;
+       bool was_pressed;
+       bool fired;
+} KeyListener;
+
+static struct
+{
+       HUDElement *pause_menu_hud;
+       bool paused;
+       KeyListener pause_listener;
+       KeyListener fullscreen_listener;
+} input;
+
+void input_on_cursor_pos(double current_x, double current_y)
+{
+       if (input.paused)
+               return;
+
+       static double last_x, last_y = 0.0;
+
+       double delta_x = current_x - last_x;
+       double delta_y = current_y - last_y;
+       last_x = current_x;
+       last_y = current_y;
+
+       client_player.yaw += (f32) delta_x * M_PI / 180.0f / 8.0f;
+       client_player.pitch -= (f32) delta_y * M_PI / 180.0f / 8.0f;
+
+       client_player.pitch = fmax(fmin(client_player.pitch, M_PI / 2.0f - 0.01f), -M_PI / 2.0f + 0.01f);
+
+       camera_set_angle(client_player.yaw, client_player.pitch);
+}
+
+static bool move(int forward, int backward, vec3 dir)
+{
+       f32 sign;
+       f32 speed = 4.317f;
+
+       if (glfwGetKey(window.handle, forward) == GLFW_PRESS)
+               sign = +1.0f;
+       else if (glfwGetKey(window.handle, backward) == GLFW_PRESS)
+               sign = -1.0f;
+       else
+               return false;
+
+       client_player.velocity.x += dir[0] * speed * sign;
+       client_player.velocity.z += dir[2] * speed * sign;
+
+       return true;
+}
+
+static void enter_game()
+{
+       glfwSetInputMode(window.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+       input.pause_menu_hud->visible = false;
+}
+
+static void do_key_listener(KeyListener *listener)
+{
+       bool is_pressed = glfwGetKey(window.handle, listener->key) == GLFW_PRESS;
+       listener->fired = listener->was_pressed && ! is_pressed;
+       listener->was_pressed = is_pressed;
+}
+
+static KeyListener create_key_listener(int key)
+{
+       return (KeyListener) {
+               .key = key,
+               .was_pressed = false,
+               .fired = false,
+       };
+}
+
+void input_tick()
+{
+       do_key_listener(&input.pause_listener);
+       do_key_listener(&input.fullscreen_listener);
+
+       if (input.pause_listener.fired) {
+               input.paused = ! input.paused;
+
+               if (input.paused) {
+                       glfwSetInputMode(window.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+                       input.pause_menu_hud->visible = true;
+               } else {
+                       enter_game();
+               }
+       }
+
+       if (input.fullscreen_listener.fired) {
+               if (window.fullscreen)
+                       window_exit_fullscreen();
+               else
+                       window_enter_fullscreen();
+       }
+
+       client_player.velocity.x = 0.0f;
+       client_player.velocity.z = 0.0f;
+
+       if (! input.paused) {
+               move(GLFW_KEY_W, GLFW_KEY_S, camera_movement_dirs.front);
+               move(GLFW_KEY_D, GLFW_KEY_A, camera_movement_dirs.right);
+
+               if (glfwGetKey(window.handle, GLFW_KEY_SPACE) == GLFW_PRESS)
+                       client_player_jump();
+       }
+}
+
+void input_init()
+{
+       input.paused = false;
+
+       input.pause_listener = create_key_listener(GLFW_KEY_ESCAPE);
+       input.fullscreen_listener = create_key_listener(GLFW_KEY_F11);
+
+       input.pause_menu_hud = hud_add((HUDElementDefinition) {
+               .type = HUD_IMAGE,
+               .pos = {-1.0f, -1.0f, 0.5f},
+               .offset = {0, 0},
+               .type_def = {
+                       .image = {
+                               .texture = texture_get(RESSOURCEPATH "textures/pause_layer.png"),
+                               .scale = {1.0f, 1.0f},
+                               .scale_type = HUD_SCALE_SCREEN
+                       },
+               },
+       });
+
+       glfwSetInputMode(window.handle, GLFW_STICKY_KEYS, GL_TRUE);
+
+       enter_game();
+}
diff --git a/src/client/input.h b/src/client/input.h
new file mode 100644 (file)
index 0000000..97f7e9f
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _INPUT_H_
+#define _INPUT_H_
+
+void input_tick();
+void input_init();
+void input_on_cursor_pos(double current_x, double current_y);
+
+#endif
diff --git a/src/client/mesh.c b/src/client/mesh.c
new file mode 100644 (file)
index 0000000..bc1141b
--- /dev/null
@@ -0,0 +1,58 @@
+#include <stdlib.h>
+#include <stddef.h>
+#include "client/mesh.h"
+
+Mesh *mesh_create()
+{
+       Mesh *mesh = malloc(sizeof(Mesh));
+       mesh->VAO = mesh->VBO = 0;
+       mesh->free_vertices = false;
+
+       return mesh;
+}
+
+void mesh_delete(Mesh *mesh)
+{
+       if (mesh->vertices && mesh->free_vertices)
+               free(mesh->vertices);
+
+       if (mesh->VAO)
+               glDeleteVertexArrays(1, &mesh->VAO);
+
+       if (mesh->VBO)
+               glDeleteBuffers(1, &mesh->VAO);
+
+       free(mesh);
+}
+
+void mesh_configure(Mesh *mesh)
+{
+       glGenVertexArrays(1, &mesh->VAO);
+       glGenBuffers(1, &mesh->VBO);
+
+       glBindVertexArray(mesh->VAO);
+       glBindBuffer(GL_ARRAY_BUFFER, mesh->VBO);
+
+       glBufferData(GL_ARRAY_BUFFER, mesh->vertices_count * mesh->layout->size, mesh->vertices, GL_STATIC_DRAW);
+
+       vertex_layout_configure(mesh->layout);
+
+       glBindBuffer(GL_ARRAY_BUFFER, 0);
+       glBindVertexArray(0);
+
+       if (mesh->free_vertices)
+               free(mesh->vertices);
+
+       mesh->vertices = NULL;
+}
+
+void mesh_render(Mesh *mesh)
+{
+       if (mesh->vertices)
+               mesh_configure(mesh);
+
+       glBindTexture(GL_TEXTURE_2D, mesh->texture);
+       glBindVertexArray(mesh->VAO);
+       glDrawArrays(GL_TRIANGLES, 0, mesh->vertices_count);
+
+}
diff --git a/src/client/mesh.h b/src/client/mesh.h
new file mode 100644 (file)
index 0000000..c3dbe96
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _MESH_H_
+#define _MESH_H_
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <stdbool.h>
+#include "client/vertex.h"
+
+typedef struct
+{
+       GLuint VAO, VBO;
+       GLuint texture;
+       GLvoid *vertices;
+       GLuint vertices_count;
+       bool free_vertices;
+       VertexLayout *layout;
+} Mesh;
+
+Mesh *mesh_create();
+void mesh_delete(Mesh *mesh);
+void mesh_configure(Mesh *mesh);
+void mesh_render(Mesh *mesh);
+
+#endif
diff --git a/src/client/object.c b/src/client/object.c
new file mode 100644 (file)
index 0000000..bd26e1c
--- /dev/null
@@ -0,0 +1,160 @@
+#include <stdlib.h>
+#include "client/object.h"
+#include "client/scene.h"
+
+static VertexAttribute vertex_attributes[3] = {
+       // position
+       {
+               .type = GL_FLOAT,
+               .length = 3,
+               .size = sizeof(Vertex3DPosition),
+       },
+       // textureCoordinates
+       {
+               .type = GL_FLOAT,
+               .length = 2,
+               .size = sizeof(Vertex3DTextureCoordinates),
+
+       },
+       // color
+       {
+               .type = GL_FLOAT,
+               .length = 3,
+               .size = sizeof(Vertex3DColor),
+       },
+};
+
+static VertexLayout vertex_layout = {
+       .attributes = vertex_attributes,
+       .count = 3,
+       .size = sizeof(Vertex3D),
+};
+
+Object *object_create()
+{
+       Object *obj = malloc(sizeof(Object));
+       obj->pos = (v3f) {0.0f, 0.0f, 0.0f};
+       obj->rot = (v3f) {0.0f, 0.0f, 0.0f};
+       obj->scale = (v3f) {1.0f, 1.0f, 1.0f};
+       obj->angle = 0.0f;
+       obj->remove = false;
+       obj->meshes = NULL;
+       obj->meshes_count = 0;
+       obj->visible = true;
+       obj->wireframe = false;
+       obj->current_face = NULL;
+       obj->faces = array_create(sizeof(ObjectFace));
+
+       return obj;
+}
+
+void object_delete(Object *obj)
+{
+       for (size_t i = 0; i < obj->meshes_count; i++)
+               mesh_delete(obj->meshes[i]);
+
+       free(obj);
+}
+
+void object_set_texture(Object *obj, Texture *texture)
+{
+       if (obj->current_face && obj->current_face->texture == texture->id)
+               return;
+
+       ObjectFace face = {
+               .texture = texture->id,
+               .vertices = array_create(sizeof(Vertex3D)),
+       };
+
+       array_append(&obj->faces, &face);
+       obj->current_face = &((ObjectFace *) obj->faces.ptr)[obj->faces.siz - 1];
+}
+
+void object_add_vertex(Object *obj, Vertex3D *vertex)
+{
+       array_append(&obj->current_face->vertices, vertex);
+}
+
+static int qsort_compare_faces(const void *f1, const void *f2)
+{
+       return ((ObjectFace *) f1)->texture - ((ObjectFace *) f2)->texture;
+}
+
+static void add_mesh(Array *meshes, Array *vertices, GLuint texture)
+{
+       if (vertices->siz > 0) {
+               Mesh *mesh = mesh_create();
+               mesh->vertices = vertices->ptr;
+               mesh->vertices_count = vertices->siz;
+               mesh->free_vertices = true;
+               mesh->texture = texture;
+               mesh->layout = &vertex_layout;
+
+               array_append(meshes, &mesh);
+       }
+
+       *vertices = array_create(sizeof(Vertex3D));
+}
+
+bool object_add_to_scene(Object *obj)
+{
+       if (obj->faces.siz == 0)
+               return false;
+
+       object_transform(obj);
+
+       qsort(obj->faces.ptr, obj->faces.siz, sizeof(ObjectFace), &qsort_compare_faces);
+
+       Array meshes = array_create(sizeof(Mesh *));
+       Array vertices = array_create(sizeof(Vertex3D));
+       GLuint texture = 0;
+
+       for (size_t f = 0; f < obj->faces.siz; f++) {
+               ObjectFace *face = &((ObjectFace *) obj->faces.ptr)[f];
+
+               if (face->texture != texture) {
+                       add_mesh(&meshes, &vertices, texture);
+                       texture = face->texture;
+               }
+
+               for (size_t v = 0; v < face->vertices.siz; v++)
+                       array_append(&vertices, &((Vertex3D *) face->vertices.ptr)[v]);
+               free(face->vertices.ptr);
+       }
+       add_mesh(&meshes, &vertices, texture);
+       free(obj->faces.ptr);
+
+       array_copy(&meshes, (void *) &obj->meshes, &obj->meshes_count);
+       free(meshes.ptr);
+
+       scene_add_object(obj);
+
+       return true;
+}
+
+void object_transform(Object *obj)
+{
+       mat4x4_translate(obj->transform, obj->pos.x, obj->pos.y, obj->pos.z);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+       mat4x4_rotate(obj->transform, obj->transform, obj->rot.x, obj->rot.y, obj->rot.z, obj->angle);
+       mat4x4_scale_aniso(obj->transform, obj->transform, obj->scale.x, obj->scale.y, obj->scale.z);
+#pragma GCC diagnostic pop
+}
+
+void object_render(Object *obj, GLint loc_model)
+{
+       if (! obj->visible)
+               return;
+
+       glUniformMatrix4fv(loc_model, 1, GL_FALSE, obj->transform[0]);
+
+       if (obj->wireframe)
+               glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+       for (size_t i = 0; i < obj->meshes_count; i++)
+               mesh_render(obj->meshes[i]);
+
+       if (obj->wireframe)
+               glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
diff --git a/src/client/object.h b/src/client/object.h
new file mode 100644 (file)
index 0000000..a09d6a8
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef _OBJECT_H_
+#define _OBJECT_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <linmath.h/linmath.h>
+#include "client/mesh.h"
+#include "client/texture.h"
+#include "client/vertex.h"
+#include "array.h"
+#include "types.h"
+
+typedef struct {
+       GLfloat x, y, z;
+} __attribute__((packed)) Vertex3DPosition;
+
+typedef struct {
+       GLfloat s, t;
+} __attribute__((packed)) Vertex3DTextureCoordinates;
+
+typedef struct {
+       GLfloat h, s, v;
+} __attribute__((packed)) Vertex3DColor;
+
+typedef struct
+{
+       Vertex3DPosition position;
+       Vertex3DTextureCoordinates textureCoordinates;
+       Vertex3DColor color;
+} __attribute__((packed)) Vertex3D;
+
+typedef struct
+{
+       GLuint texture;
+       Array vertices;
+} ObjectFace;
+
+typedef struct
+{
+       v3f pos, rot, scale;
+       f32 angle;
+       bool remove;
+       Mesh **meshes;
+       size_t meshes_count;
+       mat4x4 transform;
+       bool visible;
+       bool wireframe;
+       ObjectFace *current_face;
+       Array faces;
+} Object;
+
+Object *object_create();
+void object_delete(Object *obj);
+void object_set_texture(Object *obj, Texture *texture);
+void object_add_vertex(Object *obj, Vertex3D *vertex);
+bool object_add_to_scene(Object *obj);
+void object_transform(Object *obj);
+void object_render(Object *obj, GLint loc_model);
+
+#endif
diff --git a/src/client/scene.c b/src/client/scene.c
new file mode 100644 (file)
index 0000000..e19533e
--- /dev/null
@@ -0,0 +1,90 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <linmath.h/linmath.h>
+#include "client/camera.h"
+#include "client/client.h"
+#include "client/scene.h"
+#include "client/shader.h"
+#include "list.h"
+
+static struct
+{
+       List objects;
+       pthread_mutex_t mtx;
+       GLuint prog;
+       GLint loc_model;
+       GLint loc_view;
+       GLint loc_projection;
+       mat4x4 projection;
+       f32 fov;
+       f32 render_distance;
+} scene;
+
+bool scene_init()
+{
+       scene.objects = list_create(NULL),
+       pthread_mutex_init(&scene.mtx, NULL);
+
+       if (! shader_program_create(RESSOURCEPATH "shaders/3d", &scene.prog)) {
+               fprintf(stderr, "Failed to create 3D shader program\n");
+               return false;
+       }
+
+       scene.loc_model = glGetUniformLocation(scene.prog, "model");
+       scene.loc_view = glGetUniformLocation(scene.prog, "view");
+       scene.loc_projection = glGetUniformLocation(scene.prog, "projection");
+
+       scene.fov = 86.1f;
+       scene.render_distance = 1000.0f;
+
+       return true;
+}
+
+static void list_delete_object(void *key, __attribute__((unused)) void *value, __attribute__((unused)) void *unused)
+{
+       object_delete(key);
+}
+
+void scene_deinit()
+{
+       list_clear_func(&scene.objects, &list_delete_object, NULL);
+       pthread_mutex_destroy(&scene.mtx);
+       glDeleteProgram(scene.prog);
+}
+
+void scene_add_object(Object *obj)
+{
+       pthread_mutex_lock(&scene.mtx);
+       list_put(&scene.objects, obj, NULL);
+       pthread_mutex_unlock(&scene.mtx);
+}
+
+void scene_render()
+{
+       glUseProgram(scene.prog);
+       camera_enable(scene.loc_view);
+       glUniformMatrix4fv(scene.loc_projection, 1, GL_FALSE, scene.projection[0]);
+
+       glActiveTexture(GL_TEXTURE0);
+
+       for (ListPair **pairptr = &scene.objects.first; *pairptr != NULL; ) {
+               ListPair *pair = *pairptr;
+               Object *obj = pair->key;
+               if (obj->remove) {
+                       pthread_mutex_lock(&scene.mtx);
+                       *pairptr = pair->next;
+                       pthread_mutex_unlock(&scene.mtx);
+                       free(pair);
+                       object_delete(obj);
+               } else {
+                       object_render(obj, scene.loc_model);
+                       pairptr = &pair->next;
+               }
+       }
+}
+
+void scene_on_resize(int width, int height)
+{
+       mat4x4_perspective(scene.projection, scene.fov / 180.0f * M_PI, (float) width / (float) height, 0.01f, scene.render_distance);
+}
diff --git a/src/client/scene.h b/src/client/scene.h
new file mode 100644 (file)
index 0000000..24c40e1
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _SCENE_H_
+#define _SCENE_H_
+
+#include "client/object.h"
+
+bool scene_init();
+void scene_deinit();
+void scene_add_object(Object *obj);
+void scene_render();
+void scene_on_resize(int width, int height);
+
+#endif
diff --git a/src/client/shader.c b/src/client/shader.c
new file mode 100644 (file)
index 0000000..acdd261
--- /dev/null
@@ -0,0 +1,105 @@
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "client/shader.h"
+
+static GLuint compile_and_attach_shader(GLenum type, const char *path, const char *name, GLuint program)
+{
+       char full_path[strlen(path) + 1 + strlen(name) + 1 + 4 + 1];
+       sprintf(full_path, "%s/%s.glsl", path, name);
+
+       FILE *file = fopen(full_path, "r");
+       if (! file) {
+               perror("fopen");
+               return 0;
+       }
+
+       if (fseek(file, 0, SEEK_END) == -1) {
+               perror("fseek");
+               fclose(file);
+               return 0;
+       }
+
+       long size = ftell(file);
+
+       if (size == 1) {
+               perror("ftell");
+               fclose(file);
+               return 0;
+       }
+
+       if (fseek(file, 0, SEEK_SET) == -1) {
+               perror("fseek");
+               fclose(file);
+               return 0;
+       }
+
+       char code[size];
+
+       if (fread(code, 1, size, file) != (size_t) size) {
+               perror("fread");
+               fclose(file);
+               return 0;
+       }
+
+       fclose(file);
+
+       GLuint id = glCreateShader(type);
+
+       char const *codeptr = code;
+       const int isize = (int) size;
+       glShaderSource(id, 1, &codeptr, &isize);
+
+       glCompileShader(id);
+
+       GLint success;
+       glGetShaderiv(id, GL_COMPILE_STATUS, &success);
+       if (! success) {
+               char errbuf[BUFSIZ];
+               glGetShaderInfoLog(id, BUFSIZ, NULL, errbuf);
+               fprintf(stderr, "Failed to compile %s shader: %s\n", name, errbuf);
+               glDeleteShader(id);
+               return 0;
+       }
+
+       glAttachShader(program, id);
+
+       return id;
+}
+
+
+bool shader_program_create(const char *path, GLuint *idptr)
+{
+       GLuint id = glCreateProgram();
+
+       GLuint vert, frag;
+
+       if (! (vert = compile_and_attach_shader(GL_VERTEX_SHADER, path, "vertex", id))) {
+               glDeleteProgram(id);
+               return false;
+       }
+
+       if (! (frag = compile_and_attach_shader(GL_FRAGMENT_SHADER, path, "fragment", id))) {
+               glDeleteShader(vert);
+               glDeleteProgram(id);
+               return false;
+       }
+
+       glLinkProgram(id);
+       glDeleteShader(vert);
+       glDeleteShader(frag);
+
+       GLint success;
+       glGetProgramiv(id, GL_LINK_STATUS, &success);
+       if (! success) {
+               char errbuf[BUFSIZ];
+               glGetProgramInfoLog(id, BUFSIZ, NULL, errbuf);
+               fprintf(stderr, "Failed to link shader program: %s\n", errbuf);
+               glDeleteProgram(id);
+               return false;
+       }
+
+       *idptr = id;
+       return true;
+}
diff --git a/src/client/shader.h b/src/client/shader.h
new file mode 100644 (file)
index 0000000..515c786
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _SHADER_H_
+#define _SHADER_H_
+
+#include <stdbool.h>
+#include <GL/glew.h>
+#include <GL/gl.h>
+
+bool shader_program_create(const char *path, GLuint *idptr);
+
+#endif
diff --git a/src/client/texture.c b/src/client/texture.c
new file mode 100644 (file)
index 0000000..0feb4f0
--- /dev/null
@@ -0,0 +1,75 @@
+#define STB_IMAGE_IMPLEMENTATION
+#include <stb/stb_image.h>
+#include <stdbool.h>
+#include "client/texture.h"
+#include "list.h"
+
+static List textures;
+
+__attribute((constructor(101))) static void textures_init()
+{
+       stbi_set_flip_vertically_on_load(true);
+
+       textures = list_create(&list_compare_string);
+}
+
+static void list_delete_texture(__attribute__((unused)) void *key, void *value, __attribute__((unused)) void *unused)
+{
+       texture_delete(value);
+}
+
+__attribute((destructor)) static void textures_deinit()
+{
+       list_clear_func(&textures, &list_delete_texture, NULL);
+}
+
+Texture *texture_create(unsigned char *data, int width, int height, GLenum format)
+{
+       Texture *texture = malloc(sizeof(Texture));
+       texture->width = width;
+       texture->height = height;
+
+       glGenTextures(1, &texture->id);
+
+       glBindTexture(GL_TEXTURE_2D, texture->id);
+
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+       glTexImage2D(GL_TEXTURE_2D, 0, format, texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE, data);
+       glGenerateMipmap(GL_TEXTURE_2D);
+
+       glBindTexture(GL_TEXTURE_2D, 0);
+
+       return texture;
+}
+
+void texture_delete(Texture *texture)
+{
+       glDeleteTextures(1, &texture->id);
+       free(texture);
+}
+
+static void *create_image_texture(void *key)
+{
+       int width, height, channels;
+
+       unsigned char *data = stbi_load(key, &width, &height, &channels, 0);
+       if (! data) {
+               printf("Failed to load texture %s\n", (char *) key);
+               return 0;
+       }
+
+       Texture *texture = texture_create(data, width, height, GL_RGBA);
+
+       stbi_image_free(data);
+
+       return texture;
+}
+
+Texture *texture_get(char *path)
+{
+       return list_get_cached(&textures, path, &create_image_texture);
+}
diff --git a/src/client/texture.h b/src/client/texture.h
new file mode 100644 (file)
index 0000000..a4542b7
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _TEXTURE_H_
+#define _TEXTURE_H_
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+
+typedef struct
+{
+       GLuint id;
+       int width, height;
+} Texture;
+
+Texture *texture_create(unsigned char *data, int width, int height, GLenum format);
+void texture_delete(Texture *texture);
+Texture *texture_get(char *path);
+
+#endif
diff --git a/src/client/vertex.c b/src/client/vertex.c
new file mode 100644 (file)
index 0000000..d203668
--- /dev/null
@@ -0,0 +1,15 @@
+#include "client/vertex.h"
+
+void vertex_layout_configure(VertexLayout *layout)
+{
+       size_t offset = 0;
+
+       for (GLuint i = 0; i < layout->count; i++) {
+               VertexAttribute *attrib = &layout->attributes[i];
+
+               glVertexAttribPointer(i, attrib->length, attrib->type, GL_FALSE, layout->size, (GLvoid *) offset);
+               glEnableVertexAttribArray(i);
+
+               offset += attrib->size;
+       }
+}
diff --git a/src/client/vertex.h b/src/client/vertex.h
new file mode 100644 (file)
index 0000000..361d5f6
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _VERTEX_H_
+#define _VERTEX_H_
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+
+typedef struct
+{
+       GLenum type;
+       GLsizei length;
+       GLsizei size;
+} VertexAttribute;
+
+typedef struct
+{
+       VertexAttribute *attributes;
+       GLuint count;
+       GLsizei size;
+} VertexLayout;
+
+void vertex_layout_configure(VertexLayout *layout);
+
+#endif
diff --git a/src/client/window.c b/src/client/window.c
new file mode 100644 (file)
index 0000000..f0110d2
--- /dev/null
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include "client/hud.h"
+#include "client/input.h"
+#include "client/scene.h"
+#include "client/window.h"
+
+struct Window window;
+
+static void framebuffer_size_callback(__attribute__((unused)) GLFWwindow *handle, int width, int height)
+{
+       glViewport(0, 0, width, height);
+
+       if (! window.fullscreen) {
+               window.small_bounds.width = width;
+               window.small_bounds.height = height;
+       }
+
+       scene_on_resize(width, height);
+       hud_on_resize(width, height);
+}
+
+static void cursor_pos_callback(__attribute__((unused)) GLFWwindow *handle, double current_x, double current_y)
+{
+       input_on_cursor_pos(current_x, current_y);
+}
+
+static void window_pos_callback(__attribute__((unused)) GLFWwindow *handle, int x, int y)
+{
+       if (! window.fullscreen) {
+               window.small_bounds.x = x;
+               window.small_bounds.y = y;
+       }
+}
+
+void window_enter_fullscreen()
+{
+       window.fullscreen = true;
+       GLFWmonitor *monitor = glfwGetPrimaryMonitor();
+       const GLFWvidmode *vidmode = glfwGetVideoMode(monitor);
+       glfwSetWindowMonitor(window.handle, monitor, 0, 0, vidmode->width, vidmode->height, 0);
+}
+
+void window_exit_fullscreen()
+{
+       window.fullscreen = false;
+       glfwSetWindowMonitor(window.handle, NULL, window.small_bounds.x, window.small_bounds.y, window.small_bounds.width, window.small_bounds.height, 0);
+}
+
+bool window_init(int width, int height)
+{
+       if(! glfwInit()) {
+               fprintf(stderr, "Failed to initialize GLFW\n");
+               return false;
+       }
+
+       glfwWindowHint(GLFW_SAMPLES, 8);
+       glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+       glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+       glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+
+       window.handle = glfwCreateWindow(width, height, "Dragonblocks", NULL, NULL);
+
+       window.small_bounds.width = width;
+       window.small_bounds.height = height;
+
+       if (! window.handle) {
+               fprintf(stderr, "Failed to create window\n");
+               glfwTerminate();
+               return false;
+       }
+
+       glfwMakeContextCurrent(window.handle);
+
+       if (glewInit() != GLEW_OK) {
+               fprintf(stderr, "Failed to initialize GLEW\n");
+               return false;
+       }
+
+       glfwSetFramebufferSizeCallback(window.handle, &framebuffer_size_callback);
+       glfwSetCursorPosCallback(window.handle, &cursor_pos_callback);
+       glfwSetWindowPosCallback(window.handle, &window_pos_callback);
+
+       return true;
+}
diff --git a/src/client/window.h b/src/client/window.h
new file mode 100644 (file)
index 0000000..83b784f
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _WINDOW_H_
+#define _WINDOW_H_
+
+#include <GLFW/glfw3.h>
+
+extern struct Window
+{
+       GLFWwindow *handle;
+       bool fullscreen;
+       struct
+       {
+               int x, y;
+               int width, height;
+       } small_bounds;
+} window;
+
+bool window_init(int width, int height);
+void window_enter_fullscreen();
+void window_exit_fullscreen();
+
+#endif
diff --git a/src/clientcommands.c b/src/clientcommands.c
deleted file mode 100644 (file)
index e533da4..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include "client.h"
-#include "clientmap.h"
-#include "types.h"
-
-static bool disconnect_handler(__attribute__((unused)) Client *client, bool good)
-{
-       if (good)
-               client_disconnect(false, NULL);
-       return true;
-}
-
-static bool auth_handler(Client *client, bool good)
-{
-       u8 success;
-       if (! read_u8(client->fd, &success))
-               return false;
-
-       if (! good)
-               return true;
-
-       if (success) {
-               printf("Authenticated successfully\n");
-               client->state = CS_ACTIVE;
-       } else {
-               printf("Authentication failed, please try again\n");
-               client->state = CS_CREATED;
-       }
-
-       return true;
-}
-
-static bool block_handler(Client *client, bool good)
-{
-       v3s32 pos;
-
-       if (! read_v3s32(client->fd, &pos))
-               return false;
-
-       MapBlockHeader header;
-
-       if (! read_u32(client->fd, &header))
-               return false;
-
-       char data[header];
-       if (! read_full(client->fd, data, header))
-               return false;
-
-       MapBlock *block;
-
-       if (good)
-               block = map_get_block(client->map, pos, true);
-       else
-               block = map_allocate_block(pos);
-
-       if (block->state != MBS_CREATED)
-               map_clear_meta(block);
-
-       bool ret = map_deserialize_block(block, data, header);
-
-       if (good)
-               clientmap_block_changed(block);
-       else
-               map_free_block(block);
-
-       return ret;
-}
-
-CommandHandler command_handlers[CLIENT_COMMAND_COUNT] = {
-       {0},
-       {&disconnect_handler, "DISCONNECT", CS_CREATED | CS_AUTH | CS_ACTIVE},
-       {&auth_handler, "AUTH", CS_AUTH},
-       {&block_handler, "BLOCK", CS_ACTIVE},
-};
diff --git a/src/clientcommands.h b/src/clientcommands.h
deleted file mode 100644 (file)
index 3249ae2..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _CLIENT_COMMAND_H_
-#define _CLIENT_COMMAND_H_
-
-typedef enum
-{
-       CLIENT_COMMAND_NULL,
-       CC_DISCONNECT,
-       CC_AUTH,
-       CC_BLOCK,
-       CLIENT_COMMAND_COUNT
-} ClientCommand;
-
-#ifdef _SERVER_H_
-typedef ClientCommand RemoteCommand;
-#endif
-
-#ifdef _CLIENT_H_
-typedef ClientCommand HostCommand;
-#define HOST_COMMAND_COUNT CLIENT_COMMAND_COUNT
-#endif
-
-#endif
diff --git a/src/clientmap.c b/src/clientmap.c
deleted file mode 100644 (file)
index dd72ec3..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-#include <stdlib.h>
-#include "clientmap.h"
-#include "blockmesh.h"
-#include "queue.h"
-
-static struct
-{
-       Queue *queue;
-       pthread_t thread;
-       bool cancel;
-} meshgen;
-
-static Client *client = NULL;
-
-static void set_block_ready(void *block)
-{
-       ((MapBlock *) block)->state = MBS_READY;
-}
-
-static void *meshgen_thread(__attribute__((unused)) void *unused)
-{
-       while (! meshgen.cancel) {
-               MapBlock *block;
-               if ((block = dequeue_callback(meshgen.queue, &set_block_ready)))
-                       make_block_mesh(block, client->map, client->scene);
-               else
-                       sched_yield();
-       }
-
-       return NULL;
-}
-
-void clientmap_init(Client *cli)
-{
-       client = cli;
-       meshgen.queue = create_queue();
-}
-
-void clientmap_start_meshgen()
-{
-       pthread_create(&meshgen.thread, NULL, &meshgen_thread, NULL);
-}
-
-void clientmap_deinit()
-{
-       meshgen.cancel = true;
-       delete_queue(meshgen.queue);
-       if (meshgen.thread)
-               pthread_join(meshgen.thread, NULL);
-}
-
-static void schedule_update_block(MapBlock *block)
-{
-       if (! block)
-               return;
-
-       pthread_mutex_lock(&block->mtx);
-       if (block->state != MBS_PROCESSING) {
-               block->state = MBS_PROCESSING;
-               enqueue(meshgen.queue, block);
-       }
-       pthread_mutex_unlock(&block->mtx);
-}
-
-void clientmap_block_changed(MapBlock *block)
-{
-       schedule_update_block(block);
-
-       schedule_update_block(map_get_block(client->map, (v3s32) {block->pos.x + 1, block->pos.y + 0, block->pos.z + 0}, false));
-       schedule_update_block(map_get_block(client->map, (v3s32) {block->pos.x + 0, block->pos.y + 1, block->pos.z + 0}, false));
-       schedule_update_block(map_get_block(client->map, (v3s32) {block->pos.x + 0, block->pos.y + 0, block->pos.z + 1}, false));
-       schedule_update_block(map_get_block(client->map, (v3s32) {block->pos.x - 1, block->pos.y - 0, block->pos.z - 0}, false));
-       schedule_update_block(map_get_block(client->map, (v3s32) {block->pos.x - 0, block->pos.y - 1, block->pos.z - 0}, false));
-       schedule_update_block(map_get_block(client->map, (v3s32) {block->pos.x - 0, block->pos.y - 0, block->pos.z - 1}, false));
-}
diff --git a/src/clientmap.h b/src/clientmap.h
deleted file mode 100644 (file)
index a56a766..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _CLIENTMAP_H_
-#define _CLIENTMAP_H_
-
-#include "client.h"
-
-void clientmap_init(Client *cli);
-void clientmap_start_meshgen();
-void clientmap_deinit();
-
-void clientmap_block_changed(MapBlock *block);
-
-#endif
diff --git a/src/clientnode.c b/src/clientnode.c
deleted file mode 100644 (file)
index fd0b9c6..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#include "client.h"
-#include "clientnode.h"
-#include "node.h"
-
-static void render_state_biome(MapNode *node, Vertex *vertex)
-{
-       vertex->r = node->state.biome.x;
-       vertex->g = node->state.biome.y;
-       vertex->b = node->state.biome.z;
-}
-
-ClientNodeDefintion client_node_definitions[NODE_UNLOADED] = {
-       // invalid
-       {
-               .texture_path = RESSOURCEPATH "textures/invalid.png",
-               .texture = NULL,
-               .render = NULL,
-       },
-       // air
-       {
-               .texture_path = NULL,
-               .texture = NULL,
-               .render = NULL,
-       },
-       // grass
-       {
-               .texture_path = RESSOURCEPATH "textures/grass.png",
-               .texture = NULL,
-               .render = &render_state_biome,
-       },
-       // dirt
-       {
-               .texture_path = RESSOURCEPATH "textures/dirt.png",
-               .texture = NULL,
-               .render = NULL,
-       },
-       // stone
-       {
-               .texture_path = RESSOURCEPATH "textures/stone.png",
-               .texture = NULL,
-               .render = NULL,
-       },
-       // snow
-       {
-               .texture_path = RESSOURCEPATH "textures/snow.png",
-               .texture = NULL,
-               .render = NULL,
-       },
-};
-
-void init_client_node_definitions()
-{
-       for (Node node = NODE_INVALID; node < NODE_UNLOADED; node++) {
-               ClientNodeDefintion *def = &client_node_definitions[node];
-               if (def->texture_path)
-                       def->texture = get_texture(def->texture_path);
-       }
-}
diff --git a/src/clientnode.h b/src/clientnode.h
deleted file mode 100644 (file)
index 60338ce..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _CLIENTNODE_H_
-#define _CLIENTNODE_H_
-
-#include "map.h"
-#include "mesh.h"
-#include "texture.h"
-
-typedef struct
-{
-       char *texture_path;
-       Texture *texture;
-       void (*render)(MapNode *node, Vertex *vertex);
-} ClientNodeDefintion;
-
-extern ClientNodeDefintion client_node_definitions[];
-void init_client_node_definitions();
-
-#endif
diff --git a/src/clientplayer.c b/src/clientplayer.c
deleted file mode 100644 (file)
index dbd9739..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-#include "camera.h"
-#include "client.h"
-#include "clientplayer.h"
-#include "cube.h"
-#include "texture.h"
-
-static void update_pos(ClientPlayer *player)
-{
-       set_camera_position((v3f) {player->pos.x, player->pos.y + player->eye_height, player->pos.z});
-
-       pthread_mutex_lock(&player->client->mtx);
-       (void) (write_u32(player->client->fd, SC_POS) && write_v3f32(player->client->fd, player->pos));
-       pthread_mutex_unlock(&player->client->mtx);
-
-       player->obj->pos = player->pos;
-       meshobject_transform(player->obj);
-}
-
-void clientplayer_init(Client *client)
-{
-       client->player.client = client;
-       client->player.pos = (v3f) {0.0f, 200.0f, 0.0f};
-       client->player.velocity = (v3f) {0.0f, 0.0f, 0.0f};
-       client->player.box = (aabb3f) {{-0.3f, 0.0f, -0.3f}, {0.3f, 1.75f, 0.3f}};
-       client->player.yaw = client->player.pitch = 0.0f;
-       client->player.eye_height = 1.5f;
-}
-
-void clientplayer_add_to_scene(ClientPlayer *player)
-{
-       VertexBuffer buffer = vertexbuffer_create();
-       vertexbuffer_set_texture(&buffer, get_texture(RESSOURCEPATH "textures/player.png"));
-
-       for (int f = 0; f < 6; f++) {
-               for (int v = 0; v < 6; v++) {
-                       Vertex vertex = cube_vertices[f][v];
-                       vertex.y += 0.5;
-                       vertexbuffer_add_vertex(&buffer, &vertex);
-               }
-       }
-
-       player->obj = meshobject_create(buffer, player->client->scene, (v3f) {0.0f, 0.0f, 0.0f});
-       player->obj->scale = (v3f) {0.6f, 1.75f, 0.6f};
-       player->obj->visible = false;
-
-       update_pos(player);
-}
-
-static aabb3f get_box(ClientPlayer *player)
-{
-       return (aabb3f) {
-               {player->box.min.x + player->pos.x, player->box.min.y + player->pos.y, player->box.min.z + player->pos.z},
-               {player->box.max.x + player->pos.x, player->box.max.y + player->pos.y, player->box.max.z + player->pos.z},
-       };
-}
-
-static aabb3s32 round_box(aabb3f box)
-{
-       return (aabb3s32) {
-               {floor(box.min.x + 0.5f), floor(box.min.y + 0.5f), floor(box.min.z + 0.5f)},
-               {ceil(box.max.x - 0.5f), ceil(box.max.y - 0.5f), ceil(box.max.z - 0.5f)},
-       };
-}
-
-static bool is_solid(Map *map, s32 x, s32 y, s32 z)
-{
-       Node node = map_get_node(map, (v3s32) {x, y, z}).type;
-       return node == NODE_UNLOADED || node_definitions[node].solid;
-}
-
-static bool can_jump(ClientPlayer *player)
-{
-       aabb3f fbox = get_box(player);
-       fbox.min.y -= 0.5f;
-
-       aabb3s32 box = round_box(fbox);
-
-       if (fbox.min.y - (f32) box.min.y > 0.01f)
-               return false;
-
-       for (s32 x = box.min.x; x <= box.max.x; x++)
-               for (s32 z = box.min.z; z <= box.max.z; z++)
-                       if (is_solid(player->client->map, x, box.min.y, z))
-                               return true;
-
-       return false;
-}
-
-void clientplayer_jump(ClientPlayer *player)
-{
-       if (can_jump(player))
-               player->velocity.y += 10.0f;
-}
-
-void clientplayer_tick(ClientPlayer *player, f64 dtime)
-{
-       v3f old_pos = player->pos;
-       v3f old_velocity = player->velocity;
-
-       player->velocity.y -= 32.0f * dtime;
-
-#define GETS(vec, comp) *(s32 *) ((char *) &vec + offsetof(v3s32, comp))
-#define GETF(vec, comp) *(f32 *) ((char *) &vec + offsetof(v3f32, comp))
-#define PHYSICS(a, b, c) { \
-               f32 v = (GETF(player->velocity, a) + GETF(old_velocity, a)) / 2.0f; \
-               if (v == 0.0f) \
-                       goto a ## _physics_done; \
-               aabb3s32 box = round_box(get_box(player)); \
-               v3f old_pos = player->pos; \
-               GETF(player->pos, a) += v * dtime; \
-               s32 dir; \
-               f32 offset; \
-               if (v > 0.0f) { \
-                       dir = +1; \
-                       offset = GETF(player->box.max, a); \
-                       GETS(box.min, a) = ceil(GETF(old_pos, a) + offset + 0.5f); \
-                       GETS(box.max, a) = floor(GETF(player->pos, a) + offset + 0.5f); \
-               } else { \
-                       dir = -1; \
-                       offset = GETF(player->box.min, a); \
-                       GETS(box.min, a) = floor(GETF(old_pos, a) + offset - 0.5f); \
-                       GETS(box.max, a) = ceil(GETF(player->pos, a) + offset - 0.5f); \
-               } \
-               GETS(box.max, a) += dir; \
-               for (s32 a = GETS(box.min, a); a != GETS(box.max, a); a += dir) { \
-                       for (s32 b = GETS(box.min, b); b <= GETS(box.max, b); b++) { \
-                               for (s32 c = GETS(box.min, c); c <= GETS(box.max, c); c++) { \
-                                       if (is_solid(player->client->map, x, y, z)) { \
-                                               GETF(player->pos, a) = (f32) a - offset - 0.5f * (f32) dir; \
-                                               GETF(player->velocity, a) = 0.0f; \
-                                               goto a ## _physics_done; \
-                                       } \
-                               } \
-                       } \
-               } \
-               a ## _physics_done: (void) 0;\
-       }
-
-       PHYSICS(x, y, z)
-       PHYSICS(y, x, z)
-       PHYSICS(z, x, y)
-
-#undef GETS
-#undef GETF
-#undef PHYSICS
-
-       if (old_pos.x != player->pos.x || old_pos.y != player->pos.y || old_pos.z != player->pos.z)
-               update_pos(player);
-}
diff --git a/src/clientplayer.h b/src/clientplayer.h
deleted file mode 100644 (file)
index b284108..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _CLIENTPLAYER_H_
-#define _CLIENTPLAYER_H_
-
-#include "mesh.h"
-#include "types.h"
-
-typedef struct
-{
-       struct Client *client;
-       v3f pos;
-       v3f velocity;
-       aabb3f box;
-       f32 yaw, pitch;
-       f32 eye_height;
-       MeshObject *obj;
-} ClientPlayer;
-
-void clientplayer_init(struct Client *client);
-void clientplayer_add_to_scene(ClientPlayer *player);
-void clientplayer_jump(ClientPlayer *player);
-void clientplayer_tick(ClientPlayer *player, f64 dtime);
-
-#endif
diff --git a/src/cube.c b/src/cube.c
deleted file mode 100644 (file)
index 9f632b8..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#include "cube.h"
-
-Vertex cube_vertices[6][6] = {
-       {
-               {-0.5, -0.5, -0.5, +0.0, +0.0, +1.0, +0.0, +1.0},
-               {+0.5, -0.5, -0.5, +1.0, +0.0, +1.0, +0.0, +1.0},
-               {+0.5, +0.5, -0.5, +1.0, +1.0, +1.0, +0.0, +1.0},
-               {+0.5, +0.5, -0.5, +1.0, +1.0, +1.0, +0.0, +1.0},
-               {-0.5, +0.5, -0.5, +0.0, +1.0, +1.0, +0.0, +1.0},
-               {-0.5, -0.5, -0.5, +0.0, +0.0, +1.0, +0.0, +1.0},
-       },
-       {
-               {-0.5, -0.5, +0.5, +0.0, +0.0, +1.0, +0.0, +1.0},
-               {+0.5, +0.5, +0.5, +1.0, +1.0, +1.0, +0.0, +1.0},
-               {+0.5, -0.5, +0.5, +1.0, +0.0, +1.0, +0.0, +1.0},
-               {+0.5, +0.5, +0.5, +1.0, +1.0, +1.0, +0.0, +1.0},
-               {-0.5, -0.5, +0.5, +0.0, +0.0, +1.0, +0.0, +1.0},
-               {-0.5, +0.5, +0.5, +0.0, +1.0, +1.0, +0.0, +1.0},
-       },
-       {
-               {-0.5, +0.5, +0.5, +1.0, +1.0, +1.0, +0.0, +1.0},
-               {-0.5, -0.5, -0.5, +0.0, +0.0, +1.0, +0.0, +1.0},
-               {-0.5, +0.5, -0.5, +0.0, +1.0, +1.0, +0.0, +1.0},
-               {-0.5, -0.5, -0.5, +0.0, +0.0, +1.0, +0.0, +1.0},
-               {-0.5, +0.5, +0.5, +1.0, +1.0, +1.0, +0.0, +1.0},
-               {-0.5, -0.5, +0.5, +1.0, +0.0, +1.0, +0.0, +1.0},
-       },
-       {
-               {+0.5, +0.5, +0.5, +1.0, +1.0, +1.0, +0.0, +1.0},
-               {+0.5, +0.5, -0.5, +0.0, +1.0, +1.0, +0.0, +1.0},
-               {+0.5, -0.5, -0.5, +0.0, +0.0, +1.0, +0.0, +1.0},
-               {+0.5, -0.5, -0.5, +0.0, +0.0, +1.0, +0.0, +1.0},
-               {+0.5, -0.5, +0.5, +1.0, +0.0, +1.0, +0.0, +1.0},
-               {+0.5, +0.5, +0.5, +1.0, +1.0, +1.0, +0.0, +1.0},
-       },
-       {
-               {-0.5, -0.5, -0.5, +0.0, +1.0, +1.0, +0.0, +1.0},
-               {+0.5, -0.5, -0.5, +1.0, +1.0, +1.0, +0.0, +1.0},
-               {+0.5, -0.5, +0.5, +1.0, +0.0, +1.0, +0.0, +1.0},
-               {+0.5, -0.5, +0.5, +1.0, +0.0, +1.0, +0.0, +1.0},
-               {-0.5, -0.5, +0.5, +0.0, +0.0, +1.0, +0.0, +1.0},
-               {-0.5, -0.5, -0.5, +0.0, +1.0, +1.0, +0.0, +1.0},
-       },
-       {
-               {-0.5, +0.5, -0.5, +0.0, +1.0, +1.0, +0.0, +1.0},
-               {+0.5, +0.5, -0.5, +1.0, +1.0, +1.0, +0.0, +1.0},
-               {+0.5, +0.5, +0.5, +1.0, +0.0, +1.0, +0.0, +1.0},
-               {+0.5, +0.5, +0.5, +1.0, +0.0, +1.0, +0.0, +1.0},
-               {-0.5, +0.5, +0.5, +0.0, +0.0, +1.0, +0.0, +1.0},
-               {-0.5, +0.5, -0.5, +0.0, +1.0, +1.0, +0.0, +1.0},
-       },
-};
-
diff --git a/src/cube.h b/src/cube.h
deleted file mode 100644 (file)
index 837c593..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _CUBE_H_
-#define _CUBE_H_
-
-#include "mesh.h"
-
-extern Vertex cube_vertices[6][6];
-
-#endif
diff --git a/src/facecache.c b/src/facecache.c
deleted file mode 100644 (file)
index 341cb24..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#include <stdlib.h>
-#include "array.h"
-#include "facecache.h"
-
-static struct
-{
-       Array positions;
-       u32 size;
-       pthread_mutex_t mtx;
-} facecache;
-
-__attribute((constructor)) static void init_face_cache()
-{
-       facecache.size = 0;
-       facecache.positions = array_create(sizeof(v3s32));
-       v3s32 pos = {0, 0, 0};
-       array_append(&facecache.positions, &pos);
-       pthread_mutex_init(&facecache.mtx, NULL);
-}
-
-__attribute((destructor)) void deinit_face_cache()
-{
-       if (facecache.positions.ptr)
-               free(facecache.positions.ptr);
-       pthread_mutex_destroy(&facecache.mtx);
-}
-
-static void calculate_face_cache(s32 size)
-{
-#define ADDPOS(a, b, c, va, vb, vc) \
-       { \
-               v3s32 pos; \
-               *(s32 *) ((char *) &pos + offsetof(v3s32, a)) = va; \
-               *(s32 *) ((char *) &pos + offsetof(v3s32, b)) = vb; \
-               *(s32 *) ((char *) &pos + offsetof(v3s32, c)) = vc; \
-               array_append(&facecache.positions, &pos); \
-       }
-#define SQUARES(a, b, c) \
-       for (s32 va = -size + 1; va < size; va++) { \
-               for (s32 vb = -size + 1; vb < size; vb++) { \
-                       ADDPOS(a, b, c, va, vb,  size) \
-                       ADDPOS(a, b, c, va, vb, -size) \
-               } \
-       }
-       SQUARES(x, z, y)
-       SQUARES(x, y, z)
-       SQUARES(z, y, x)
-#undef SQUARES
-#define EDGES(a, b, c) \
-       for (s32 va = -size + 1; va < size; va++) { \
-               ADDPOS(a, b, c, va,  size,  size) \
-               ADDPOS(a, b, c, va,  size, -size) \
-               ADDPOS(a, b, c, va, -size,  size) \
-               ADDPOS(a, b, c, va, -size, -size) \
-       }
-       EDGES(x, y, z)
-       EDGES(z, x, y)
-       EDGES(y, x, z)
-#undef EDGES
-       ADDPOS(x, y, z,  size,  size,  size)
-       ADDPOS(x, y, z,  size,  size, -size)
-       ADDPOS(x, y, z,  size, -size,  size)
-       ADDPOS(x, y, z,  size, -size, -size)
-       ADDPOS(x, y, z, -size,  size,  size)
-       ADDPOS(x, y, z, -size,  size, -size)
-       ADDPOS(x, y, z, -size, -size,  size)
-       ADDPOS(x, y, z, -size, -size, -size)
-#undef ADDPOS
-}
-
-v3s32 get_face(size_t i, v3s32 *base)
-{
-       pthread_mutex_lock(&facecache.mtx);
-       while (facecache.positions.siz <= i)
-               calculate_face_cache(++facecache.size);
-       v3s32 pos = ((v3s32 *) facecache.positions.ptr)[i];
-       pthread_mutex_unlock(&facecache.mtx);
-       if (base) {
-               pos.x += base->x;
-               pos.y += base->y;
-               pos.z += base->z;
-       }
-       return pos;
-}
-
-size_t get_face_count(u32 size)
-{
-       size_t len = 1 + size * 2;
-       return 1 + len * len * len;
-}
diff --git a/src/facecache.h b/src/facecache.h
deleted file mode 100644 (file)
index 706349c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _FACECACHE_H_
-#define _FACECACHE_H_
-
-#include <pthread.h>
-#include "types.h"
-
-v3s32 get_face(size_t i, v3s32 *base);
-size_t get_face_count(u32 size);
-
-#endif
diff --git a/src/hud.c b/src/hud.c
deleted file mode 100644 (file)
index fe20893..0000000
--- a/src/hud.c
+++ /dev/null
@@ -1,117 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-#include <GL/glew.h>
-#include <GL/gl.h>
-#include "client.h"
-#include "cube.h"
-#include "hud.h"
-
-static struct
-{
-       MeshObject *obj;
-       List elements;
-       ShaderProgram *prog;
-       mat4x4 view, projection;
-       int width, height;
-} hud;
-
-void hud_init(ShaderProgram *prog)
-{
-       hud.prog = prog;
-       hud.elements = list_create(NULL);
-
-       Texture *texture = get_texture(RESSOURCEPATH "textures/invalid.png");
-       VertexBuffer buffer = vertexbuffer_create();
-       vertexbuffer_set_texture(&buffer, texture);
-
-       for (int v = 0; v < 6; v++) {
-               Vertex vertex = cube_vertices[0][v];
-               vertex.z = 0.0f;
-               vertexbuffer_add_vertex(&buffer, &vertex);
-       }
-
-       hud.obj = meshobject_create(buffer, NULL, (v3f) {0.0f, 0.0f, 0.0f});
-
-       mat4x4_identity(hud.view);
-}
-
-static void free_element(void *key, __attribute__((unused)) void *value, __attribute__((unused)) void *arg)
-{
-       free(key);
-}
-
-void hud_deinit()
-{
-       meshobject_delete(hud.obj);
-       list_clear_func(&hud.elements, &free_element, NULL);
-}
-
-static void element_transform(HUDElement *element)
-{
-       mat4x4_translate(element->transform, (1.0f + element->pos.x) / 2.0f * (f32) hud.width, (1.0f + element->pos.y) / 2.0f * (f32) hud.height, element->pos.z);
-
-       v2f scale = element->scale;
-
-       switch (element->scale_type) {
-               case HUD_SCALE_TEXTURE:
-                       scale.x *= element->texture->width;
-                       scale.y *= element->texture->height;
-
-                       break;
-
-               case HUD_SCALE_SCREEN:
-                       scale.x *= hud.width * 2.0f;
-                       scale.y *= hud.height * 2.0f;
-
-                       break;
-
-               default:
-                       break;
-       }
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpedantic"
-       mat4x4_scale_aniso(element->transform, element->transform, scale.x, scale.y, 1.0f);
-#pragma GCC diagnostic pop
-}
-
-void hud_on_resize(int width, int height)
-{
-       hud.width = width;
-       hud.height = height;
-       mat4x4_ortho(hud.projection, 0, width, height, 0, -1.0f, 1.0f);
-
-       for (ListPair *pair = hud.elements.first; pair != NULL; pair = pair->next)
-               element_transform(pair->key);
-}
-
-void hud_render()
-{
-       glUniformMatrix4fv(hud.prog->loc_view, 1, GL_FALSE, hud.view[0]);
-       glUniformMatrix4fv(hud.prog->loc_projection, 1, GL_FALSE, hud.projection[0]);
-
-       for (ListPair *pair = hud.elements.first; pair != NULL; pair = pair->next) {
-               HUDElement *element = pair->key;
-
-               if (element->visible) {
-                       memcpy(hud.obj->transform, element->transform, sizeof(mat4x4));
-                       hud.obj->meshes[0]->texture = element->texture->id;
-                       meshobject_render(hud.obj, hud.prog);
-               }
-       }
-}
-
-HUDElement *hud_add(char *texture, v3f pos, v2f scale, HUDScaleType scale_type)
-{
-       HUDElement *element = malloc(sizeof(HUDElement));
-       element->texture = get_texture(texture);
-       element->visible = true;
-       element->pos = pos;
-       element->scale = scale;
-       element->scale_type = scale_type;
-
-       element_transform(element);
-
-       list_set(&hud.elements, element, NULL);
-       return element;
-}
diff --git a/src/hud.h b/src/hud.h
deleted file mode 100644 (file)
index 90c21b8..0000000
--- a/src/hud.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef _HUD_H_
-#define _HUD_H_
-
-#include <stdbool.h>
-#include <linmath.h/linmath.h>
-#include "shaders.h"
-#include "texture.h"
-#include "types.h"
-
-typedef enum
-{
-       HUD_SCALE_TEXTURE,
-       HUD_SCALE_SCREEN,
-       HUD_SCALE_NONE,
-} HUDScaleType;
-
-typedef struct
-{
-       Texture *texture;
-       bool visible;
-       v3f pos;
-       v2f scale;
-       HUDScaleType scale_type;
-       mat4x4 transform;
-} HUDElement;
-
-void hud_init(ShaderProgram *prog);
-void hud_deinit();
-void hud_on_resize(int width, int height);
-void hud_render();
-HUDElement *hud_add(char *texture, v3f pos, v2f scale, HUDScaleType scale_type);
-
-#endif
diff --git a/src/input.c b/src/input.c
deleted file mode 100644 (file)
index 6d9784c..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-#include <math.h>
-#include "camera.h"
-#include "client.h"
-#include "hud.h"
-#include "input.h"
-
-typedef struct
-{
-       int key;
-       bool was_pressed;
-       bool fired;
-} KeyListener;
-
-static struct
-{
-       GLFWwindow *window;
-       Client *client;
-       HUDElement *pause_menu_hud;
-       bool paused;
-       bool fullscreen;
-       KeyListener pause_listener;
-       KeyListener fullscreen_listener;
-       int small_x, small_y, small_width, small_height;
-} input;
-
-void input_on_cursor_pos(double current_x, double current_y)
-{
-       if (input.paused)
-               return;
-
-       static double last_x, last_y = 0.0;
-
-       double delta_x = current_x - last_x;
-       double delta_y = current_y - last_y;
-       last_x = current_x;
-       last_y = current_y;
-
-       input.client->player.yaw += (f32) delta_x * M_PI / 180.0f / 8.0f;
-       input.client->player.pitch -= (f32) delta_y * M_PI / 180.0f / 8.0f;
-
-       input.client->player.pitch = fmax(fmin(input.client->player.pitch, M_PI / 2.0f - 0.01f), -M_PI / 2.0f + 0.01f);
-
-       set_camera_angle(input.client->player.yaw, input.client->player.pitch);
-}
-
-void input_on_resize(int width, int height)
-{
-       if (! input.fullscreen) {
-               input.small_width = width;
-               input.small_height = height;
-       }
-}
-
-void input_on_window_pos(int x, int y)
-{
-       if (! input.fullscreen) {
-               input.small_x = x;
-               input.small_y = y;
-       }
-}
-
-static bool move(int forward, int backward, vec3 dir)
-{
-       f32 sign;
-       f32 speed = 4.317f;
-
-       if (glfwGetKey(input.window, forward) == GLFW_PRESS)
-               sign = +1.0f;
-       else if (glfwGetKey(input.window, backward) == GLFW_PRESS)
-               sign = -1.0f;
-       else
-               return false;
-
-       input.client->player.velocity.x += dir[0] * speed * sign;
-       input.client->player.velocity.z += dir[2] * speed * sign;
-
-       return true;
-}
-
-static void enter_game()
-{
-       glfwSetInputMode(input.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
-       input.pause_menu_hud->visible = false;
-}
-
-static void do_key_listener(KeyListener *listener)
-{
-       bool is_pressed = glfwGetKey(input.window, listener->key) == GLFW_PRESS;
-       listener->fired = listener->was_pressed && ! is_pressed;
-       listener->was_pressed = is_pressed;
-}
-
-static KeyListener create_key_listener(int key)
-{
-       return (KeyListener) {
-               .key = key,
-               .was_pressed = false,
-               .fired = false,
-       };
-}
-
-void process_input()
-{
-       do_key_listener(&input.pause_listener);
-       do_key_listener(&input.fullscreen_listener);
-
-       if (input.pause_listener.fired) {
-               input.paused = ! input.paused;
-
-               if (input.paused) {
-                       glfwSetInputMode(input.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
-                       input.pause_menu_hud->visible = true;
-               } else {
-                       enter_game();
-               }
-       }
-
-       if (input.fullscreen_listener.fired) {
-               input.fullscreen = ! input.fullscreen;
-
-               if (input.fullscreen) {
-                       GLFWmonitor *monitor = glfwGetPrimaryMonitor();
-                       const GLFWvidmode *vidmode = glfwGetVideoMode(monitor);
-                       glfwSetWindowMonitor(input.window, monitor, 0, 0, vidmode->width, vidmode->height, 0);
-               } else {
-                       glfwSetWindowMonitor(input.window, NULL, input.small_x, input.small_y, input.small_width, input.small_height, 0);
-               }
-       }
-
-       input.client->player.velocity.x = 0.0f;
-       input.client->player.velocity.z = 0.0f;
-
-       if (! input.paused) {
-               move(GLFW_KEY_W, GLFW_KEY_S, movement_dirs.front);
-               move(GLFW_KEY_D, GLFW_KEY_A, movement_dirs.right);
-
-               if (glfwGetKey(input.window, GLFW_KEY_SPACE) == GLFW_PRESS)
-                       clientplayer_jump(&input.client->player);
-       }
-}
-
-void init_input(Client *client, GLFWwindow *window)
-{
-       input.client = client;
-       input.window = window;
-
-       input.paused = false;
-
-       input.pause_listener = create_key_listener(GLFW_KEY_ESCAPE);
-       input.fullscreen_listener = create_key_listener(GLFW_KEY_F11);
-
-       input.pause_menu_hud = hud_add(RESSOURCEPATH "textures/pause_layer.png", (v3f) {-1.0f, -1.0f, 0.5f}, (v2f) {1.0f, 1.0f}, HUD_SCALE_SCREEN);
-
-       enter_game();
-}
-
-
diff --git a/src/input.h b/src/input.h
deleted file mode 100644 (file)
index 4ad202a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _INPUT_H_
-#define _INPUT_H_
-
-#include <GLFW/glfw3.h>
-
-void process_input();
-void init_input(Client *client, GLFWwindow *window);
-void input_on_cursor_pos(double current_x, double current_y);
-void input_on_resize(int width, int height);
-void input_on_window_pos(int x, int y);
-
-#endif
index 51e4cd7649a0804903803d72816cee7d7a5c95a4..4c73cc812962dae8390788ad380971ef90a18820 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -285,7 +285,7 @@ MapNode map_node_create(Node type)
        node.type = type;
        memset(&node.state, 0, sizeof(NodeState));
 
-       if (node_definitions[node.type].create)
+       if (node.type != NODE_UNLOADED && node_definitions[node.type].create)
                node_definitions[node.type].create(&node);
 
        return node;
diff --git a/src/mapdb.c b/src/mapdb.c
deleted file mode 100644 (file)
index 686fa26..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#include <stdio.h>
-#include <endian.h>
-#include <stdlib.h>
-#include "mapdb.h"
-#include "servermap.h"
-
-static void print_error(sqlite3 *db, MapBlock *block, const char *action)
-{
-       printf("Database error with %s block at %d %d %d: %s\n", action, block->pos.x, block->pos.y, block->pos.z, sqlite3_errmsg(db));
-}
-
-sqlite3 *open_mapdb(const char *path)
-{
-       sqlite3 *db;
-       char *err;
-
-       if (sqlite3_open_v2(path, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK) {
-               printf("Failed to open database: %s\n", sqlite3_errmsg(db));
-       } else if (sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS blocks (pos BLOB PRIMARY KEY, data BLOB NOT NULL);", NULL, NULL, &err) != SQLITE_OK) {
-               printf("Failed to initialize database: %s\n", err);
-               sqlite3_free(err);
-       }
-
-       return db;
-}
-
-static sqlite3_stmt *prepare_statement(sqlite3 *db, MapBlock *block, const char *action, const char *sql)
-{
-       sqlite3_stmt *stmt;
-
-       if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
-               print_error(db, block, action);
-               return NULL;
-       }
-
-       size_t psize = sizeof(s32) * 3;
-       s32 *pos = malloc(psize);
-       pos[0] = htobe32(block->pos.x);
-       pos[1] = htobe32(block->pos.y);
-       pos[2] = htobe32(block->pos.z);
-
-       sqlite3_bind_blob(stmt, 1, pos, psize, &free);
-
-       return stmt;
-}
-
-bool load_block(sqlite3 *db, MapBlock *block)
-{
-       sqlite3_stmt *stmt;
-
-       if (! (stmt = prepare_statement(db, block, "loading", "SELECT data FROM blocks WHERE pos=?")))
-               return false;
-
-       int rc = sqlite3_step(stmt);
-       bool found = rc == SQLITE_ROW;
-
-       if (found) {
-               const char *data = sqlite3_column_blob(stmt, 0);
-               map_deserialize_block(block, data + sizeof(MapBlockHeader), be32toh(*(MapBlockHeader *) data));
-       } else if (rc != SQLITE_DONE) {
-               print_error(db, block, "loading");
-       }
-
-       sqlite3_finalize(stmt);
-       return found;
-}
-
-void save_block(sqlite3 *db, MapBlock *block)
-{
-       sqlite3_stmt *stmt;
-
-       if (! (stmt = prepare_statement(db, block, "saving", "REPLACE INTO blocks (pos, data) VALUES(?1, ?2)")))
-               return;
-
-       MapBlockExtraData *extra = block->extra;
-
-       sqlite3_bind_blob(stmt, 2, extra->data, extra->size, SQLITE_TRANSIENT);
-
-       if (sqlite3_step(stmt) != SQLITE_DONE)
-               print_error(db, block, "saving");
-
-       sqlite3_finalize(stmt);
-}
diff --git a/src/mapdb.h b/src/mapdb.h
deleted file mode 100644 (file)
index beb318b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _MAPDB_H_
-#define _MAPDB_H_
-
-#include <sqlite3.h>
-#include <stdbool.h>
-#include "map.h"
-
-sqlite3 *open_mapdb(const char *path);
-bool load_block(sqlite3 *db, MapBlock *block);
-void save_block(sqlite3 *db, MapBlock *block);
-
-#endif
diff --git a/src/mapgen.c b/src/mapgen.c
deleted file mode 100644 (file)
index dcfd386..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <math.h>
-#include "mapgen.h"
-#include "perlin.h"
-
-void mapgen_generate_block(MapBlock *block)
-{
-       for (u8 x = 0; x < 16; x++) {
-               u32 ux = x + block->pos.x * 16 + ((u32) 1 << 31);
-               for (u8 z = 0; z < 16; z++) {
-                       u32 uz = z + block->pos.z * 16 + ((u32) 1 << 31);
-                       s32 height = smooth2d(ux / 32.0, uz / 32.0, 0, 0) * 16.0 + 128.0;
-                       bool is_mountain = false;
-
-                       double mountain_factor = (smooth2d(ux / 1000.0, uz / 1000.0, 0, 1) - 0.3) * 5.0;
-
-                       if (mountain_factor > 0.0) {
-                               height = pow(height * pow(((smooth2d(ux / 50.0, uz / 50.0, 2, 2) + 1.0) * 256.0 + 128.0), mountain_factor), 1.0 / (mountain_factor + 1.0));
-                               is_mountain = true;
-                       }
-
-                       for (u8 y = 0; y < 16; y++) {
-                               s32 ay = block->pos.y * 16 + y;
-                               s32 diff = ay - height;
-
-                               Node node = NODE_AIR;
-
-                               if (diff < -5)
-                                       node = NODE_STONE;
-                               else if (diff < -1)
-                                       node = is_mountain ? NODE_STONE : NODE_DIRT;
-                               else if (diff < 0)
-                                       node = is_mountain ? NODE_STONE : NODE_GRASS;
-                               else if (diff < 1)
-                                       node = (is_mountain && ay > 256) ? NODE_SNOW : NODE_AIR;
-
-                               block->data[x][y][z] = map_node_create(node);
-                               block->metadata[x][y][z] = list_create(&list_compare_string);
-
-                               if (node == NODE_GRASS) {
-                                       double min, max;
-                                       min = 0.15;
-                                       max = 0.45;
-                                       block->data[x][y][z].state.biome.x = (smooth2d(ux / 128.0, uz / 128.0, 0, 3) * 0.5 + 0.5) * (max - min) + min;
-                                       block->data[x][y][z].state.biome.y = 1.0;
-                               }
-                       }
-               }
-       }
-}
diff --git a/src/mapgen.h b/src/mapgen.h
deleted file mode 100644 (file)
index 8f1b20d..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _MAPGEN_H_
-#define _MAPGEN_H_
-
-#include "map.h"
-
-void mapgen_generate_block(MapBlock *block);
-
-#endif
diff --git a/src/mesh.c b/src/mesh.c
deleted file mode 100644 (file)
index ab2f793..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include "mesh.h"
-#include "scene.h"
-
-VertexBuffer vertexbuffer_create()
-{
-       return (VertexBuffer) {
-               .faces = array_create(sizeof(Face)),
-       };
-}
-
-void vertexbuffer_set_texture(VertexBuffer *buffer, Texture *texture)
-{
-       if (buffer->current && buffer->current->texture == texture->id)
-               return;
-       Face face = {
-               .texture = texture->id,
-               .vertices = array_create(sizeof(Vertex)),
-       };
-       array_append(&buffer->faces, &face);
-       buffer->current = &((Face *) buffer->faces.ptr)[buffer->faces.siz - 1];
-}
-
-void vertexbuffer_add_vertex(VertexBuffer *buffer, Vertex *vertex)
-{
-       array_append(&buffer->current->vertices, vertex);
-}
-
-static int qsort_compare_faces(const void *f1, const void *f2)
-{
-       return ((Face *) f1)->texture - ((Face *) f2)->texture;
-}
-
-static void add_mesh(Array *meshes, Array *vertices, GLuint texture)
-{
-       if (vertices->siz > 0) {
-               Mesh *mesh = malloc(sizeof(Mesh));
-               mesh->VAO = mesh->VBO = 0;
-               // the reason the vertices are not copied and then free'd like anything else is that the vertices will be deleted after the first render anyway
-               mesh->vertices = vertices->ptr;
-               mesh->vertices_count = vertices->siz;
-               mesh->texture = texture;
-
-               array_append(meshes, &mesh);
-       }
-
-       *vertices = array_create(sizeof(Vertex));
-}
-
-MeshObject *meshobject_create(VertexBuffer buffer, struct Scene *scene, v3f pos)
-{
-       if (buffer.faces.siz == 0)
-               return NULL;
-
-       MeshObject *obj = malloc(sizeof(MeshObject));
-       obj->remove = false;
-
-       obj->pos = pos;
-       obj->rot = (v3f) {0.0f, 0.0f, 0.0f};
-       obj->scale = (v3f) {1.0f, 1.0f, 1.0f};
-       obj->angle = 0.0f;
-       obj->visible = true;
-       obj->wireframe = false;
-       meshobject_transform(obj);
-
-       qsort(buffer.faces.ptr, buffer.faces.siz, sizeof(Face), &qsort_compare_faces);
-
-       Array meshes = array_create(sizeof(Mesh *));
-       Array vertices = array_create(sizeof(Vertex));
-       GLuint texture = 0;
-
-       for (size_t f = 0; f < buffer.faces.siz; f++) {
-               Face *face = &((Face *) buffer.faces.ptr)[f];
-
-               if (face->texture != texture) {
-                       add_mesh(&meshes, &vertices, texture);
-                       texture = face->texture;
-               }
-
-               for (size_t v = 0; v < face->vertices.siz; v++)
-                       array_append(&vertices, &((Vertex *) face->vertices.ptr)[v]);
-               free(face->vertices.ptr);
-       }
-       add_mesh(&meshes, &vertices, texture);
-       free(buffer.faces.ptr);
-
-       array_copy(&meshes, (void *) &obj->meshes, &obj->meshes_count);
-       free(meshes.ptr);
-
-       if (scene)
-               scene_add_object(scene, obj);
-
-       return obj;
-}
-
-
-void meshobject_transform(MeshObject *obj)
-{
-       mat4x4_translate(obj->transform, obj->pos.x, obj->pos.y, obj->pos.z);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpedantic"
-       mat4x4_rotate(obj->transform, obj->transform, obj->rot.x, obj->rot.y, obj->rot.z, obj->angle);
-       mat4x4_scale_aniso(obj->transform, obj->transform, obj->scale.x, obj->scale.y, obj->scale.z);
-#pragma GCC diagnostic pop
-}
-
-
-void meshobject_delete(MeshObject *obj)
-{
-       for (size_t i = 0; i < obj->meshes_count; i++) {
-               Mesh *mesh = obj->meshes[i];
-
-               if (mesh->vertices)
-                       free(mesh->vertices);
-
-               if (mesh->VAO)
-                       glDeleteVertexArrays(1, &mesh->VAO);
-
-               if (mesh->VBO)
-                       glDeleteBuffers(1, &mesh->VAO);
-
-               free(mesh);
-       }
-
-       free(obj);
-}
-
-static void mesh_configure(Mesh *mesh)
-{
-       glGenVertexArrays(1, &mesh->VAO);
-       glGenBuffers(1, &mesh->VBO);
-
-       glBindVertexArray(mesh->VAO);
-       glBindBuffer(GL_ARRAY_BUFFER, mesh->VBO);
-
-       glBufferData(GL_ARRAY_BUFFER, mesh->vertices_count * sizeof(Vertex), mesh->vertices, GL_STATIC_DRAW);
-
-       glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(Vertex), (GLvoid *) offsetof(Vertex, x));
-       glEnableVertexAttribArray(0);
-
-       glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(Vertex), (GLvoid *) offsetof(Vertex, s));
-       glEnableVertexAttribArray(1);
-
-       glVertexAttribPointer(2, 3, GL_FLOAT, false, sizeof(Vertex), (GLvoid *) offsetof(Vertex, r));
-       glEnableVertexAttribArray(2);
-
-       glBindBuffer(GL_ARRAY_BUFFER, 0);
-       glBindVertexArray(0);
-
-       free(mesh->vertices);
-       mesh->vertices = NULL;
-}
-
-void meshobject_render(MeshObject *obj, ShaderProgram *prog)
-{
-       if (! obj->visible)
-               return;
-
-       glUniformMatrix4fv(prog->loc_model, 1, GL_FALSE, obj->transform[0]);
-
-       glActiveTexture(GL_TEXTURE0);
-
-       if (obj->wireframe)
-               glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
-       for (size_t i = 0; i < obj->meshes_count; i++) {
-               Mesh *mesh = obj->meshes[i];
-
-               if (mesh->vertices)
-                       mesh_configure(mesh);
-
-               glBindTexture(GL_TEXTURE_2D, mesh->texture);
-               glBindVertexArray(mesh->VAO);
-
-               glDrawArrays(GL_TRIANGLES, 0, mesh->vertices_count);
-       }
-
-       glBindTexture(GL_TEXTURE_2D, 0);
-       glBindVertexArray(0);
-
-       if (obj->wireframe)
-               glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-}
diff --git a/src/mesh.h b/src/mesh.h
deleted file mode 100644 (file)
index 9271bef..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef _MESH_H_
-#define _MESH_H_
-
-#include <GL/glew.h>
-#include <GL/gl.h>
-#include <linmath.h/linmath.h>
-#include <stdbool.h>
-#include "array.h"
-#include "shaders.h"
-#include "texture.h"
-#include "types.h"
-
-typedef struct
-{
-       GLfloat x, y, z;
-       GLfloat s, t;
-       GLfloat r, g, b;
-} __attribute__((packed)) Vertex;
-
-typedef struct
-{
-       GLuint texture;
-       Array vertices;
-} Face;
-
-typedef struct
-{
-       Face *current;
-       Array faces;
-} VertexBuffer;
-
-typedef struct
-{
-       GLuint VAO, VBO;
-       GLuint texture;
-       Vertex *vertices;
-       GLuint vertices_count;
-} Mesh;
-
-typedef struct
-{
-       v3f pos, rot, scale;
-       f32 angle;
-       bool visible;
-       mat4x4 transform;
-       bool remove;
-       Mesh **meshes;
-       size_t meshes_count;
-       bool wireframe;
-} MeshObject;
-
-struct Scene;
-
-VertexBuffer vertexbuffer_create();
-void vertexbuffer_set_texture(VertexBuffer *buffer, Texture *texture);
-void vertexbuffer_add_vertex(VertexBuffer *buffer, Vertex *vertex);
-
-MeshObject *meshobject_create(VertexBuffer buffer, struct Scene *scene, v3f pos);
-void meshobject_delete(MeshObject *obj);
-void meshobject_transform(MeshObject *obj);
-void meshobject_render(MeshObject *obj, ShaderProgram *prog);
-
-#endif
index f21ecbec92270e9c4f2b8a610502fa2de41e8383..4ae343d624362876b665804948906c97d0fe1af0 100644 (file)
@@ -2,7 +2,7 @@
 #define _NETWORK_H_
 
 #include <stdbool.h>
-#define NAME_MAX 64
+#define PLAYER_NAME_MAX 64
 
 typedef enum
 {
diff --git a/src/perlin.c b/src/perlin.c
deleted file mode 100644 (file)
index c6d415c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#include <perlin/perlin.c>
-
diff --git a/src/perlin.h b/src/perlin.h
deleted file mode 100644 (file)
index b328f61..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _PERLIN_H_
-#define _PERLIN_H_
-
-#include <perlin/perlin.h>
-
-#endif
index 05375d661e7fe9bd0ac2e9ff27baacf1521ba4e9..04aaccd548e2f7c1333446db4a337ec43f3c764f 100644 (file)
@@ -1,7 +1,7 @@
 #include <stdlib.h>
 #include "queue.h"
 
-Queue *create_queue()
+Queue *queue_create()
 {
        Queue *queue = malloc(sizeof(Queue));
        queue->list = list_create(NULL);
@@ -9,14 +9,14 @@ Queue *create_queue()
        return queue;
 }
 
-void delete_queue(Queue *queue)
+void queue_delete(Queue *queue)
 {
        pthread_mutex_destroy(&queue->mtx);
        list_clear(&queue->list);
        free(queue);
 }
 
-void enqueue(Queue *queue, void *elem)
+void queue_enqueue(Queue *queue, void *elem)
 {
        pthread_mutex_lock(&queue->mtx);
        list_put(&queue->list, elem, NULL);
@@ -25,10 +25,10 @@ void enqueue(Queue *queue, void *elem)
 
 void *dequeue(Queue *queue)
 {
-       return dequeue_callback(queue, NULL);
+       return queue_dequeue_callback(queue, NULL);
 }
 
-void *dequeue_callback(Queue *queue, void (*callback)(void *elem))
+void *queue_dequeue_callback(Queue *queue, void (*callback)(void *elem))
 {
        pthread_mutex_lock(&queue->mtx);
        void *elem = NULL;
index d77f048fdac0fa1eed93aa49978b1cdf68c18d50..d6690263113bf6016d3e0c33dece74025d497b9a 100644 (file)
@@ -10,10 +10,10 @@ typedef struct
        pthread_mutex_t mtx;
 } Queue;
 
-Queue *create_queue();
-void delete_queue(Queue *queue);
-void enqueue(Queue *queue, void *elem);
-void *dequeue(Queue *queue);
-void *dequeue_callback(Queue *queue, void (*callback)(void *elem));
+Queue *queue_create();
+void queue_delete(Queue *queue);
+void queue_enqueue(Queue *queue, void *elem);
+void *queue_dequeue(Queue *queue);
+void *queue_dequeue_callback(Queue *queue, void (*callback)(void *elem));
 
 #endif
diff --git a/src/scene.c b/src/scene.c
deleted file mode 100644 (file)
index a753d13..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#include <stdlib.h>
-#include "scene.h"
-
-Scene *scene_create()
-{
-       Scene *scene = malloc(sizeof(Scene));
-       scene->objects = list_create(NULL),
-       pthread_mutex_init(&scene->mtx, NULL);
-       return scene;
-}
-
-static void list_delete_mesh(void *key, __attribute__((unused)) void *value, __attribute__((unused)) void *unused)
-{
-       meshobject_delete(key);
-}
-
-void scene_delete(Scene *scene)
-{
-       list_clear_func(&scene->objects, &list_delete_mesh, NULL);
-       pthread_mutex_destroy(&scene->mtx);
-       free(scene);
-}
-
-void scene_add_object(Scene *scene, MeshObject *obj)
-{
-       pthread_mutex_lock(&scene->mtx);
-       list_put(&scene->objects, obj, NULL);
-       pthread_mutex_unlock(&scene->mtx);
-}
-
-void scene_render(Scene *scene, ShaderProgram *prog)
-{
-       for (ListPair **pairptr = &scene->objects.first; *pairptr != NULL; ) {
-               ListPair *pair = *pairptr;
-               MeshObject *obj = pair->key;
-               if (obj->remove) {
-                       pthread_mutex_lock(&scene->mtx);
-                       *pairptr = pair->next;
-                       pthread_mutex_unlock(&scene->mtx);
-                       free(pair);
-                       meshobject_delete(obj);
-               } else {
-                       meshobject_render(obj, prog);
-                       pairptr = &pair->next;
-               }
-       }
-}
diff --git a/src/scene.h b/src/scene.h
deleted file mode 100644 (file)
index 465e860..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef _SCENE_H_
-#define _SCENE_H_
-
-#include <pthread.h>
-#include "list.h"
-#include "mesh.h"
-#include "shaders.h"
-
-typedef struct Scene
-{
-       List objects;
-       pthread_mutex_t mtx;
-} Scene;
-
-Scene *scene_create();
-void scene_delete(Scene *scene);
-
-void scene_add_object(Scene *scene, MeshObject *obj);
-void scene_render(Scene *scene, ShaderProgram *prog);
-
-#endif
diff --git a/src/server.c b/src/server.c
deleted file mode 100644 (file)
index fed4ab4..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <netdb.h>
-#include "server.h"
-#include "servermap.h"
-#include "signal.h"
-#include "util.h"
-
-Server server;
-
-void server_disconnect_client(Client *client, int flags, const char *detail)
-{
-       client->state = CS_DISCONNECTED;
-
-       if (! (flags & DISCO_NO_REMOVE)) {
-               if (client->name) {
-                       pthread_rwlock_wrlock(&server.players_rwlck);
-                       list_delete(&server.players, client->name);
-                       pthread_rwlock_unlock(&server.players_rwlck);
-               }
-               pthread_rwlock_wrlock(&server.clients_rwlck);
-               list_delete(&server.clients, client);
-               pthread_rwlock_unlock(&server.clients_rwlck);
-       }
-
-       if (! (flags & DISCO_NO_MESSAGE))
-               printf("Disconnected %s %s%s%s\n", client->name, INBRACES(detail));
-
-       if (! (flags & DISCO_NO_SEND))
-               send_command(client, CC_DISCONNECT);
-
-       pthread_mutex_lock(&client->mtx);
-       close(client->fd);
-       pthread_mutex_unlock(&client->mtx);
-
-       if (! (flags & DISCO_NO_JOIN))
-               pthread_join(client->net_thread, NULL);
-
-       if (client->name != client->address)
-               free(client->name);
-       free(client->address);
-
-       pthread_mutex_destroy(&client->mtx);
-       free(client);
-}
-
-#include "network.c"
-
-static void *server_reciever_thread(void *cli)
-{
-       Client *client = cli;
-
-       if (! handle_packets(client))
-               server_disconnect_client(client, DISCO_NO_SEND | DISCO_NO_JOIN, "network error");
-
-       return NULL;
-}
-
-static void server_accept_client()
-{
-       struct sockaddr_storage client_address = {0};
-       socklen_t client_addrlen = sizeof(client_address);
-
-       int fd = accept(server.sockfd, (struct sockaddr *) &client_address, &client_addrlen);
-
-       if (fd == -1) {
-               if (errno != EINTR)
-                       perror("accept");
-               return;
-       }
-
-       Client *client = malloc(sizeof(Client));
-       client->fd = fd;
-       pthread_mutex_init(&client->mtx, NULL);
-       client->state = CS_CREATED;
-       client->address = address_string((struct sockaddr_in6 *) &client_address);
-       client->name = client->address;
-       client->server = &server;
-       client->pos = (v3f) {0.0f, 0.0f, 0.0f};
-       pthread_create(&client->net_thread, NULL, &server_reciever_thread, client);
-       client->sent_blocks = list_create(NULL);
-
-       pthread_rwlock_wrlock(&server.clients_rwlck);
-       list_put(&server.clients, client, NULL);
-       pthread_rwlock_unlock(&server.clients_rwlck);
-
-       printf("Connected %s\n", client->address);
-}
-
-static void list_disconnect_client(void *key, __attribute__((unused)) void *value, __attribute__((unused)) void *unused)
-{
-       server_disconnect_client(key, DISCO_NO_REMOVE | DISCO_NO_MESSAGE, "");
-}
-
-void server_start(int fd)
-{
-       server.sockfd = fd;
-       server.map = map_create(NULL);
-       pthread_rwlock_init(&server.clients_rwlck, NULL);
-       server.clients = list_create(NULL);
-       pthread_rwlock_init(&server.players_rwlck, NULL);
-       server.players = list_create(&list_compare_string);
-
-       servermap_init(&server);
-
-       while (! interrupted)
-               server_accept_client();
-
-       printf("Shutting down\n");
-
-       servermap_deinit();
-
-       pthread_rwlock_wrlock(&server.clients_rwlck);
-       list_clear_func(&server.clients, &list_disconnect_client, NULL);
-       pthread_rwlock_unlock(&server.clients_rwlck);
-       pthread_rwlock_wrlock(&server.players_rwlck);
-       list_clear(&server.players);
-       pthread_rwlock_unlock(&server.players_rwlck);
-
-       pthread_rwlock_destroy(&server.clients_rwlck);
-       pthread_rwlock_destroy(&server.players_rwlck);
-
-       shutdown(server.sockfd, SHUT_RDWR);
-       close(server.sockfd);
-
-       map_delete(server.map);
-
-       exit(EXIT_SUCCESS);
-}
-
-int main(int argc, char **argv)
-{
-       program_name = argv[0];
-
-       if (argc < 2)
-               internal_error("missing port");
-
-       struct addrinfo hints = {
-               .ai_family = AF_INET6,
-               .ai_socktype = SOCK_STREAM,
-               .ai_protocol = 0,
-               .ai_flags = AI_NUMERICSERV | AI_PASSIVE,
-       };
-
-       struct addrinfo *info = NULL;
-
-       int gai_state = getaddrinfo(NULL, argv[1], &hints, &info);
-
-       if (gai_state != 0)
-               internal_error(gai_strerror(gai_state));
-
-       int fd = socket(info->ai_family, info->ai_socktype, 0);
-
-       if (fd == -1)
-               syscall_error("socket");
-
-       int flag = 1;
-
-       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1)
-               syscall_error("setsockopt");
-
-       if (bind(fd, info->ai_addr, info->ai_addrlen) == -1)
-               syscall_error("bind");
-
-       if (listen(fd, 3) == -1)
-               syscall_error("listen");
-
-       char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
-       printf("Listening on %s\n", addrstr);
-       free(addrstr);
-
-       freeaddrinfo(info);
-
-       init_signal_handlers();
-       server_start(fd);
-
-       return EXIT_SUCCESS;
-}
diff --git a/src/server.h b/src/server.h
deleted file mode 100644 (file)
index 5d1f3cc..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef _SERVER_H_
-#define _SERVER_H_
-
-#include <pthread.h>
-#include <netinet/in.h>
-#include "clientcommands.h"
-#include "servercommands.h"
-#include "list.h"
-#include "map.h"
-#include "network.h"
-
-typedef struct
-{
-       int sockfd;
-       pthread_rwlock_t clients_rwlck;
-       List clients;
-       pthread_rwlock_t players_rwlck;
-       List players;
-       Map *map;
-} Server;
-
-typedef struct Client
-{
-       int fd;
-       pthread_mutex_t mtx;
-       ClientState state;
-       char *address;
-       char *name;
-       Server *server;
-       pthread_t net_thread;
-       List sent_blocks;
-       v3f pos;
-} Client;
-
-typedef enum
-{
-       DISCO_NO_REMOVE = 0x01,
-       DISCO_NO_SEND = 0x02,
-       DISCO_NO_MESSAGE = 0x04,
-       DISCO_NO_JOIN = 0x08,
-} DiscoFlag;
-
-void server_disconnect_client(Client *client, int flags, const char *detail);
-void server_shutdown();
-
-#endif
diff --git a/src/server/facecache.c b/src/server/facecache.c
new file mode 100644 (file)
index 0000000..c15e878
--- /dev/null
@@ -0,0 +1,90 @@
+#include <stdlib.h>
+#include "server/facecache.h"
+#include "array.h"
+
+static struct
+{
+       Array positions;
+       u32 size;
+       pthread_mutex_t mtx;
+} facecache;
+
+__attribute((constructor)) static void face_cache_init()
+{
+       facecache.size = 0;
+       facecache.positions = array_create(sizeof(v3s32));
+       v3s32 pos = {0, 0, 0};
+       array_append(&facecache.positions, &pos);
+       pthread_mutex_init(&facecache.mtx, NULL);
+}
+
+__attribute((destructor)) void face_cache_deinit()
+{
+       if (facecache.positions.ptr)
+               free(facecache.positions.ptr);
+       pthread_mutex_destroy(&facecache.mtx);
+}
+
+static void face_cache_calculate(s32 size)
+{
+#define ADDPOS(a, b, c, va, vb, vc) \
+       { \
+               v3s32 pos; \
+               *(s32 *) ((char *) &pos + offsetof(v3s32, a)) = va; \
+               *(s32 *) ((char *) &pos + offsetof(v3s32, b)) = vb; \
+               *(s32 *) ((char *) &pos + offsetof(v3s32, c)) = vc; \
+               array_append(&facecache.positions, &pos); \
+       }
+#define SQUARES(a, b, c) \
+       for (s32 va = -size + 1; va < size; va++) { \
+               for (s32 vb = -size + 1; vb < size; vb++) { \
+                       ADDPOS(a, b, c, va, vb,  size) \
+                       ADDPOS(a, b, c, va, vb, -size) \
+               } \
+       }
+       SQUARES(x, z, y)
+       SQUARES(x, y, z)
+       SQUARES(z, y, x)
+#undef SQUARES
+#define EDGES(a, b, c) \
+       for (s32 va = -size + 1; va < size; va++) { \
+               ADDPOS(a, b, c, va,  size,  size) \
+               ADDPOS(a, b, c, va,  size, -size) \
+               ADDPOS(a, b, c, va, -size,  size) \
+               ADDPOS(a, b, c, va, -size, -size) \
+       }
+       EDGES(x, y, z)
+       EDGES(z, x, y)
+       EDGES(y, x, z)
+#undef EDGES
+       ADDPOS(x, y, z,  size,  size,  size)
+       ADDPOS(x, y, z,  size,  size, -size)
+       ADDPOS(x, y, z,  size, -size,  size)
+       ADDPOS(x, y, z,  size, -size, -size)
+       ADDPOS(x, y, z, -size,  size,  size)
+       ADDPOS(x, y, z, -size,  size, -size)
+       ADDPOS(x, y, z, -size, -size,  size)
+       ADDPOS(x, y, z, -size, -size, -size)
+#undef ADDPOS
+}
+
+v3s32 facecache_face(size_t i, v3s32 *base)
+{
+       pthread_mutex_lock(&facecache.mtx);
+       while (facecache.positions.siz <= i)
+               face_cache_calculate(++facecache.size);
+       v3s32 pos = ((v3s32 *) facecache.positions.ptr)[i];
+       pthread_mutex_unlock(&facecache.mtx);
+       if (base) {
+               pos.x += base->x;
+               pos.y += base->y;
+               pos.z += base->z;
+       }
+       return pos;
+}
+
+size_t facecache_count(u32 size)
+{
+       size_t len = 1 + size * 2;
+       return len * len * len;
+}
diff --git a/src/server/facecache.h b/src/server/facecache.h
new file mode 100644 (file)
index 0000000..847b739
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _FACECACHE_H_
+#define _FACECACHE_H_
+
+#include <pthread.h>
+#include "types.h"
+
+v3s32 facecache_face(size_t i, v3s32 *base);
+size_t facecache_count(u32 size);
+
+#endif
diff --git a/src/server/mapdb.c b/src/server/mapdb.c
new file mode 100644 (file)
index 0000000..fc0bf42
--- /dev/null
@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <endian.h>
+#include <stdlib.h>
+#include "server/mapdb.h"
+#include "server/server_map.h"
+
+static void print_error(sqlite3 *db, MapBlock *block, const char *action)
+{
+       printf("Database error with %s block at %d %d %d: %s\n", action, block->pos.x, block->pos.y, block->pos.z, sqlite3_errmsg(db));
+}
+
+sqlite3 *mapdb_open(const char *path)
+{
+       sqlite3 *db;
+       char *err;
+
+       if (sqlite3_open_v2(path, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK) {
+               printf("Failed to open database: %s\n", sqlite3_errmsg(db));
+       } else if (sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS blocks (pos BLOB PRIMARY KEY, data BLOB NOT NULL);", NULL, NULL, &err) != SQLITE_OK) {
+               printf("Failed to initialize database: %s\n", err);
+               sqlite3_free(err);
+       }
+
+       return db;
+}
+
+static sqlite3_stmt *prepare_statement(sqlite3 *db, MapBlock *block, const char *action, const char *sql)
+{
+       sqlite3_stmt *stmt;
+
+       if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
+               print_error(db, block, action);
+               return NULL;
+       }
+
+       size_t psize = sizeof(s32) * 3;
+       s32 *pos = malloc(psize);
+       pos[0] = htobe32(block->pos.x);
+       pos[1] = htobe32(block->pos.y);
+       pos[2] = htobe32(block->pos.z);
+
+       sqlite3_bind_blob(stmt, 1, pos, psize, &free);
+
+       return stmt;
+}
+
+bool mapdb_load_block(sqlite3 *db, MapBlock *block)
+{
+       sqlite3_stmt *stmt;
+
+       if (! (stmt = prepare_statement(db, block, "loading", "SELECT data FROM blocks WHERE pos=?")))
+               return false;
+
+       int rc = sqlite3_step(stmt);
+       bool found = rc == SQLITE_ROW;
+
+       if (found) {
+               const char *data = sqlite3_column_blob(stmt, 0);
+               map_deserialize_block(block, data + sizeof(MapBlockHeader), be32toh(*(MapBlockHeader *) data));
+       } else if (rc != SQLITE_DONE) {
+               print_error(db, block, "loading");
+       }
+
+       sqlite3_finalize(stmt);
+       return found;
+}
+
+void mapdb_save_block(sqlite3 *db, MapBlock *block)
+{
+       sqlite3_stmt *stmt;
+
+       if (! (stmt = prepare_statement(db, block, "saving", "REPLACE INTO blocks (pos, data) VALUES(?1, ?2)")))
+               return;
+
+       MapBlockExtraData *extra = block->extra;
+
+       sqlite3_bind_blob(stmt, 2, extra->data, extra->size, SQLITE_TRANSIENT);
+
+       if (sqlite3_step(stmt) != SQLITE_DONE)
+               print_error(db, block, "saving");
+
+       sqlite3_finalize(stmt);
+}
diff --git a/src/server/mapdb.h b/src/server/mapdb.h
new file mode 100644 (file)
index 0000000..41187ba
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _MAPDB_H_
+#define _MAPDB_H_
+
+#include <sqlite3.h>
+#include <stdbool.h>
+#include "map.h"
+
+sqlite3 *mapdb_open(const char *path);
+bool mapdb_load_block(sqlite3 *db, MapBlock *block);
+void mapdb_save_block(sqlite3 *db, MapBlock *block);
+
+#endif
diff --git a/src/server/mapgen.c b/src/server/mapgen.c
new file mode 100644 (file)
index 0000000..c214555
--- /dev/null
@@ -0,0 +1,49 @@
+#include <math.h>
+#include "server/mapgen.h"
+#include "server/perlin.h"
+
+void mapgen_generate_block(MapBlock *block)
+{
+       for (u8 x = 0; x < 16; x++) {
+               u32 ux = x + block->pos.x * 16 + ((u32) 1 << 31);
+               for (u8 z = 0; z < 16; z++) {
+                       u32 uz = z + block->pos.z * 16 + ((u32) 1 << 31);
+                       s32 height = smooth2d(ux / 32.0, uz / 32.0, 0, 0) * 16.0 + 128.0;
+                       bool is_mountain = false;
+
+                       double mountain_factor = (smooth2d(ux / 1000.0, uz / 1000.0, 0, 1) - 0.3) * 5.0;
+
+                       if (mountain_factor > 0.0) {
+                               height = pow(height * pow(((smooth2d(ux / 50.0, uz / 50.0, 2, 2) + 1.0) * 256.0 + 128.0), mountain_factor), 1.0 / (mountain_factor + 1.0));
+                               is_mountain = true;
+                       }
+
+                       for (u8 y = 0; y < 16; y++) {
+                               s32 ay = block->pos.y * 16 + y;
+                               s32 diff = ay - height;
+
+                               Node node = NODE_AIR;
+
+                               if (diff < -5)
+                                       node = NODE_STONE;
+                               else if (diff < -1)
+                                       node = is_mountain ? NODE_STONE : NODE_DIRT;
+                               else if (diff < 0)
+                                       node = is_mountain ? NODE_STONE : NODE_GRASS;
+                               else if (diff < 1)
+                                       node = (is_mountain && ay > 256) ? NODE_SNOW : NODE_AIR;
+
+                               block->data[x][y][z] = map_node_create(node);
+                               block->metadata[x][y][z] = list_create(&list_compare_string);
+
+                               if (node == NODE_GRASS) {
+                                       double min, max;
+                                       min = 0.15;
+                                       max = 0.45;
+                                       block->data[x][y][z].state.biome.x = (smooth2d(ux / 128.0, uz / 128.0, 0, 3) * 0.5 + 0.5) * (max - min) + min;
+                                       block->data[x][y][z].state.biome.y = 1.0;
+                               }
+                       }
+               }
+       }
+}
diff --git a/src/server/mapgen.h b/src/server/mapgen.h
new file mode 100644 (file)
index 0000000..8f1b20d
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _MAPGEN_H_
+#define _MAPGEN_H_
+
+#include "map.h"
+
+void mapgen_generate_block(MapBlock *block);
+
+#endif
diff --git a/src/server/perlin.c b/src/server/perlin.c
new file mode 100644 (file)
index 0000000..c6d415c
--- /dev/null
@@ -0,0 +1,2 @@
+#include <perlin/perlin.c>
+
diff --git a/src/server/perlin.h b/src/server/perlin.h
new file mode 100644 (file)
index 0000000..b328f61
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _PERLIN_H_
+#define _PERLIN_H_
+
+#include <perlin/perlin.h>
+
+#endif
diff --git a/src/server/server.c b/src/server/server.c
new file mode 100644 (file)
index 0000000..5d4ebbd
--- /dev/null
@@ -0,0 +1,180 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include "server/server.h"
+#include "server/server_map.h"
+#include "signal.h"
+#include "util.h"
+
+Server server;
+
+void server_disconnect_client(Client *client, int flags, const char *detail)
+{
+       client->state = CS_DISCONNECTED;
+
+       if (! (flags & DISCO_NO_REMOVE)) {
+               if (client->name) {
+                       pthread_rwlock_wrlock(&server.players_rwlck);
+                       list_delete(&server.players, client->name);
+                       pthread_rwlock_unlock(&server.players_rwlck);
+               }
+               pthread_rwlock_wrlock(&server.clients_rwlck);
+               list_delete(&server.clients, client);
+               pthread_rwlock_unlock(&server.clients_rwlck);
+       }
+
+       if (! (flags & DISCO_NO_MESSAGE))
+               printf("Disconnected %s %s%s%s\n", client->name, INBRACES(detail));
+
+       if (! (flags & DISCO_NO_SEND))
+               send_command(client, CC_DISCONNECT);
+
+       pthread_mutex_lock(&client->mtx);
+       close(client->fd);
+       pthread_mutex_unlock(&client->mtx);
+
+       if (! (flags & DISCO_NO_JOIN))
+               pthread_join(client->net_thread, NULL);
+
+       if (client->name != client->address)
+               free(client->name);
+       free(client->address);
+
+       pthread_mutex_destroy(&client->mtx);
+       free(client);
+}
+
+#include "network.c"
+
+static void *server_reciever_thread(void *cli)
+{
+       Client *client = cli;
+
+       if (! handle_packets(client))
+               server_disconnect_client(client, DISCO_NO_SEND | DISCO_NO_JOIN, "network error");
+
+       return NULL;
+}
+
+static void server_accept_client()
+{
+       struct sockaddr_storage client_address = {0};
+       socklen_t client_addrlen = sizeof(client_address);
+
+       int fd = accept(server.sockfd, (struct sockaddr *) &client_address, &client_addrlen);
+
+       if (fd == -1) {
+               if (errno != EINTR)
+                       perror("accept");
+               return;
+       }
+
+       Client *client = malloc(sizeof(Client));
+       client->fd = fd;
+       pthread_mutex_init(&client->mtx, NULL);
+       client->state = CS_CREATED;
+       client->address = address_string((struct sockaddr_in6 *) &client_address);
+       client->name = client->address;
+       client->server = &server;
+       client->pos = (v3f) {0.0f, 0.0f, 0.0f};
+       pthread_create(&client->net_thread, NULL, &server_reciever_thread, client);
+       client->sent_blocks = list_create(NULL);
+
+       pthread_rwlock_wrlock(&server.clients_rwlck);
+       list_put(&server.clients, client, NULL);
+       pthread_rwlock_unlock(&server.clients_rwlck);
+
+       printf("Connected %s\n", client->address);
+}
+
+static void list_disconnect_client(void *key, __attribute__((unused)) void *value, __attribute__((unused)) void *unused)
+{
+       server_disconnect_client(key, DISCO_NO_REMOVE | DISCO_NO_MESSAGE, "");
+}
+
+void server_start(int fd)
+{
+       server.sockfd = fd;
+       server.map = map_create(NULL);
+       pthread_rwlock_init(&server.clients_rwlck, NULL);
+       server.clients = list_create(NULL);
+       pthread_rwlock_init(&server.players_rwlck, NULL);
+       server.players = list_create(&list_compare_string);
+
+       server_map_init(&server);
+
+       while (! interrupted)
+               server_accept_client();
+
+       printf("Shutting down\n");
+
+       server_map_deinit();
+
+       pthread_rwlock_wrlock(&server.clients_rwlck);
+       list_clear_func(&server.clients, &list_disconnect_client, NULL);
+       pthread_rwlock_unlock(&server.clients_rwlck);
+       pthread_rwlock_wrlock(&server.players_rwlck);
+       list_clear(&server.players);
+       pthread_rwlock_unlock(&server.players_rwlck);
+
+       pthread_rwlock_destroy(&server.clients_rwlck);
+       pthread_rwlock_destroy(&server.players_rwlck);
+
+       shutdown(server.sockfd, SHUT_RDWR);
+       close(server.sockfd);
+
+       map_delete(server.map);
+
+       exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char **argv)
+{
+       program_name = argv[0];
+
+       if (argc < 2)
+               internal_error("missing port");
+
+       struct addrinfo hints = {
+               .ai_family = AF_INET6,
+               .ai_socktype = SOCK_STREAM,
+               .ai_protocol = 0,
+               .ai_flags = AI_NUMERICSERV | AI_PASSIVE,
+       };
+
+       struct addrinfo *info = NULL;
+
+       int gai_state = getaddrinfo(NULL, argv[1], &hints, &info);
+
+       if (gai_state != 0)
+               internal_error(gai_strerror(gai_state));
+
+       int fd = socket(info->ai_family, info->ai_socktype, 0);
+
+       if (fd == -1)
+               syscall_error("socket");
+
+       int flag = 1;
+
+       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1)
+               syscall_error("setsockopt");
+
+       if (bind(fd, info->ai_addr, info->ai_addrlen) == -1)
+               syscall_error("bind");
+
+       if (listen(fd, 3) == -1)
+               syscall_error("listen");
+
+       char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
+       printf("Listening on %s\n", addrstr);
+       free(addrstr);
+
+       freeaddrinfo(info);
+
+       signal_handlers_init();
+       server_start(fd);
+
+       return EXIT_SUCCESS;
+}
diff --git a/src/server/server.h b/src/server/server.h
new file mode 100644 (file)
index 0000000..89b91cc
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _SERVER_H_
+#define _SERVER_H_
+
+#include <pthread.h>
+#include <netinet/in.h>
+#include "client/client_commands.h"
+#include "server/server_commands.h"
+#include "list.h"
+#include "map.h"
+#include "network.h"
+
+typedef struct
+{
+       int sockfd;
+       pthread_rwlock_t clients_rwlck;
+       List clients;
+       pthread_rwlock_t players_rwlck;
+       List players;
+       Map *map;
+} Server;
+
+typedef struct Client
+{
+       int fd;
+       pthread_mutex_t mtx;
+       ClientState state;
+       char *address;
+       char *name;
+       Server *server;
+       pthread_t net_thread;
+       List sent_blocks;
+       v3f pos;
+} Client;
+
+typedef enum
+{
+       DISCO_NO_REMOVE = 0x01,
+       DISCO_NO_SEND = 0x02,
+       DISCO_NO_MESSAGE = 0x04,
+       DISCO_NO_JOIN = 0x08,
+} DiscoFlag;
+
+void server_disconnect_client(Client *client, int flags, const char *detail);
+void server_shutdown();
+
+#endif
diff --git a/src/server/server_commands.c b/src/server/server_commands.c
new file mode 100644 (file)
index 0000000..f0dafa9
--- /dev/null
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "server/server.h"
+#include "server/server_map.h"
+#include "util.h"
+
+static bool disconnect_handler(Client *client, bool good)
+{
+       if (good)
+               server_disconnect_client(client, DISCO_NO_SEND, NULL);
+       return true;
+}
+
+static bool auth_handler(Client *client, bool good)
+{
+       char *name = read_string(client->fd, PLAYER_NAME_MAX);
+
+       if (! name)
+               return false;
+
+       if (! good) {
+               free(name);
+               return true;
+       }
+
+       pthread_rwlock_wrlock(&client->server->players_rwlck);
+       u8 success = list_put(&client->server->players, name, client);
+
+       if (success) {
+               client->name = name;
+               client->state = CS_ACTIVE;
+       } else {
+               free(name);
+       }
+
+       pthread_mutex_lock(&client->mtx);
+       bool ret = write_u32(client->fd, CC_AUTH) && write_u8(client->fd, success);
+       pthread_mutex_unlock(&client->mtx);
+
+       pthread_rwlock_unlock(&client->server->players_rwlck);
+
+       printf("Authentication %s: %s -> %s\n", success ? "success" : "failure", client->address, name);
+
+       return ret;
+}
+
+static bool setnode_handler(Client *client, bool good)
+{
+       v3s32 pos;
+
+       if (! read_v3s32(client->fd, &pos))
+               return false;
+
+       MapNode node;
+
+       if (! map_deserialize_node(client->fd, &node))
+               return false;
+
+       if (good)
+               map_set_node(client->server->map, pos, node);
+
+       return true;
+}
+
+static bool pos_handler(Client *client, bool good)
+{
+       v3f pos;
+
+       if (! read_v3f32(client->fd, &pos))
+               return false;
+
+       if (good)
+               client->pos = pos;
+
+       return true;
+}
+
+CommandHandler command_handlers[SERVER_COMMAND_COUNT] = {
+       {0},
+       {&disconnect_handler, "DISCONNECT", CS_CREATED | CS_ACTIVE},
+       {&auth_handler, "AUTH", CS_CREATED},
+       {&setnode_handler, "SETNODE", CS_ACTIVE},
+       {&pos_handler, "POS", CS_ACTIVE},
+};
diff --git a/src/server/server_commands.h b/src/server/server_commands.h
new file mode 100644 (file)
index 0000000..ba78278
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _SERVER_COMMANDS_H_
+#define _SCOMMANDS_H_
+
+typedef enum
+{
+       SERVER_COMMAND_NULL,
+       SC_DISCONNECT,
+       SC_AUTH,
+       SC_SETNODE,
+       SC_POS,
+       SERVER_COMMAND_COUNT,
+} ServerCommand;
+
+#ifdef _CLIENT_H_
+typedef ServerCommand RemoteCommand;
+#endif
+
+#ifdef _SERVER_H_
+typedef ServerCommand HostCommand;
+#define HOST_COMMAND_COUNT SERVER_COMMAND_COUNT
+#endif
+
+#endif
diff --git a/src/server/server_map.c b/src/server/server_map.c
new file mode 100644 (file)
index 0000000..ed6fde8
--- /dev/null
@@ -0,0 +1,174 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "server/facecache.h"
+#include "server/mapdb.h"
+#include "server/mapgen.h"
+#include "server/server_map.h"
+#include "map.h"
+
+static struct {
+       Server *server;
+       size_t max_blocks;
+       pthread_t thread;
+       sqlite3 *db;
+       bool cancel;
+} server_map;
+
+static void initialize_block(MapBlock *block)
+{
+       if (! mapdb_load_block(server_map.db, block))
+               mapgen_generate_block(block);
+       block->state = MBS_MODIFIED;
+}
+
+static void reset_client_block(void *key, __attribute__((unused)) void *value, void *block)
+{
+       Client *client = list_get(&server_map.server->players, key);
+       if (client)
+               list_delete(&client->sent_blocks, block);
+       free(key);
+}
+
+static void list_delete_extra_data(void *key, __attribute__((unused)) void *value, __attribute__((unused)) void *unused)
+{
+       free(key);
+}
+
+static void free_extra_data(void *ext)
+{
+       MapBlockExtraData *extra = ext;
+
+       if (extra) {
+               list_clear_func(&extra->clients, &list_delete_extra_data, NULL);
+               free(extra->data);
+               free(extra);
+       }
+}
+
+static void reset_block(MapBlock *block)
+{
+       MapBlockExtraData *extra = block->extra;
+
+       if (extra) {
+               free(extra->data);
+       } else {
+               extra = malloc(sizeof(MapBlockExtraData));
+               extra->clients = list_create(&list_compare_string);
+       }
+
+       map_serialize_block(block, &extra->data, &extra->size);
+
+       block->extra = extra;
+       block->free_extra = &free_extra_data;
+
+       mapdb_save_block(server_map.db, block);
+
+       list_clear_func(&extra->clients, &reset_client_block, block);
+       list_clear(&extra->clients);
+
+       block->state = MBS_READY;
+}
+
+static void send_block(Client *client, MapBlock *block)
+{
+       MapBlockExtraData *extra = block->extra;
+
+       list_put(&client->sent_blocks, block, block);
+       list_put(&extra->clients, strdup(client->name), NULL);
+
+       pthread_mutex_lock(&client->mtx);
+       if (client->state == CS_ACTIVE)
+               (void) (write_u32(client->fd, CC_BLOCK) && write_v3s32(client->fd, block->pos) && write(client->fd, extra->data, extra->size) != -1);
+       pthread_mutex_unlock(&client->mtx);
+}
+
+static void reset_modified_blocks(Client *client)
+{
+       for (ListPair **pairptr = &client->sent_blocks.first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
+
+               MapBlock *block = (*pairptr)->key;
+
+               pthread_mutex_lock(&block->mtx);
+               if (block->state == MBS_MODIFIED) {
+                       reset_block(block);
+
+                       ListPair *next = (*pairptr)->next;
+                       free(*pairptr);
+                       *pairptr = next;
+               }
+               pthread_mutex_unlock(&block->mtx);
+       }
+}
+
+static void send_blocks(Client *client)
+{
+       v3s32 pos = map_node_to_block_pos((v3s32) {client->pos.x, client->pos.y, client->pos.z}, NULL);
+
+       for (size_t i = 0; i < server_map.max_blocks; i++) {
+               MapBlock *block = map_get_block(client->server->map, facecache_face(i, &pos), true);
+
+               pthread_mutex_lock(&block->mtx);
+               switch (block->state) {
+                       case MBS_CREATED:
+
+                               initialize_block(block);
+
+                       __attribute__ ((fallthrough)); case MBS_MODIFIED:
+
+                               reset_block(block);
+
+                               send:
+                               send_block(client, block);
+
+                               pthread_mutex_unlock(&block->mtx);
+                               return;
+
+                       case MBS_READY:
+
+                               if (! list_get(&client->sent_blocks, block))
+                                       goto send;
+                               else
+                                       break;
+
+                       default:
+
+                               break;
+               }
+               pthread_mutex_unlock(&block->mtx);
+       }
+}
+
+static void map_step()
+{
+       pthread_rwlock_rdlock(&server_map.server->players_rwlck);
+       ITERATE_LIST(&server_map.server->players, pair) reset_modified_blocks(pair->value);
+       ITERATE_LIST(&server_map.server->players, pair) send_blocks(pair->value);
+       pthread_rwlock_unlock(&server_map.server->players_rwlck);
+}
+
+static void *map_thread(__attribute__((unused)) void *unused)
+{
+       server_map.db = mapdb_open("map.sqlite");
+
+       while (! server_map.cancel)
+               map_step();
+
+       return NULL;
+}
+
+void server_map_init(Server *server)
+{
+       server_map.server = server;
+       server_map.max_blocks = facecache_count(10);
+
+       pthread_create(&server_map.thread, NULL, &map_thread, NULL);
+}
+
+void server_map_deinit()
+{
+       server_map.cancel = true;
+       pthread_join(server_map.thread, NULL);
+       sqlite3_close(server_map.db);
+}
diff --git a/src/server/server_map.h b/src/server/server_map.h
new file mode 100644 (file)
index 0000000..b98e866
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _SERVER_MAP_H_
+#define _SERVER_MAP_H_
+
+#include "server/server.h"
+
+typedef struct
+{
+       List clients;
+       char *data;
+       size_t size;
+} MapBlockExtraData;
+
+void server_map_init(Server *server);
+void server_map_deinit();
+
+#endif
diff --git a/src/servercommands.c b/src/servercommands.c
deleted file mode 100644 (file)
index c5d7f01..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include "server.h"
-#include "servermap.h"
-#include "util.h"
-
-static bool disconnect_handler(Client *client, bool good)
-{
-       if (good)
-               server_disconnect_client(client, DISCO_NO_SEND, NULL);
-       return true;
-}
-
-static bool auth_handler(Client *client, bool good)
-{
-       char *name = read_string(client->fd, NAME_MAX);
-
-       if (! name)
-               return false;
-
-       if (! good) {
-               free(name);
-               return true;
-       }
-
-       pthread_rwlock_wrlock(&client->server->players_rwlck);
-       u8 success = list_put(&client->server->players, name, client);
-
-       if (success) {
-               client->name = name;
-               client->state = CS_ACTIVE;
-       } else {
-               free(name);
-       }
-
-       pthread_mutex_lock(&client->mtx);
-       bool ret = write_u32(client->fd, CC_AUTH) && write_u8(client->fd, success);
-       pthread_mutex_unlock(&client->mtx);
-
-       pthread_rwlock_unlock(&client->server->players_rwlck);
-
-       printf("Authentication %s: %s -> %s\n", success ? "success" : "failure", client->address, name);
-
-       return ret;
-}
-
-static bool setnode_handler(Client *client, bool good)
-{
-       v3s32 pos;
-
-       if (! read_v3s32(client->fd, &pos))
-               return false;
-
-       MapNode node;
-
-       if (! map_deserialize_node(client->fd, &node))
-               return false;
-
-       if (good)
-               map_set_node(client->server->map, pos, node);
-
-       return true;
-}
-
-static bool pos_handler(Client *client, bool good)
-{
-       v3f pos;
-
-       if (! read_v3f32(client->fd, &pos))
-               return false;
-
-       if (good)
-               client->pos = pos;
-
-       return true;
-}
-
-CommandHandler command_handlers[SERVER_COMMAND_COUNT] = {
-       {0},
-       {&disconnect_handler, "DISCONNECT", CS_CREATED | CS_ACTIVE},
-       {&auth_handler, "AUTH", CS_CREATED},
-       {&setnode_handler, "SETNODE", CS_ACTIVE},
-       {&pos_handler, "POS", CS_ACTIVE},
-};
diff --git a/src/servercommands.h b/src/servercommands.h
deleted file mode 100644 (file)
index e3c2f9f..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _SERVER_COMMAND_H_
-#define _SERVER_COMMAND_H_
-
-typedef enum
-{
-       SERVER_COMMAND_NULL,
-       SC_DISCONNECT,
-       SC_AUTH,
-       SC_SETNODE,
-       SC_POS,
-       SERVER_COMMAND_COUNT,
-} ServerCommand;
-
-#ifdef _CLIENT_H_
-typedef ServerCommand RemoteCommand;
-#endif
-
-#ifdef _SERVER_H_
-typedef ServerCommand HostCommand;
-#define HOST_COMMAND_COUNT SERVER_COMMAND_COUNT
-#endif
-
-#endif
diff --git a/src/servermap.c b/src/servermap.c
deleted file mode 100644 (file)
index 9b495aa..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
-#include "facecache.h"
-#include "map.h"
-#include "mapdb.h"
-#include "mapgen.h"
-#include "servermap.h"
-
-static struct {
-       size_t max_blocks;
-       pthread_t thread;
-       sqlite3 *db;
-       bool cancel;
-} servermap;
-
-static Server *server = NULL;
-
-static void initialize_block(MapBlock *block)
-{
-       if (! load_block(servermap.db, block))
-               mapgen_generate_block(block);
-       block->state = MBS_MODIFIED;
-}
-
-static void reset_client_block(void *key, __attribute__((unused)) void *value, void *block)
-{
-       Client *client = list_get(&server->players, key);
-       if (client)
-               list_delete(&client->sent_blocks, block);
-       free(key);
-}
-
-static void list_delete_extra_data(void *key, __attribute__((unused)) void *value, __attribute__((unused)) void *unused)
-{
-       free(key);
-}
-
-static void free_extra_data(void *ext)
-{
-       MapBlockExtraData *extra = ext;
-
-       if (extra) {
-               list_clear_func(&extra->clients, &list_delete_extra_data, NULL);
-               free(extra->data);
-               free(extra);
-       }
-}
-
-static void reset_block(MapBlock *block)
-{
-       MapBlockExtraData *extra = block->extra;
-
-       if (extra) {
-               free(extra->data);
-       } else {
-               extra = malloc(sizeof(MapBlockExtraData));
-               extra->clients = list_create(&list_compare_string);
-       }
-
-       map_serialize_block(block, &extra->data, &extra->size);
-
-       block->extra = extra;
-       block->free_extra = &free_extra_data;
-
-       save_block(servermap.db, block);
-
-       list_clear_func(&extra->clients, &reset_client_block, block);
-       list_clear(&extra->clients);
-
-       block->state = MBS_READY;
-}
-
-static void send_block(Client *client, MapBlock *block)
-{
-       MapBlockExtraData *extra = block->extra;
-
-       list_put(&client->sent_blocks, block, block);
-       list_put(&extra->clients, strdup(client->name), NULL);
-
-       pthread_mutex_lock(&client->mtx);
-       if (client->state == CS_ACTIVE)
-               (void) (write_u32(client->fd, CC_BLOCK) && write_v3s32(client->fd, block->pos) && write(client->fd, extra->data, extra->size) != -1);
-       pthread_mutex_unlock(&client->mtx);
-}
-
-static void reset_modified_blocks(Client *client)
-{
-       for (ListPair **pairptr = &client->sent_blocks.first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
-
-               MapBlock *block = (*pairptr)->key;
-
-               pthread_mutex_lock(&block->mtx);
-               if (block->state == MBS_MODIFIED) {
-                       reset_block(block);
-
-                       ListPair *next = (*pairptr)->next;
-                       free(*pairptr);
-                       *pairptr = next;
-               }
-               pthread_mutex_unlock(&block->mtx);
-       }
-}
-
-static void send_blocks(Client *client)
-{
-       v3s32 pos = map_node_to_block_pos((v3s32) {client->pos.x, client->pos.y, client->pos.z}, NULL);
-
-       for (size_t i = 0; i < servermap.max_blocks; i++) {
-               MapBlock *block = map_get_block(client->server->map, get_face(i, &pos), true);
-
-               pthread_mutex_lock(&block->mtx);
-               switch (block->state) {
-                       case MBS_CREATED:
-
-                               initialize_block(block);
-
-                       __attribute__ ((fallthrough)); case MBS_MODIFIED:
-
-                               reset_block(block);
-
-                               send:
-                               send_block(client, block);
-
-                               pthread_mutex_unlock(&block->mtx);
-                               return;
-
-                       case MBS_READY:
-
-                               if (! list_get(&client->sent_blocks, block))
-                                       goto send;
-                               else
-                                       break;
-
-                       default:
-
-                               break;
-               }
-               pthread_mutex_unlock(&block->mtx);
-       }
-}
-
-static void map_step()
-{
-       pthread_rwlock_rdlock(&server->players_rwlck);
-       ITERATE_LIST(&server->players, pair) reset_modified_blocks(pair->value);
-       ITERATE_LIST(&server->players, pair) send_blocks(pair->value);
-       pthread_rwlock_unlock(&server->players_rwlck);
-}
-
-static void *map_thread(__attribute__((unused)) void *unused)
-{
-       servermap.db = open_mapdb("map.sqlite");
-
-       while (! servermap.cancel)
-               map_step();
-
-       return NULL;
-}
-
-void servermap_init(Server *srv)
-{
-       server = srv;
-       servermap.max_blocks = get_face_count(10);
-
-       pthread_create(&servermap.thread, NULL, &map_thread, NULL);
-}
-
-void servermap_deinit()
-{
-       servermap.cancel = true;
-       pthread_join(servermap.thread, NULL);
-       sqlite3_close(servermap.db);
-}
diff --git a/src/servermap.h b/src/servermap.h
deleted file mode 100644 (file)
index a519d2f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _SERVERMAP_H_
-#define _SERVERMAP_H_
-
-#include "server.h"
-
-typedef struct
-{
-       List clients;
-       char *data;
-       size_t size;
-} MapBlockExtraData;
-
-void servermap_init(Server *srv);
-void servermap_deinit();
-
-#endif
diff --git a/src/shaders.c b/src/shaders.c
deleted file mode 100644 (file)
index d0981a6..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "shaders.h"
-
-static GLuint compile_and_attach_shader(GLenum type, const char *path, const char *name, GLuint program)
-{
-       char full_path[strlen(path) + 1 + strlen(name) + 1 + 4 + 1];
-       sprintf(full_path, "%s/%s.glsl", path, name);
-
-       FILE *file = fopen(full_path, "r");
-       if (! file) {
-               perror("fopen");
-               return 0;
-       }
-
-       if (fseek(file, 0, SEEK_END) == -1) {
-               perror("fseek");
-               fclose(file);
-               return 0;
-       }
-
-       long size = ftell(file);
-
-       if (size == 1) {
-               perror("ftell");
-               fclose(file);
-               return 0;
-       }
-
-       if (fseek(file, 0, SEEK_SET) == -1) {
-               perror("fseek");
-               fclose(file);
-               return 0;
-       }
-
-       char code[size];
-
-       if (fread(code, 1, size, file) != (size_t) size) {
-               perror("fread");
-               fclose(file);
-               return 0;
-       }
-
-       fclose(file);
-
-       GLuint id = glCreateShader(type);
-
-       char const *codeptr = code;
-       const int isize = (int) size;
-       glShaderSource(id, 1, &codeptr, &isize);
-
-       glCompileShader(id);
-
-       GLint success;
-       glGetShaderiv(id, GL_COMPILE_STATUS, &success);
-       if (! success) {
-               char errbuf[BUFSIZ];
-               glGetShaderInfoLog(id, BUFSIZ, NULL, errbuf);
-               fprintf(stderr, "Failed to compile %s shader: %s\n", name, errbuf);
-               glDeleteShader(id);
-               return 0;
-       }
-
-       glAttachShader(program, id);
-
-       return id;
-}
-
-
-ShaderProgram *create_shader_program(const char *path)
-{
-       GLuint id = glCreateProgram();
-
-       GLuint vert, frag;
-
-       if (! (vert = compile_and_attach_shader(GL_VERTEX_SHADER, path, "vertex", id))) {
-               glDeleteProgram(id);
-               return NULL;
-       }
-
-       if (! (frag = compile_and_attach_shader(GL_FRAGMENT_SHADER, path, "fragment", id))) {
-               glDeleteShader(vert);
-               glDeleteProgram(id);
-               return NULL;
-       }
-
-       glLinkProgram(id);
-       glDeleteShader(vert);
-       glDeleteShader(frag);
-
-       GLint success;
-       glGetProgramiv(id, GL_LINK_STATUS, &success);
-       if (! success) {
-               char errbuf[BUFSIZ];
-               glGetProgramInfoLog(id, BUFSIZ, NULL, errbuf);
-               fprintf(stderr, "Failed to link shader program: %s\n", errbuf);
-               glDeleteProgram(id);
-               return NULL;
-       }
-
-       ShaderProgram *prog = malloc(sizeof(ShaderProgram));
-       prog->id = id;
-       prog->loc_model = glGetUniformLocation(id, "model");
-       prog->loc_view = glGetUniformLocation(id, "view");
-       prog->loc_projection = glGetUniformLocation(id, "projection");
-
-       return prog;
-}
-
-void delete_shader_program(ShaderProgram *prog)
-{
-       glDeleteProgram(prog->id);
-       free(prog);
-}
-
diff --git a/src/shaders.h b/src/shaders.h
deleted file mode 100644 (file)
index 3bba72c..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _SHADERS_H_
-#define _SHADERS_H_
-
-#include <GL/glew.h>
-#include <GL/gl.h>
-
-typedef struct
-{
-       GLuint id;
-       GLint loc_model;
-       GLint loc_view;
-       GLint loc_projection;
-} ShaderProgram;
-
-ShaderProgram *create_shader_program(const char *path);
-void delete_shader_program(ShaderProgram *prog);
-
-#endif
index d9a8c846922bf5be589034df79fa0f62a1a4f212..ca2a29e0dca94c2d54ad42a7f738a6e99aa181f8 100644 (file)
@@ -18,7 +18,7 @@ static void silent_handler(__attribute__((unused)) int sig)
 static struct sigaction sigact_interrupt = {0};
 static struct sigaction sigact_silent = {0};
 
-void init_signal_handlers()
+void signal_handlers_init()
 {
        sigact_interrupt.sa_handler = &interrupt_handler;
        sigaction(SIGINT, &sigact_interrupt, NULL);
index ec3234bc101da764c614ceeba3eaa9cdb52d601c..16c5966c5181411c0ee62280dfe0aa15d5adbd74 100644 (file)
@@ -4,6 +4,6 @@
 #include <stdbool.h>
 
 extern bool interrupted;
-void init_signal_handlers();
+void signal_handlers_init();
 
 #endif
diff --git a/src/texture.c b/src/texture.c
deleted file mode 100644 (file)
index 239c1a4..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#define STB_IMAGE_IMPLEMENTATION
-#include <stb/stb_image.h>
-#include <stdbool.h>
-#include "list.h"
-#include "texture.h"
-
-static List textures;
-
-__attribute((constructor(101))) static void init_textures()
-{
-       stbi_set_flip_vertically_on_load(true);
-
-       textures = list_create(&list_compare_string);
-}
-
-static void list_delete_texture(__attribute__((unused)) void *key, void *value, __attribute__((unused)) void *unused)
-{
-       Texture *texture = value;
-       glDeleteTextures(1, &texture->id);
-       free(texture);
-}
-
-__attribute((destructor)) static void delete_textures()
-{
-       list_clear_func(&textures, &list_delete_texture, NULL);
-}
-
-static void *create_texture(void *key)
-{
-       Texture *texture = malloc(sizeof(Texture));
-       int channels;
-
-       unsigned char *data = stbi_load(key, &texture->width, &texture->height, &channels, 0);
-       if (! data) {
-               printf("Failed to load texture %s\n", (char *) key);
-               return 0;
-       }
-
-       glGenTextures(1, &texture->id);
-
-       glBindTexture(GL_TEXTURE_2D, texture->id);
-
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
-       glGenerateMipmap(GL_TEXTURE_2D);
-
-       stbi_image_free(data);
-
-       glBindTexture(GL_TEXTURE_2D, 0);
-
-       return texture;
-}
-
-Texture *get_texture(char *path)
-{
-       return list_get_cached(&textures, path, &create_texture);
-}
diff --git a/src/texture.h b/src/texture.h
deleted file mode 100644 (file)
index cface04..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _TEXTURE_H_
-#define _TEXTURE_H_
-
-#include <GL/glew.h>
-#include <GL/gl.h>
-
-typedef struct
-{
-       GLuint id;
-       int width, height;
-} Texture;
-
-Texture *get_texture(char *path);
-
-#endif