[submodule "deps/perlin"]
path = deps/perlin
url = https://github.com/czinn/perlin
+[submodule "deps/stb"]
+ path = deps/stb
+ url = https://github.com/nothings/stb
--- /dev/null
+Subproject commit c9064e317699d2e495f36ba4f9ac037e88ee371a
#version 330 core
-in vec3 fragmentColor;
+in vec2 fragmentTextureCoords;
out vec4 outColor;
+uniform sampler2D texture0;
+
void main()
{
- outColor = vec4(fragmentColor, 0.1);
+ outColor = texture(texture0, fragmentTextureCoords);
}
#version 330 core
layout(location = 0) in vec3 vertexPosition;
-layout(location = 1) in vec3 vertexColor;
+layout(location = 1) in vec2 vertexTextureCoords;
-out vec3 fragmentColor;
+out vec2 fragmentTextureCoords;
uniform mat4 model;
uniform mat4 view;
void main()
{
gl_Position = projection * view * model * vec4(vertexPosition, 1.0);
- fragmentColor = vertexColor;
+ fragmentTextureCoords = vertexTextureCoords;
}
COMMON = array.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) client.o clientcommands.o clientmap.o mesh.o scene.o shaders.o blockmesh.o
+CLIENT = $(COMMON) client.o clientcommands.o clientmap.o clientnode.o mesh.o scene.o shaders.o blockmesh.o texture.o
LIBRARIES = -lpthread -lm -lz
FLAGS = -g -fmax-errors=4
memcpy((char *) array->ptr + oldsiz * array->membsiz, elem, array->membsiz);
}
+void array_copy(Array *array, void **ptr, size_t *count)
+{
+ *count = array->siz;
+ size_t size = array->siz * array->membsiz;
+ *ptr = malloc(size);
+ memcpy(*ptr, array->ptr, size);
+}
+
ArraySearchResult array_search(Array *array, void *search)
{
assert(array->cmp);
Array array_create(size_t membsiz);
void array_insert(Array *array, void *elem, size_t idx);
void array_append(Array *array, void *elem);
+void array_copy(Array *array, void **ptr, size_t *count);
ArraySearchResult array_search(Array *array, void *search);
#endif
#include "blockmesh.h"
+#include "clientnode.h"
-static v3f vpos[6][6] = {
+Vertex cube_vertices[6][6] = {
{
- {-0.5f, -0.5f, -0.5f},
- {+0.5f, -0.5f, -0.5f},
- {+0.5f, +0.5f, -0.5f},
- {+0.5f, +0.5f, -0.5f},
- {-0.5f, +0.5f, -0.5f},
- {-0.5f, -0.5f, -0.5f},
+ {-0.5, -0.5, -0.5, +0.0, +0.0},
+ {+0.5, -0.5, -0.5, +1.0, +0.0},
+ {+0.5, +0.5, -0.5, +1.0, +1.0},
+ {+0.5, +0.5, -0.5, +1.0, +1.0},
+ {-0.5, +0.5, -0.5, +0.0, +1.0},
+ {-0.5, -0.5, -0.5, +0.0, +0.0},
},
{
- {-0.5f, -0.5f, +0.5f},
- {+0.5f, +0.5f, +0.5f},
- {+0.5f, -0.5f, +0.5f},
- {+0.5f, +0.5f, +0.5f},
- {-0.5f, -0.5f, +0.5f},
- {-0.5f, +0.5f, +0.5f},
+ {-0.5, -0.5, +0.5, +0.0, +0.0},
+ {+0.5, +0.5, +0.5, +1.0, +1.0},
+ {+0.5, -0.5, +0.5, +1.0, +0.0},
+ {+0.5, +0.5, +0.5, +1.0, +1.0},
+ {-0.5, -0.5, +0.5, +0.0, +0.0},
+ {-0.5, +0.5, +0.5, +0.0, +1.0},
},
{
- {-0.5f, +0.5f, +0.5f},
- {-0.5f, -0.5f, -0.5f},
- {-0.5f, +0.5f, -0.5f},
- {-0.5f, -0.5f, -0.5f},
- {-0.5f, +0.5f, +0.5f},
- {-0.5f, -0.5f, +0.5f},
+ {-0.5, +0.5, +0.5, +1.0, +1.0},
+ {-0.5, -0.5, -0.5, +0.0, +0.0},
+ {-0.5, +0.5, -0.5, +0.0, +1.0},
+ {-0.5, -0.5, -0.5, +0.0, +0.0},
+ {-0.5, +0.5, +0.5, +1.0, +1.0},
+ {-0.5, -0.5, +0.5, +1.0, +0.0},
},
{
- {+0.5f, +0.5f, +0.5f},
- {+0.5f, +0.5f, -0.5f},
- {+0.5f, -0.5f, -0.5f},
- {+0.5f, -0.5f, -0.5f},
- {+0.5f, -0.5f, +0.5f},
- {+0.5f, +0.5f, +0.5f},
+ {+0.5, +0.5, +0.5, +1.0, +1.0},
+ {+0.5, +0.5, -0.5, +0.0, +1.0},
+ {+0.5, -0.5, -0.5, +0.0, +0.0},
+ {+0.5, -0.5, -0.5, +0.0, +0.0},
+ {+0.5, -0.5, +0.5, +1.0, +0.0},
+ {+0.5, +0.5, +0.5, +1.0, +1.0},
},
{
- {-0.5f, -0.5f, -0.5f},
- {+0.5f, -0.5f, -0.5f},
- {+0.5f, -0.5f, +0.5f},
- {+0.5f, -0.5f, +0.5f},
- {-0.5f, -0.5f, +0.5f},
- {-0.5f, -0.5f, -0.5f},
+ {-0.5, -0.5, -0.5, +0.0, +1.0},
+ {+0.5, -0.5, -0.5, +1.0, +1.0},
+ {+0.5, -0.5, +0.5, +1.0, +0.0},
+ {+0.5, -0.5, +0.5, +1.0, +0.0},
+ {-0.5, -0.5, +0.5, +0.0, +0.0},
+ {-0.5, -0.5, -0.5, +0.0, +1.0},
},
{
- {-0.5f, +0.5f, -0.5f},
- {+0.5f, +0.5f, -0.5f},
- {+0.5f, +0.5f, +0.5f},
- {+0.5f, +0.5f, +0.5f},
- {-0.5f, +0.5f, +0.5f},
- {-0.5f, +0.5f, -0.5f},
+ {-0.5, +0.5, -0.5, +0.0, +1.0},
+ {+0.5, +0.5, -0.5, +1.0, +1.0},
+ {+0.5, +0.5, +0.5, +1.0, +0.0},
+ {+0.5, +0.5, +0.5, +1.0, +0.0},
+ {-0.5, +0.5, +0.5, +0.0, +0.0},
+ {-0.5, +0.5, -0.5, +0.0, +1.0},
},
};
{+0, +1, +0},
};
-#define GNODDEF(block, x, y, z) node_definitions[block->data[x][y][z].type]
+#define VISIBLE(block, x, y, z) node_definitions[block->data[x][y][z].type].visible
#define VALIDPOS(pos) (pos.x >= 0 && pos.x < 16 && pos.y >= 0 && pos.y < 16 && pos.z >= 0 && pos.z < 16)
-static Array make_vertices(MapBlock *block)
+static VertexBuffer make_vertices(MapBlock *block)
{
- Array vertices = array_create(sizeof(Vertex));
+ VertexBuffer buffer = vertexbuffer_create();
ITERATE_MAPBLOCK {
- NodeDefintion *def = &GNODDEF(block, x, y, z);
- if (def->visible) {
- v3u8 pos = {x, y, z};
+ if (VISIBLE(block, x, y, z)) {
v3f offset = {x + 8.5f, y + 8.5f, z + 8.5f};
- v3f color = get_node_color(def);
+
+ vertexbuffer_set_texture(&buffer, client_node_definitions[block->data[x][y][z].type].texture);
+
for (int f = 0; f < 6; f++) {
- v3s8 *noff = &fdir[f];
v3s8 npos = {
- pos.x + noff->x,
- pos.y + noff->y,
- pos.z + noff->z,
+ x + fdir[f].x,
+ y + fdir[f].y,
+ z + fdir[f].z,
};
- if (! VALIDPOS(npos) || ! GNODDEF(block, npos.x, npos.y, npos.z).visible) {
+
+ if (! VALIDPOS(npos) || ! VISIBLE(block, npos.x, npos.y, npos.z)) {
for (int v = 0; v < 6; v++) {
- Vertex vertex = {
- vpos[f][v].x + offset.x,
- vpos[f][v].y + offset.y,
- vpos[f][v].z + offset.z,
- color.x,
- color.y,
- color.z,
- };
- array_append(&vertices, &vertex);
+ Vertex vertex = cube_vertices[f][v];
+ vertex.x += offset.x;
+ vertex.y += offset.y;
+ vertex.z += offset.z;
+
+ vertexbuffer_add_vertex(&buffer, &vertex);
}
}
}
}
}
- return vertices;
+ return buffer;
}
#undef GNODDEF
void make_block_mesh(MapBlock *block, Scene *scene)
{
- Array vertices = make_vertices(block);
- Mesh *mesh = NULL;
-
- if (vertices.siz > 0) {
- mesh = mesh_create(vertices.ptr, vertices.siz);
- mesh->pos = (v3f) {block->pos.x * 16.0f - 8.0f, block->pos.y * 16.0f - 8.0f, block->pos.z * 16.0f - 8.0f};
- mesh_transform(mesh);
- scene_add_mesh(scene, mesh);
- }
-
if (block->extra)
- ((Mesh *) block->extra)->remove = true;
- block->extra = mesh;
+ ((MeshObject *) block->extra)->remove = true;
+ block->extra = meshobject_create(make_vertices(block), scene, (v3f) {block->pos.x * 16.0f - 8.0f, block->pos.y * 16.0f - 8.0f, block->pos.z * 16.0f - 8.0f});
}
#include <GLFW/glfw3.h>
#include "client.h"
#include "clientmap.h"
+#include "clientnode.h"
#include "signal.h"
#include "shaders.h"
#include "util.h"
#include "network.c"
-static void *reciever_thread(void *unused)
+static void *reciever_thread(__attribute__((unused)) void *unused)
{
- (void) unused;
-
handle_packets(&client);
if (errno != EINTR)
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
- const char *shader_path;
-
-#ifdef RELEASE
- shader_path = "shaders";
-#else
- shader_path = "../shaders";
-#endif
-
- ShaderProgram *prog = create_shader_program(shader_path);
+ 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();
+
mat4x4 view, projection;
update_view_matrix(prog, view);
#include "network.h"
#include "scene.h"
+#ifdef RELEASE
+ #define RESSOURCEPATH ""
+#else
+ #define RESSOURCEPATH "../"
+#endif
+
typedef struct Client
{
int fd;
#include "clientmap.h"
#include "types.h"
-static bool disconnect_handler(Client *client, bool good)
+static bool disconnect_handler(__attribute__((unused)) Client *client, bool good)
{
- (void) client;
-
if (good)
client_disconnect(false, NULL);
return true;
((MapBlock *) block)->state = MBS_READY;
}
-static void *meshgen_thread(void *unused)
+static void *meshgen_thread(__attribute__((unused)) void *unused)
{
- (void) unused;
-
while (! meshgen.cancel) {
MapBlock *block;
if ((block = dequeue_callback(meshgen.queue, &set_block_ready)))
{
client = cli;
meshgen.queue = create_queue();
+}
+
+void clientmap_start_meshgen()
+{
pthread_create(&meshgen.thread, NULL, &meshgen_thread, NULL);
}
void clientmap_deinit()
{
meshgen.cancel = true;
- pthread_join(meshgen.thread, NULL);
+ delete_queue(meshgen.queue);
+ if (meshgen.thread)
+ pthread_join(meshgen.thread, NULL);
}
void clientmap_block_changed(MapBlock *block)
#include "client.h"
void clientmap_init(Client *cli);
+void clientmap_start_meshgen();
void clientmap_deinit();
void clientmap_block_changed(MapBlock *block);
--- /dev/null
+#include "client.h"
+#include "clientnode.h"
+#include "node.h"
+#include "texture.h"
+
+ClientNodeDefintion client_node_definitions[NODE_UNLOADED] = {
+ {RESSOURCEPATH "textures/invalid.png", 0},
+ {NULL, 0},
+ {RESSOURCEPATH "textures/grass.png", 0},
+ {RESSOURCEPATH "textures/dirt.png", 0},
+ {RESSOURCEPATH "textures/stone.png", 0},
+};
+
+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);
+ }
+}
--- /dev/null
+#ifndef _CLIENTNODE_H_
+#define _CLIENTNODE_H_
+
+#include "node.h"
+
+typedef struct
+{
+ char *texture_path;
+ GLuint texture;
+} ClientNodeDefintion;
+
+extern ClientNodeDefintion client_node_definitions[];
+void init_client_node_definitions();
+
+#endif
}
void list_clear(List *list)
+{
+ list_clear_func(list, NULL, NULL);
+}
+
+void list_clear_func(List *list, void (*func)(void *key, void *value, void *arg), void *arg)
{
for (ListPair *pair = list->first; pair != NULL;) {
ListPair *next = pair->next;
+ if (func)
+ func(pair->key, pair->value, arg);
free(pair);
pair = next;
}
return true;
}
+void *list_get_cached(List *list, void *key, void *(*provider)(void *key))
+{
+ ListPair **pairptr;
+ for (pairptr = &list->first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
+ if (list->cmp((*pairptr)->key, key))
+ return (*pairptr)->value;
+ }
+ return (*pairptr = make_pair(key, provider(key)))->value;
+}
+
void list_set(List *list, void *key, void *value)
{
ListPair **pairptr;
List list_create(ListComparator cmp);
void list_clear(List *list);
+void list_clear_func(List *list, void (*func)(void *key, void *value, void *arg), void *arg);
bool list_put(List *list, void *key, void *value);
+void *list_get_cached(List *list, void *key, void *(*provider)(void *key));
void list_set(List *list, void *key, void *value);
void *list_get(List *list, void *key);
void *list_delete(List *list, void *key);
#include "map.h"
#include "util.h"
-#define CMPBOUNDS(x) x == 0 ? 0 : x > 0 ? 1 : -1
-
static s8 sector_compare(void *hash, void *sector)
{
s64 d = *((u64 *) hash) - (*(MapSector **) sector)->hash;
+#include <assert.h>
#include <stdlib.h>
#include <stddef.h>
#include "mesh.h"
+#include "scene.h"
-Mesh *mesh_create(Vertex *vertices, GLsizei count)
+VertexBuffer vertexbuffer_create()
{
- Mesh *mesh = malloc(sizeof(Mesh));
- mesh->pos = (v3f) {0.0f, 0.0f, 0.0f};
- mesh->rot = (v3f) {0.0f, 0.0f, 0.0f};
- mesh->scale = (v3f) {1.0f, 1.0f, 1.0f};
- mesh_transform(mesh);
- mesh->angle = 0.0f;
- mesh->VAO = 0;
- mesh->VBO = 0;
- mesh->remove = false;
- mesh->vertices = vertices;
- mesh->count = count;
- return mesh;
+ return (VertexBuffer) {
+ .faces = array_create(sizeof(Face)),
+ };
+}
+
+void vertexbuffer_set_texture(VertexBuffer *buffer, GLuint texture)
+{
+ if (buffer->current && buffer->current->texture == texture)
+ return;
+ Face face = {
+ .texture = texture,
+ .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;
+ 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);
+
+ scene_add_object(scene, obj);
+
+ return obj;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
-void mesh_transform(Mesh *mesh)
+void meshobject_transform(MeshObject *obj)
{
- mat4x4_translate(mesh->transform, mesh->pos.x, mesh->pos.y, mesh->pos.z);
- mat4x4_rotate(mesh->transform, mesh->transform, mesh->rot.x, mesh->rot.y, mesh->rot.z, mesh->angle);
- mat4x4_scale_aniso(mesh->transform, mesh->transform, mesh->scale.x, mesh->scale.y, mesh->scale.z);
+ mat4x4_translate(obj->transform, obj->pos.x, obj->pos.y, obj->pos.z);
+ 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 mesh_delete(Mesh *mesh)
+void meshobject_delete(MeshObject *obj)
{
- if (mesh->vertices)
- free(mesh->vertices);
- if (mesh->VAO)
- glDeleteVertexArrays(1, &mesh->VAO);
- if (mesh->VBO)
- glDeleteBuffers(1, &mesh->VAO);
- free(mesh);
+ 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)
glBindVertexArray(mesh->VAO);
glBindBuffer(GL_ARRAY_BUFFER, mesh->VBO);
- glBufferData(GL_ARRAY_BUFFER, mesh->count * sizeof(Vertex), mesh->vertices, GL_STATIC_DRAW);
+ 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, 3, GL_FLOAT, false, sizeof(Vertex), (GLvoid *) offsetof(Vertex, r));
+
+ glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(Vertex), (GLvoid *) offsetof(Vertex, s));
glEnableVertexAttribArray(1);
+
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
mesh->vertices = NULL;
}
-void mesh_render(Mesh *mesh, ShaderProgram *prog)
+void meshobject_render(MeshObject *obj, ShaderProgram *prog)
{
- if (mesh->vertices)
- mesh_configure(mesh);
+ glUniformMatrix4fv(prog->loc_model, 1, GL_FALSE, obj->transform[0]);
- glUniformMatrix4fv(prog->loc_model, 1, GL_FALSE, mesh->transform[0]);
+ glActiveTexture(GL_TEXTURE0);
- glBindVertexArray(mesh->VAO);
- glDrawArrays(GL_TRIANGLES, 0, mesh->count);
+ 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);
}
#include <GL/gl.h>
#include <linmath.h/linmath.h>
#include <stdbool.h>
+#include "array.h"
#include "shaders.h"
#include "types.h"
typedef struct
{
GLfloat x, y, z;
- GLfloat r, g, b;
-} __attribute__((packed, aligned(4))) Vertex;
+ GLfloat s, t;
+} __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;
float angle;
mat4x4 transform;
- GLuint VAO, VBO;
bool remove;
- Vertex *vertices;
- GLsizei count;
-} Mesh;
+ Mesh **meshes;
+ size_t meshes_count;
+} MeshObject;
+
+struct Scene;
+
+VertexBuffer vertexbuffer_create();
+void vertexbuffer_set_texture(VertexBuffer *buffer, GLuint texture);
+void vertexbuffer_add_vertex(VertexBuffer *buffer, Vertex *vertex);
-Mesh *mesh_create(Vertex *vertices, GLsizei count);
-void mesh_delete(Mesh *mesh);
-void mesh_transform(Mesh *mesh);
-void mesh_render(Mesh *mesh, ShaderProgram *prog);
+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
#include "util.h"
NodeDefintion node_definitions[NODE_UNLOADED] = {
- {true, false, "#991300", {0.0f, 0.0f, 0.0f}},
- {false, false, "", {0.0f, 0.0f, 0.0f}},
- {true, false, "#137822", {0.0f, 0.0f, 0.0f}},
- {true, false, "#6B3627", {0.0f, 0.0f, 0.0f}},
- {true, false, "#4F4F4F", {0.0f, 0.0f, 0.0f}},
+ {true},
+ {false},
+ {true},
+ {true},
+ {true},
};
-
-v3f get_node_color(NodeDefintion *def)
-{
- return def->color_initialized ? def->color : (def->color = html_to_v3f(def->color_str));
-}
#ifndef _NODE_H_
#define _NODE_H_
+#include <stdbool.h>
#include "types.h"
typedef enum
typedef struct
{
bool visible;
- bool color_initialized;
- const char *color_str;
- v3f color;
} NodeDefintion;
-v3f get_node_color(NodeDefintion *def);
-
extern NodeDefintion node_definitions[];
#endif
{
pthread_mutex_destroy(&queue->mtx);
list_clear(&queue->list);
+ free(queue);
}
void enqueue(Queue *queue, void *elem)
Scene *scene_create()
{
Scene *scene = malloc(sizeof(Scene));
- scene->meshes = list_create(NULL),
+ 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)
{
- ITERATE_LIST(&scene->meshes, pair) mesh_delete(pair->key);
- list_clear(&scene->meshes);
+ list_clear_func(&scene->objects, &list_delete_mesh, NULL);
pthread_mutex_destroy(&scene->mtx);
free(scene);
}
-void scene_add_mesh(Scene *scene, Mesh *mesh)
+void scene_add_object(Scene *scene, MeshObject *obj)
{
pthread_mutex_lock(&scene->mtx);
- list_put(&scene->meshes, mesh, NULL);
+ list_put(&scene->objects, obj, NULL);
pthread_mutex_unlock(&scene->mtx);
}
void scene_render(Scene *scene, ShaderProgram *prog)
{
- for (ListPair **pairptr = &scene->meshes.first; *pairptr != NULL; ) {
+ for (ListPair **pairptr = &scene->objects.first; *pairptr != NULL; ) {
ListPair *pair = *pairptr;
- Mesh *mesh = pair->key;
- if (mesh->remove) {
+ MeshObject *obj = pair->key;
+ if (obj->remove) {
pthread_mutex_lock(&scene->mtx);
*pairptr = pair->next;
pthread_mutex_unlock(&scene->mtx);
free(pair);
- mesh_delete(mesh);
+ meshobject_delete(obj);
} else {
- mesh_render(mesh, prog);
+ meshobject_render(obj, prog);
pairptr = &pair->next;
}
}
#include "mesh.h"
#include "shaders.h"
-typedef struct
+typedef struct Scene
{
- List meshes;
+ List objects;
pthread_mutex_t mtx;
} Scene;
Scene *scene_create();
void scene_delete(Scene *scene);
-void scene_add_mesh(Scene *scene, Mesh *mesh);
-void scene_remove_mesh(Scene *scene, Mesh *mesh);
+void scene_add_object(Scene *scene, MeshObject *obj);
void scene_render(Scene *scene, ShaderProgram *prog);
#endif
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;
servermap_deinit();
pthread_rwlock_wrlock(&server.clients_rwlck);
- ITERATE_LIST(&server.clients, pair) server_disconnect_client(pair->key, DISCO_NO_REMOVE | DISCO_NO_MESSAGE, "");
- list_clear(&server.clients);
+ 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);
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 reset_block(MapBlock *block)
{
MapBlockExtraData *extra = block->extra;
save_block(servermap.db, block);
- ITERATE_LIST(&extra->clients, pair) {
- Client *client = list_get(&server->players, pair->key);
- if (client)
- list_delete(&client->sent_blocks, block);
- free(pair->key);
- }
+ list_clear_func(&extra->clients, &reset_client_block, block);
list_clear(&extra->clients);
block->state = MBS_READY;
pthread_rwlock_unlock(&server->players_rwlck);
}
-static void *map_thread(void *unused)
+static void *map_thread(__attribute__((unused)) void *unused)
{
- (void) unused;
-
servermap.db = open_mapdb("map.sqlite");
while (! servermap.cancel)
pthread_create(&servermap.thread, NULL, &map_thread, NULL);
}
+static void list_delete_extra_data(void *key, __attribute__((unused)) void *value, __attribute__((unused)) void *unused)
+{
+ free(key);
+}
+
void servermap_delete_extra_data(void *ext)
{
MapBlockExtraData *extra = ext;
if (extra) {
- ITERATE_LIST(&extra->clients, pair) free(pair->key);
- list_clear(&extra->clients);
+ list_clear_func(&extra->clients, &list_delete_extra_data, NULL);
free(extra->data);
free(extra);
}
fprintf(stderr, "%s\n", strsignal(sig));
}
-static void silent_handler(int sig)
+static void silent_handler(__attribute__((unused)) int sig)
{
- (void) sig;
}
static struct sigaction sigact_interrupt = {0};
--- /dev/null
+#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)
+{
+ glDeleteTextures(1, value);
+ free(value);
+}
+
+__attribute((destructor)) static void delete_textures()
+{
+ list_clear_func(&textures, &list_delete_texture, NULL);
+}
+
+static void *create_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;
+ }
+
+ GLuint *id = malloc(sizeof(GLuint));
+
+ glGenTextures(1, id);
+
+ glBindTexture(GL_TEXTURE_2D, *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_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ stbi_image_free(data);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ return id;
+}
+
+GLuint get_texture(char *path)
+{
+ return *(GLuint *)list_get_cached(&textures, path, &create_texture);
+}
--- /dev/null
+#ifndef _TEXTURE_H_
+#define _TEXTURE_H_
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+
+GLuint get_texture(char *path);
+
+#endif
#define ever (;;)
#define INBRACES(str) str ? "(" : "", str ? str : "", str ? ")" : ""
+#define CMPBOUNDS(x) x == 0 ? 0 : x > 0 ? 1 : -1
extern const char *program_name;