]> git.lizzy.rs Git - dragonblocks_alpha.git/blobdiff - src/client/model.c
Fix memory leak in model.c
[dragonblocks_alpha.git] / src / client / model.c
index 1d163c7b1a34c8b78a4a3bde116986626905370f..7c1c1e2b6170e7a5da819538e7011fcbf373a19d 100644 (file)
@@ -1,10 +1,12 @@
 #include <dragonstd/tree.h>
+#include <getline.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <pthread.h>
 #include "client/camera.h"
 #include "client/client_config.h"
 #include "client/frustum.h"
+#include "client/opengl.h"
 #include "client/model.h"
 
 typedef struct {
@@ -13,10 +15,10 @@ typedef struct {
 } ModelBatchTexture;
 
 static List scene;
-static pthread_rwlock_t lock_scene;
+static List scene_new;
+static pthread_mutex_t lock_scene_new;
 static GLint units;
 
-// fixme: blending issues still occur
 static int cmp_batch_texture(const ModelBatchTexture *ta, const ModelBatchTexture *tb)
 {
        return
@@ -54,20 +56,32 @@ static void render_node(ModelNode *node)
        if (!node->visible)
                return;
 
+       if (node->clockwise) {
+               glFrontFace(GL_CW); GL_DEBUG
+       }
+
        for (size_t i = 0; i < node->meshes.siz; i++) {
                ModelMesh *mesh = &((ModelMesh *) node->meshes.ptr)[i];
 
-               glUseProgram(mesh->shader->prog);
-               glUniformMatrix4fv(mesh->shader->loc_transform, 1, GL_FALSE, node->abs[0]);
+               if (!mesh->mesh)
+                       continue;
+
+               glUseProgram(mesh->shader->prog); GL_DEBUG
+               glUniformMatrix4fv(mesh->shader->loc_transform, 1, GL_FALSE, node->abs[0]); GL_DEBUG
 
                // bind textures
-               for (GLuint i = 0; i < mesh->num_textures; i++)
-                       glBindTextureUnit(i, mesh->textures[i]);
+               for (GLuint i = 0; i < mesh->num_textures; i++) {
+                       glBindTextureUnit(i, mesh->textures[i]); GL_DEBUG
+               }
 
                mesh_render(mesh->mesh);
        }
 
-       list_itr(&node->children, (void *) &render_node, NULL, NULL);
+       list_itr(&node->children, &render_node, NULL, NULL);
+
+       if (node->clockwise) {
+               glFrontFace(GL_CCW); GL_DEBUG
+       }
 }
 
 static void free_node_meshes(ModelNode *node)
@@ -79,7 +93,7 @@ static void free_node_meshes(ModelNode *node)
                free(mesh->mesh);
        }
 
-       list_clr(&node->children, (void *) &free_node_meshes, NULL, NULL);
+       list_clr(&node->children, &free_node_meshes, NULL, NULL);
 }
 
 static void delete_node(ModelNode *node)
@@ -90,9 +104,11 @@ static void delete_node(ModelNode *node)
                if (mesh->textures)
                        free(mesh->textures);
        }
-       list_clr(&node->children, (void *) &delete_node, NULL, NULL);
+       list_clr(&node->children, &delete_node, NULL, NULL);
        array_clr(&node->meshes);
 
+       if (node->name)
+               free(node->name);
        free(node);
 }
 
