1 #include <dragonstd/tree.h>
5 #include "client/camera.h"
6 #include "client/client_config.h"
7 #include "client/frustum.h"
8 #include "client/model.h"
16 static pthread_rwlock_t lock_scene;
19 // fixme: blending issues still occur
20 static int cmp_batch_texture(const ModelBatchTexture *ta, const ModelBatchTexture *tb)
23 ta->vertices.siz > tb->vertices.siz ? -1 :
24 ta->vertices.siz < tb->vertices.siz ? +1 :
28 static int cmp_node(const ModelNode *node, const char *str)
30 if (str == node->name)
39 return strcmp(node->name, str);
42 static void transform_node(ModelNode *node)
45 mat4x4_mul(node->abs, node->parent->abs, node->rel);
47 mat4x4_dup(node->abs, node->rel);
49 list_itr(&node->children, &transform_node, NULL, NULL);
52 static void render_node(ModelNode *node)
57 for (size_t i = 0; i < node->meshes.siz; i++) {
58 ModelMesh *mesh = &((ModelMesh *) node->meshes.ptr)[i];
60 glUseProgram(mesh->shader->prog);
61 glUniformMatrix4fv(mesh->shader->loc_transform, 1, GL_FALSE, node->abs[0]);
64 for (GLuint i = 0; i < mesh->num_textures; i++)
65 glBindTextureUnit(i, mesh->textures[i]);
67 mesh_render(mesh->mesh);
70 list_itr(&node->children, (void *) &render_node, NULL, NULL);
73 static void free_node_meshes(ModelNode *node)
75 for (size_t i = 0; i < node->meshes.siz; i++) {
76 ModelMesh *mesh = &((ModelMesh *) node->meshes.ptr)[i];
78 mesh_destroy(mesh->mesh);
82 list_clr(&node->children, (void *) &free_node_meshes, NULL, NULL);
85 static void delete_node(ModelNode *node)
87 for (size_t i = 0; i < node->meshes.siz; i++) {
88 ModelMesh *mesh = &((ModelMesh *) node->meshes.ptr)[i];
93 list_clr(&node->children, (void *) &delete_node, NULL, NULL);
94 array_clr(&node->meshes);
99 static void init_node(ModelNode *node, ModelNode *parent)
101 if ((node->parent = parent))
102 list_apd(&parent->children, node);
104 list_ini(&node->children);
107 static void clone_mesh(ModelMesh *mesh)
109 GLuint *old_textures = mesh->textures;
110 memcpy(mesh->textures = malloc(mesh->num_textures * sizeof *mesh->textures),
111 old_textures, mesh->num_textures * sizeof *mesh->textures);
114 static ModelNode *clone_node(ModelNode *original, ModelNode *parent)
116 ModelNode *node = malloc(sizeof *node);
118 init_node(node, parent);
120 array_cln(&node->meshes, &original->meshes);
121 for (size_t i = 0; i < node->meshes.siz; i++)
122 clone_mesh(&((ModelMesh *) node->meshes.ptr)[i]);
124 list_itr(&original->children, (void *) &clone_node, parent, NULL);
128 static int cmp_model(const Model *model, const f32 *distance)
130 return f32_cmp(&model->distance, distance);
133 static void render_model(Model *model)
135 if (model->flags.wireframe)
136 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
138 render_node(model->root);
140 if (model->flags.wireframe)
141 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
144 // step model help im stuck
145 static void model_step(Model *model, Tree *transparent, f64 dtime)
147 if (client_config.view_distance < (model->distance = sqrt(
148 pow(model->root->pos.x - camera.eye[0], 2) +
149 pow(model->root->pos.y - camera.eye[1], 2) +
150 pow(model->root->pos.z - camera.eye[2], 2))))
153 if (model->callbacks.step)
154 model->callbacks.step(model, dtime);
156 if (!model->root->visible)
159 if (model->flags.frustum_culling && frustum_cull((aabb3f32) {
160 v3f32_add(model->box.min, model->root->pos),
161 v3f32_add(model->box.max, model->root->pos)}))
164 // fixme: if there are multiple objects with the exact same distance, only one is rendered
165 if (model->flags.transparent)
166 tree_add(transparent, &model->distance, model, &cmp_model, NULL);
175 pthread_rwlock_init(&lock_scene, NULL);
176 glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units);
182 list_clr(&scene, &model_delete, NULL, NULL);
183 pthread_rwlock_destroy(&lock_scene);
188 Model *model_create()
190 Model *model = malloc(sizeof *model);
191 model->root = model_node_create(NULL);
194 model->callbacks.step = NULL;
195 model->callbacks.delete = NULL;
197 model->flags.delete =
198 model->flags.wireframe =
199 model->flags.frustum_culling =
200 model->flags.transparent = 0;
205 Model *model_load(const char *path, const char *textures_path, Mesh *cube, ModelShader *shader)
207 Model *model = model_create();
210 array_ini(&stack, sizeof(ModelNode *), 5);
211 array_apd(&stack, &model->root);
213 FILE *file = fopen(path, "r");
215 fprintf(stderr, "[warning] failed to open model %s\n", path);
224 while ((length = getline(&line, &siz, file)) > 0) {
230 char *cursor = line - 1;
233 while (*++cursor == '\t')
236 if (tabs >= stack.siz) {
237 fprintf(stderr, "[warning] invalid indent in model %s in line %d\n", path, count);
241 ModelNode *node = model_node_create(((ModelNode **) stack.ptr)[tabs]);
244 char key[length + 1];
245 while (sscanf(cursor, "%s %n", key, &n) == 1) {
248 if (strcmp(key, "name") == 0) {
249 char name[length + 1];
251 if (sscanf(cursor, "%s %n", name, &n) == 1) {
256 node->name = strdup(name);
258 fprintf(stderr, "[warning] invalid value for name in model %s in line %d\n", path, count);
260 } else if (strcmp(key, "pos") == 0) {
261 if (sscanf(cursor, "%f %f %f %n", &node->pos.x, &node->pos.y, &node->pos.z, &n) == 3)
264 fprintf(stderr, "[warning] invalid value for pos in model %s in line %d\n", path, count);
265 } else if (strcmp(key, "rot") == 0) {
266 if (sscanf(cursor, "%f %f %f %n", &node->rot.x, &node->rot.y, &node->rot.z, &n) == 3)
269 fprintf(stderr, "[warning] invalid value for rot in model %s in line %d\n", path, count);
270 } else if (strcmp(key, "scale") == 0) {
271 if (sscanf(cursor, "%f %f %f %n", &node->scale.x, &node->scale.y, &node->scale.z, &n) == 3)
274 fprintf(stderr, "[warning] invalid value for scale in model %s in line %d\n", path, count);
275 } else if (strcmp(key, "angle") == 0) {
276 if (sscanf(cursor, "%f%n", &node->angle, &n) == 1)
279 fprintf(stderr, "[warning] invalid value for angle in model %s in line %d\n", path, count);
280 } else if (strcmp(key, "cube") == 0) {
281 char texture[length + 1];
283 if (sscanf(cursor, "%s %n", texture, &n) == 1) {
286 char filepath[strlen(textures_path) + 1 + strlen(texture) + 1];
287 sprintf(filepath, "%s/%s", textures_path, texture);
288 Texture *texture = texture_load_cubemap(filepath);
290 model_node_add_mesh(node, &(ModelMesh) {
292 .textures = &texture->txo,
297 fprintf(stderr, "[warning] invalid value for cube in model %s in line %d\n", path, count);
300 fprintf(stderr, "[warning] invalid key '%s' in model %s in line %d\n", key, path, count);
304 model_node_transform(node);
306 stack.siz = tabs + 1;
307 array_apd(&stack, &node);
319 Model *model_clone(Model *original)
321 Model *model = malloc(sizeof *model);
323 model->root = clone_node(original->root, NULL);
327 void model_delete(Model *model)
329 if (model->callbacks.delete)
330 model->callbacks.delete(model);
332 delete_node(model->root);
336 void model_free_meshes(Model *model)
338 free_node_meshes(model->root);
341 void model_get_bones(Model *model, ModelBoneMapping *mappings, size_t num_mappings)
343 char *name, *cursor, *saveptr, *tok;
345 for (size_t i = 0; i < num_mappings; i++) {
346 name = cursor = strdup(mappings[i].name);
348 ModelNode *node = model->root;
349 while ((tok = strtok_r(cursor, ".", &saveptr))) {
350 node = list_get(&node->children, tok, (void *) &cmp_node, NULL);
355 *mappings[i].node = node;
357 fprintf(stderr, "[warning] no such bone: %s\n", name);
363 // ModelNode functions
365 ModelNode *model_node_create(ModelNode *parent)
367 ModelNode *node = malloc(sizeof *node);
369 node->visible = true;
370 node->pos = (v3f32) {0.0f, 0.0f, 0.0f};
371 node->rot = (v3f32) {0.0f, 0.0f, 0.0f};
372 node->scale = (v3f32) {1.0f, 1.0f, 1.0f};
374 array_ini(&node->meshes, sizeof(ModelMesh), 0);
375 init_node(node, parent);
379 void model_node_transform(ModelNode *node)
381 mat4x4_translate(node->rel,
386 mat4x4_rotate(node->rel, node->rel,
392 mat4x4_scale_aniso(node->rel, node->rel,
397 transform_node(node);
400 void model_node_add_mesh(ModelNode *node, const ModelMesh *mesh)
402 array_apd(&node->meshes, mesh);
403 clone_mesh(&((ModelMesh *) node->meshes.ptr)[node->meshes.siz - 1]);
406 void model_node_add_batch(ModelNode *node, ModelBatch *batch)
408 if (!batch->textures.siz) {
413 array_srt(&batch->textures, &cmp_batch_texture);
414 ModelBatchTexture *textures = batch->textures.ptr;
416 size_t num_meshes = ceil((double) batch->textures.siz / (double) units);
417 array_grw(&node->meshes, num_meshes);
418 ModelMesh *meshes = node->meshes.ptr + node->meshes.siz - num_meshes;
420 for (size_t m = 0; m < num_meshes; m++) {
421 ModelMesh *mesh = &meshes[m];
423 mesh->mesh = malloc(sizeof *mesh->mesh);
424 mesh->mesh->layout = batch->layout;
425 mesh->mesh->vao = mesh->mesh->vbo = 0;
426 mesh->mesh->free_data = true;
428 mesh->textures = malloc(sizeof *mesh->textures * (mesh->num_textures =
429 ceil((double) (batch->textures.siz - m) / (double) num_meshes)));
431 mesh->shader = batch->shader;
433 mesh->mesh->count = 0;
434 for (size_t t = 0; t < mesh->num_textures; t++) {
435 ModelBatchTexture *texture = &textures[m + t * num_meshes];
436 mesh->mesh->count += texture->vertices.siz;
437 mesh->textures[t] = texture->texture;
439 for (size_t v = 0; v < texture->vertices.siz; v++)
440 *((f32 *) (texture->vertices.ptr + v * texture->vertices.mbs
441 + batch->off_tex_idx)) = t;
444 ModelBatchTexture *first = &textures[m];
445 first->vertices.cap = mesh->mesh->count;
446 first->vertices.ext = 0;
447 array_rlc(&first->vertices);
449 mesh->mesh->data = first->vertices.ptr;
451 for (size_t t = 1; t < mesh->num_textures; t++) {
452 ModelBatchTexture *texture = &textures[m + t * num_meshes];
453 memcpy(first->vertices.ptr + first->vertices.siz * first->vertices.mbs,
454 texture->vertices.ptr, texture->vertices.siz * texture->vertices.mbs);
455 first->vertices.siz += texture->vertices.siz;
457 array_clr(&texture->vertices);
461 array_clr(&batch->textures);
465 // ModelBatch functions
467 ModelBatch *model_batch_create(ModelShader *shader, VertexLayout *layout, size_t off_tex_idx)
469 ModelBatch *batch = malloc(sizeof *batch);
470 batch->shader = shader;
471 batch->layout = layout;
472 batch->off_tex_idx = off_tex_idx;
473 array_ini(&batch->textures, sizeof(ModelBatchTexture), 5);
477 void model_batch_free(ModelBatch *batch)
479 for (size_t i = 0; i < batch->textures.siz; i++)
480 array_clr(&((ModelBatchTexture *) batch->textures.ptr)[i].vertices);
482 array_clr(&batch->textures);
486 void model_batch_add_vertex(ModelBatch *batch, GLuint texture, const void *vertex)
488 ModelBatchTexture *batch_texture = NULL;
490 for (size_t i = 0; i <= batch->textures.siz; i++) {
491 if (i == batch->textures.siz) {
492 ModelBatchTexture new;
493 new.texture = texture;
494 array_ini(&new.vertices, batch->layout->size, 10000);
495 array_apd(&batch->textures, &new);
498 if ((batch_texture = &((ModelBatchTexture *) batch->textures.ptr)[i])->texture == texture)
502 array_apd(&batch_texture->vertices, vertex);
507 void model_scene_add(Model *model)
509 pthread_rwlock_wrlock(&lock_scene);
510 list_apd(&scene, model);
511 pthread_rwlock_unlock(&lock_scene);
514 void model_scene_render(f64 dtime)
517 tree_ini(&transparent);
519 pthread_rwlock_rdlock(&lock_scene);
520 for (ListNode **node = &scene.fst; *node != NULL;) {
521 Model *model = (*node)->dat;
523 pthread_rwlock_unlock(&lock_scene);
524 if (model->flags.delete) {
527 pthread_rwlock_wrlock(&lock_scene);
528 list_nrm(&scene, node);
529 pthread_rwlock_unlock(&lock_scene);
531 pthread_rwlock_rdlock(&lock_scene);
533 model_step(model, &transparent, dtime);
535 pthread_rwlock_rdlock(&lock_scene);
536 node = &(*node)->nxt;
539 pthread_rwlock_unlock(&lock_scene);
541 tree_clr(&transparent, &render_model, NULL, NULL, TRAVERSION_INORDER);