@@ -115,44 +131,46 @@ static ModelNode *clone_node(ModelNode *original, ModelNode *parent)
 {
        ModelNode *node = malloc(sizeof *node);
        *node = *original;
+       if (original->name)
+               node->name = strdup(original->name);
        init_node(node, parent);
 
        array_cln(&node->meshes, &original->meshes);
        for (size_t i = 0; i < node->meshes.siz; i++)
                clone_mesh(&((ModelMesh *) node->meshes.ptr)[i]);
 
-       list_itr(&original->children, (void *) &clone_node, parent, NULL);
+       list_itr(&original->children, &clone_node, node, NULL);
        return node;
 }
 
 static int cmp_model(const Model *model, const f32 *distance)
 {
-       return f32_cmp(&model->distance, distance);
+       return -f32_cmp(&model->distance, distance);
 }
 
 static void render_model(Model *model)
 {
-       if (model->flags.wireframe)
-               glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+       if (model->callbacks.before_render)
+               model->callbacks.before_render(model);
 
        render_node(model->root);
 
-       if (model->flags.wireframe)
-               glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+       if (model->callbacks.after_render)
+               model->callbacks.after_render(model);
 }
 
 // step model help im stuck
 static void model_step(Model *model, Tree *transparent, f64 dtime)
 {
+       if (model->callbacks.step)
+               model->callbacks.step(model, dtime);
+
        if (client_config.view_distance < (model->distance = sqrt(
                        pow(model->root->pos.x - camera.eye[0], 2) +
                        pow(model->root->pos.y - camera.eye[1], 2) +
                        pow(model->root->pos.z - camera.eye[2], 2))))
                return;
 
-       if (model->callbacks.step)
-               model->callbacks.step(model, dtime);
-
        if (!model->root->visible)
                return;
 
@@ -172,15 +190,19 @@ static void model_step(Model *model, Tree *transparent, f64 dtime)
 void model_init()
 {
        list_ini(&scene);
-       pthread_rwlock_init(&lock_scene, NULL);
-       glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units);
+       list_ini(&scene_new);
+
+       pthread_mutex_init(&lock_scene_new, NULL);
+       units = opengl_texture_batch_units();
 }
 
 // ded
 void model_deinit()
 {
        list_clr(&scene, &model_delete, NULL, NULL);
-       pthread_rwlock_destroy(&lock_scene);
+       list_clr(&scene_new, &model_delete, NULL, NULL);
+
+       pthread_mutex_destroy(&lock_scene_new);
 }
 
 // Model functions
@@ -190,12 +212,14 @@ Model *model_create()
        Model *model = malloc(sizeof *model);
        model->root = model_node_create(NULL);
        model->extra = NULL;
+       model->replace = NULL;
 
        model->callbacks.step = NULL;
+       model->callbacks.before_render = NULL;
+       model->callbacks.after_render = NULL;
        model->callbacks.delete = NULL;
 
        model->flags.delete =
-               model->flags.wireframe =
                model->flags.frustum_culling =
                model->flags.transparent = 0;
 
@@ -267,16 +291,15 @@ Model *model_load(const char *path, const char *textures_path, Mesh *cube, Model
                                        cursor += n;
                                else
                                        fprintf(stderr, "[warning] invalid value for rot in model %s in line %d\n", path, count);
+
+                               node->rot = v3f32_scale(node->rot, M_PI / 180.0);
                        } else if (strcmp(key, "scale") == 0) {
                                if (sscanf(cursor, "%f %f %f %n", &node->scale.x, &node->scale.y, &node->scale.z, &n) == 3)
                                        cursor += n;
                                else
                                        fprintf(stderr, "[warning] invalid value for scale in model %s in line %d\n", path, count);
-                       } else if (strcmp(key, "angle") == 0) {
-                               if (sscanf(cursor, "%f%n", &node->angle, &n) == 1)
-                                       cursor += n;
-                               else
-                                       fprintf(stderr, "[warning] invalid value for angle in model %s in line %d\n", path, count);
+                       } else if (strcmp(key, "clockwise") == 0) {
+                               node->clockwise = 1;
                        } else if (strcmp(key, "cube") == 0) {
                                char texture[length + 1];
 
@@ -285,7 +308,7 @@ Model *model_load(const char *path, const char *textures_path, Mesh *cube, Model
 
                                        char filepath[strlen(textures_path) + 1 + strlen(texture) + 1];
                                        sprintf(filepath, "%s/%s", textures_path, texture);
-                                       Texture *texture = texture_load_cubemap(filepath);
+                                       Texture *texture = texture_load_cubemap(filepath, false);
 
                                        model_node_add_mesh(node, &(ModelMesh) {
                                                .mesh = cube,
@@ -313,6 +336,7 @@ Model *model_load(const char *path, const char *textures_path, Mesh *cube, Model
        fclose(file);
        array_clr(&stack);
 
+       transform_node(model->root);
        return model;
 }
 
@@ -346,15 +370,16 @@ void model_get_bones(Model *model, ModelBoneMapping *mappings, size_t num_mappin
                name = cursor = strdup(mappings[i].name);
 
                ModelNode *node = model->root;
-               while ((tok = strtok_r(cursor, ".", &saveptr))) {
-                       node = list_get(&node->children, tok, (void *) &cmp_node, NULL);
+
+               while (node && (tok = strtok_r(cursor, ".", &saveptr))) {
+                       node = list_get(&node->children, tok, &cmp_node, NULL);
                        cursor = NULL;
                }
 
                if (node)
                        *mappings[i].node = node;
                else
-                       fprintf(stderr, "[warning] no such bone: %s\n", name);
+                       fprintf(stderr, "[warning] no such bone: %s\n", mappings[i].name);
 
                free(name);
        }
@@ -366,11 +391,11 @@ ModelNode *model_node_create(ModelNode *parent)
 {
        ModelNode *node = malloc(sizeof *node);
        node->name = NULL;
-       node->visible = true;
+       node->visible = 1;
+       node->clockwise = 0;
        node->pos = (v3f32) {0.0f, 0.0f, 0.0f};
        node->rot = (v3f32) {0.0f, 0.0f, 0.0f};
        node->scale = (v3f32) {1.0f, 1.0f, 1.0f};
-       node->angle = 0.0f;
        array_ini(&node->meshes, sizeof(ModelMesh), 0);
        init_node(node, parent);
        return node;
@@ -378,22 +403,22 @@ ModelNode *model_node_create(ModelNode *parent)
 
 void model_node_transform(ModelNode *node)
 {
+       mat4x4_identity(node->rel);
+
        mat4x4_translate(node->rel,
                node->pos.x,
                node->pos.y,
                node->pos.z);
 
-       mat4x4_rotate(node->rel, node->rel,
-               node->rot.x,
-               node->rot.y,
-               node->rot.z,
-               node->angle);
-
        mat4x4_scale_aniso(node->rel, node->rel,
                node->scale.x,
                node->scale.y,
                node->scale.z);
 
+       mat4x4_rotate_X(node->rel, node->rel, node->rot.x);
+       mat4x4_rotate_Y(node->rel, node->rel, node->rot.y);
+       mat4x4_rotate_Z(node->rel, node->rel, node->rot.z);
+
        transform_node(node);
 }
 
@@ -415,7 +440,7 @@ void model_node_add_batch(ModelNode *node, ModelBatch *batch)
 
        size_t num_meshes = ceil((double) batch->textures.siz / (double) units);
        array_grw(&node->meshes, num_meshes);
-       ModelMesh *meshes = node->meshes.ptr + node->meshes.siz - num_meshes;
+       ModelMesh *meshes = &((ModelMesh *) node->meshes.ptr)[node->meshes.siz - num_meshes];
 
        for (size_t m = 0; m < num_meshes; m++) {
                ModelMesh *mesh = &meshes[m];
@@ -506,37 +531,40 @@ void model_batch_add_vertex(ModelBatch *batch, GLuint texture, const void *verte
 
 void model_scene_add(Model *model)
 {
-       pthread_rwlock_wrlock(&lock_scene);
-       list_apd(&scene, model);
-       pthread_rwlock_unlock(&lock_scene);
+       pthread_mutex_lock(&lock_scene_new);
+       list_apd(&scene_new, model);
+       pthread_mutex_unlock(&lock_scene_new);
 }
 
 void model_scene_render(f64 dtime)
 {
+       pthread_mutex_lock(&lock_scene_new);
+       if (scene_new.fst) {
+               *scene.end = scene_new.fst;
+               scene.end = scene_new.end;
+
+               list_ini(&scene_new);
+       }
+       pthread_mutex_unlock(&lock_scene_new);
+
        Tree transparent;
        tree_ini(&transparent);
 
-       pthread_rwlock_rdlock(&lock_scene);
        for (ListNode **node = &scene.fst; *node != NULL;) {
                Model *model = (*node)->dat;
 
-               pthread_rwlock_unlock(&lock_scene);
                if (model->flags.delete) {
-                       model_delete(model);
+                       if (model->replace)
+                               (*node)->dat = model->replace;
+                       else
+                               list_nrm(&scene, node);
 
-                       pthread_rwlock_wrlock(&lock_scene);
-                       list_nrm(&scene, node);
-                       pthread_rwlock_unlock(&lock_scene);
-
-                       pthread_rwlock_rdlock(&lock_scene);
+                       model_delete(model);
                } else {
-                       model_step(model, &transparent, dtime);
-
-                       pthread_rwlock_rdlock(&lock_scene);
                        node = &(*node)->nxt;
+                       model_step(model, &transparent, dtime);
                }
        }
-       pthread_rwlock_unlock(&lock_scene);
 
        tree_clr(&transparent, &render_model, NULL, NULL, TRAVERSION_INORDER);
 }