A 3D game engine from scratch.
at main 592 lines 21 kB view raw
1// (c) 2020 Vlad-Stefan Harbuz <vlad@vladh.net> 2 3#include "../src_external/glad/glad.h" 4#include "../src_external/pstr.h" 5#include <assimp/cimport.h> 6#include <assimp/postprocess.h> 7#include "pack.hpp" 8#include "logs.hpp" 9#include "models.hpp" 10#include "debug.hpp" 11#include "util.hpp" 12#include "intrinsics.hpp" 13 14 15bool 16models::prepare_model_loader_and_check_if_done(ModelLoader *model_loader) { 17 if (model_loader->state == ModelLoaderState::initialized) { 18 if (pstr_starts_with(model_loader->model_path, "builtin:")) { 19 logs::error("Found model with builtin model_path for which no vertex data was loaded."); 20 return false; 21 } 22 tasks::push({ 23 .fn = (tasks::TaskFn)load_model_from_file, 24 .argument_1 = (void*)model_loader, 25 }); 26 model_loader->state = ModelLoaderState::mesh_data_being_loaded; 27 } 28 29 if (model_loader->state == ModelLoaderState::mesh_data_being_loaded) { 30 // Wait. The task will progress this for us. 31 } 32 33 if (model_loader->state == ModelLoaderState::mesh_data_loaded) { 34 for (u32 idx = 0; idx < model_loader->n_meshes; idx++) { 35 geom::Mesh *mesh = &model_loader->meshes[idx]; 36 geom::setup_mesh_vertex_buffers(mesh, mesh->vertices, mesh->n_vertices, mesh->indices, mesh->n_indices); 37 memory::destroy_memory_pool(&mesh->temp_memory_pool); 38 } 39 model_loader->state = ModelLoaderState::vertex_buffers_set_up; 40 } 41 42 if (model_loader->state == ModelLoaderState::vertex_buffers_set_up) { 43 // Set material names for each mesh 44 range_named (idx_material, 0, model_loader->n_material_names) { 45 range_named (idx_mesh, 0, model_loader->n_meshes) { 46 geom::Mesh *mesh = &model_loader->meshes[idx_mesh]; 47 u8 mesh_number = pack::get(&mesh->indices_pack, 0); 48 // For our model's mesh number `mesh_number`, we want to choose 49 // material `idx_mesh` such that `mesh_number == idx_mesh`, i.e. 50 // we choose the 4th material for mesh number 4. 51 // However, if we have more meshes than materials, the extra 52 // meshes all get material number 0. 53 if ( 54 mesh_number == idx_material || 55 (mesh_number >= model_loader->n_material_names && idx_material == 0) 56 ) { 57 pstr_copy(mesh->material_name, MAX_COMMON_NAME_LENGTH, model_loader->material_names[idx_material]); 58 } 59 } 60 } 61 62 model_loader->state = ModelLoaderState::complete; 63 } 64 65 if (model_loader->state == ModelLoaderState::complete) { 66 return true; 67 } 68 69 return false; 70} 71 72 73bool 74models::prepare_entity_loader_and_check_if_done( 75 EntityLoader *entity_loader, 76 ModelLoader *model_loader 77) { 78 if (entity_loader->state == EntityLoaderState::initialized) { 79 // Before we can create entities, we need this entity's models to have 80 // been loaded. 81 if (model_loader->state != ModelLoaderState::complete) { 82 return false; 83 } 84 85 spatial::Component *spatial_component = spatial::get_component(entity_loader->entity_handle); 86 *spatial_component = entity_loader->spatial_component; 87 spatial_component->entity_handle = entity_loader->entity_handle; 88 89 lights::Component *light_component = lights::get_component(entity_loader->entity_handle); 90 *light_component = entity_loader->light_component; 91 light_component->entity_handle = entity_loader->entity_handle; 92 93 behavior::Component *behavior_component = behavior::get_component(entity_loader->entity_handle); 94 *behavior_component = entity_loader->behavior_component; 95 behavior_component->entity_handle = entity_loader->entity_handle; 96 97 anim::Component *animation_component = anim::get_component(entity_loader->entity_handle); 98 *animation_component = model_loader->animation_component; 99 animation_component->entity_handle = entity_loader->entity_handle; 100 101 physics::Component *physics_component = physics::get_component(entity_loader->entity_handle); 102 *physics_component = entity_loader->physics_component; 103 physics_component->entity_handle = entity_loader->entity_handle; 104 105 // drawable::Component 106 if (model_loader->n_meshes == 1) { 107 drawable::Component *drawable_component = drawable::get_component(entity_loader->entity_handle); 108 assert(drawable_component); 109 *drawable_component = { 110 .entity_handle = entity_loader->entity_handle, 111 .mesh = model_loader->meshes[0], 112 .target_render_pass = entity_loader->render_pass, 113 }; 114 } else if (model_loader->n_meshes > 1) { 115 for (u32 idx = 0; idx < model_loader->n_meshes; idx++) { 116 geom::Mesh *mesh = &model_loader->meshes[idx]; 117 118 entities::Entity *child_entity = entities::add_entity_to_set(entity_loader->name); 119 120 if (spatial::is_spatial_component_valid(&entity_loader->spatial_component)) { 121 spatial::Component *child_spatial_component = spatial::get_component(child_entity->handle); 122 assert(child_spatial_component); 123 *child_spatial_component = { 124 .entity_handle = child_entity->handle, 125 .position = v3(0.0f), 126 .rotation = glm::angleAxis(radians(0.0f), v3(0.0f)), 127 .scale = v3(0.0f), 128 .parent_entity_handle = entity_loader->entity_handle, 129 }; 130 } 131 132 drawable::Component *drawable_component = drawable::get_component(child_entity->handle); 133 assert(drawable_component); 134 *drawable_component = { 135 .entity_handle = child_entity->handle, 136 .mesh = *mesh, 137 .target_render_pass = entity_loader->render_pass, 138 }; 139 } 140 } 141 142 entity_loader->state = EntityLoaderState::complete; 143 } 144 145 if (entity_loader->state == EntityLoaderState::complete) { 146 return true; 147 } 148 149 return false; 150} 151 152 153bool 154models::is_model_loader_valid(ModelLoader *model_loader) 155{ 156 return model_loader->state != ModelLoaderState::empty; 157} 158 159 160bool 161models::is_entity_loader_valid(EntityLoader *entity_loader) 162{ 163 return entity_loader->state != EntityLoaderState::empty; 164} 165 166 167void 168models::add_material_to_model_loader( 169 ModelLoader *model_loader, 170 char const *material_name 171) { 172 pstr_copy( 173 model_loader->material_names[model_loader->n_material_names++], 174 MAX_COMMON_NAME_LENGTH, 175 material_name 176 ); 177} 178 179 180models::ModelLoader * 181models::init_model_loader( 182 ModelLoader *model_loader, 183 char const *model_path 184) { 185 assert(model_loader); 186 pstr_copy(model_loader->model_path, MAX_PATH, model_path); 187 188 model_loader->state = ModelLoaderState::initialized; 189 190 if (pstr_starts_with(model_path, "builtin:")) { 191 load_model_from_data(model_loader); 192 } 193 194 return model_loader; 195} 196 197 198models::EntityLoader * 199models::init_entity_loader( 200 EntityLoader *entity_loader, 201 const char *name, 202 const char *model_path, 203 drawable::Pass render_pass, 204 entities::Handle entity_handle 205) { 206 assert(entity_loader); 207 pstr_copy(entity_loader->name, MAX_COMMON_NAME_LENGTH, name); 208 pstr_copy(entity_loader->model_path, MAX_PATH, model_path); 209 entity_loader->render_pass = render_pass; 210 entity_loader->entity_handle = entity_handle; 211 // TODO: Can we move this to constructor? 212 // If so, can we do so for other init_*() methods? 213 entity_loader->state = EntityLoaderState::initialized; 214 return entity_loader; 215} 216 217 218bool 219models::is_bone_only_node(aiNode *node) 220{ 221 if (node->mNumMeshes > 0) { 222 return false; 223 } 224 bool have_we_found_it = true; 225 range (0, node->mNumChildren) { 226 if (!is_bone_only_node(node->mChildren[idx])) { 227 have_we_found_it = false; 228 } 229 } 230 return have_we_found_it; 231} 232 233 234aiNode * 235models::find_root_bone(const aiScene *scene) 236{ 237 // NOTE: To find the root bone, we find the first-level node (direct child 238 // of root node) whose entire descendent tree has no meshes, including the 239 // leaf nodes. Is this a perfect way of finding the root bone? Probably 240 // not. Is it good enough? Sure looks like it! :) 241 aiNode *root_node = scene->mRootNode; 242 243 range (0, root_node->mNumChildren) { 244 aiNode *first_level_node = root_node->mChildren[idx]; 245 if (is_bone_only_node(first_level_node)) { 246 return first_level_node; 247 } 248 } 249 250 return nullptr; 251} 252 253 254void 255models::add_bone_tree_to_animation_component( 256 anim::Component *animation_component, 257 aiNode *node, 258 u32 idx_parent 259) { 260 u32 idx_new_bone = animation_component->n_bones; 261 animation_component->bones[idx_new_bone] = { 262 .idx_parent = idx_parent, 263 // NOTE: offset is added later, since we don't have the aiBone at this stage. 264 }; 265 pstr_copy(animation_component->bones[idx_new_bone].name, MAX_NODE_NAME_LENGTH, node->mName.C_Str()); 266 animation_component->n_bones++; 267 268 range (0, node->mNumChildren) { 269 add_bone_tree_to_animation_component(animation_component, node->mChildren[idx], idx_new_bone); 270 } 271} 272 273 274void 275models::load_bones( 276 anim::Component *animation_component, 277 const aiScene *scene 278) { 279 aiNode *root_bone = find_root_bone(scene); 280 281 if (!root_bone) { 282 // No bones. Okay! 283 return; 284 } 285 286 // The root will just have its parent marked as itself, to avoid using 287 // a -1 index and so on. This is fine, because the root will always be 288 // index 0, so we can just disregard the parent if we're on index 0. 289 add_bone_tree_to_animation_component(animation_component, root_bone, 0); 290} 291 292 293void 294models::load_animations( 295 anim::Component *animation_component, 296 const aiScene *scene 297) { 298 m4 scene_root_transform = util::aimatrix4x4_to_glm(&scene->mRootNode->mTransformation); 299 m4 inverse_scene_root_transform = inverse(scene_root_transform); 300 301 animation_component->n_animations = scene->mNumAnimations; 302 range_named (idx_animation, 0, scene->mNumAnimations) { 303 anim::Animation *animation = &animation_component->animations[idx_animation]; 304 aiAnimation *ai_animation = scene->mAnimations[idx_animation]; 305 306 *animation = { 307 .duration = ai_animation->mDuration * ai_animation->mTicksPerSecond, 308 .idx_bone_matrix_set = anim::push_to_bone_matrix_pool(), 309 }; 310 pstr_copy(animation->name, MAX_NODE_NAME_LENGTH, ai_animation->mName.C_Str()); 311 312 // Calculate bone matrices. 313 // NOTE: We do not finalise the bone matrices at this stage! 314 // The matrices in local form are still needed for the children. 315 range_named(idx_bone, 0, animation_component->n_bones) { 316 anim::Bone *bone = &animation_component->bones[idx_bone]; 317 318 u32 found_channel_idx = 0; 319 bool did_find_channel = false; 320 321 range_named (idx_channel, 0, ai_animation->mNumChannels) { 322 aiNodeAnim *ai_channel = ai_animation->mChannels[idx_channel]; 323 if (pstr_eq(ai_channel->mNodeName.C_Str(), bone->name)) { 324 found_channel_idx = idx_channel; 325 did_find_channel = true; 326 break; 327 } 328 } 329 330 if (!did_find_channel) { 331 // No channel for this bone. Maybe it's just not animated. Skip it. 332 continue; 333 } 334 335 anim::make_bone_matrices_for_animation_bone(animation_component, 336 ai_animation->mChannels[found_channel_idx], 337 idx_animation, idx_bone); 338 } 339 340 // Finalise bone matrices. 341 // NOTE: Now that we've calculated all the bone matrices for this 342 // animation, we can finalise them. 343 range_named(idx_bone, 0, animation_component->n_bones) { 344 anim::Bone *bone = &animation_component->bones[idx_bone]; 345 346 range_named (idx_anim_key, 0, bone->n_anim_keys) { 347 // #slow: We could avoid this multiplication here. 348 m4 *bone_matrix = anim::get_bone_matrix(animation->idx_bone_matrix_set, 349 idx_bone, idx_anim_key); 350 351 *bone_matrix = 352 scene_root_transform * 353 *bone_matrix * 354 bone->offset * 355 inverse_scene_root_transform; 356 } 357 } 358 } 359} 360 361 362void 363models::load_mesh( 364 geom::Mesh *mesh, 365 aiMesh *ai_mesh, 366 const aiScene *scene, 367 ModelLoader *model_loader, 368 m4 transform, 369 pack::Pack indices_pack 370) { 371 mesh->transform = transform; 372 m3 normal_matrix = m3(transpose(inverse(transform))); 373 mesh->mode = GL_TRIANGLES; 374 375 mesh->indices_pack = indices_pack; 376 377 // Vertices 378 if (!ai_mesh->mNormals) { 379 logs::warning("Model does not have normals."); 380 } 381 382 mesh->n_vertices = ai_mesh->mNumVertices; 383 mesh->vertices = (geom::Vertex*)memory::push(&mesh->temp_memory_pool, 384 mesh->n_vertices * sizeof(geom::Vertex), "mesh_vertices"); 385 386 for (u32 idx = 0; idx < ai_mesh->mNumVertices; idx++) { 387 geom::Vertex *vertex = &mesh->vertices[idx]; 388 *vertex = {}; 389 390 v4 raw_vertex_pos = v4( 391 ai_mesh->mVertices[idx].x, 392 ai_mesh->mVertices[idx].y, 393 ai_mesh->mVertices[idx].z, 394 1.0f); 395 vertex->position = v3(mesh->transform * raw_vertex_pos); 396 397 v3 raw_vertex_normal = v3( 398 ai_mesh->mNormals[idx].x, 399 ai_mesh->mNormals[idx].y, 400 ai_mesh->mNormals[idx].z); 401 vertex->normal = normalize(normal_matrix * raw_vertex_normal); 402 403 if (ai_mesh->mTextureCoords[0]) { 404 vertex->tex_coords = v2(ai_mesh->mTextureCoords[0][idx].x, 1 - ai_mesh->mTextureCoords[0][idx].y); 405 } 406 } 407 408 // Indices 409 u32 n_indices = 0; 410 for (u32 idx_face = 0; idx_face < ai_mesh->mNumFaces; idx_face++) { 411 aiFace face = ai_mesh->mFaces[idx_face]; 412 n_indices += face.mNumIndices; 413 } 414 415 mesh->n_indices = n_indices; 416 mesh->indices = (u32*)memory::push(&mesh->temp_memory_pool, 417 mesh->n_indices * sizeof(u32), "mesh_indices"); 418 u32 idx_index = 0; 419 420 for (u32 idx_face = 0; idx_face < ai_mesh->mNumFaces; idx_face++) { 421 aiFace face = ai_mesh->mFaces[idx_face]; 422 for ( 423 u32 idx_face_index = 0; 424 idx_face_index < face.mNumIndices; 425 idx_face_index++ 426 ) { 427 mesh->indices[idx_index++] = face.mIndices[idx_face_index]; 428 } 429 } 430 431 // Bones 432 assert(ai_mesh->mNumBones < MAX_N_BONES); 433 anim::Component *animation_component = &model_loader->animation_component; 434 range_named (idx_bone, 0, ai_mesh->mNumBones) { 435 aiBone *ai_bone = ai_mesh->mBones[idx_bone]; 436 u32 idx_found_bone = 0; 437 bool did_find_bone = false; 438 439 range_named (idx_animcomp_bone, 0, animation_component->n_bones) { 440 if (pstr_eq( 441 animation_component->bones[idx_animcomp_bone].name, ai_bone->mName.C_Str() 442 )) { 443 did_find_bone = true; 444 idx_found_bone = idx_animcomp_bone; 445 break; 446 } 447 } 448 449 assert(did_find_bone); 450 451 // NOTE: We really only need to do this once, but I honestly can't be 452 // bothered to add some mechanism to check if we already set it, it would 453 // just make things more complicated. We set it multiple times, whatever. 454 // It's the same value anyway. 455 animation_component->bones[idx_found_bone].offset = 456 util::aimatrix4x4_to_glm(&ai_bone->mOffsetMatrix); 457 458 range_named (idx_weight, 0, ai_bone->mNumWeights) { 459 u32 vertex_idx = ai_bone->mWeights[idx_weight].mVertexId; 460 f32 weight = ai_bone->mWeights[idx_weight].mWeight; 461 assert(vertex_idx < mesh->n_vertices); 462 range_named (idx_vertex_weight, 0, MAX_N_BONES_PER_VERTEX) { 463 // Put it in the next free space, if there is any. 464 if (mesh->vertices[vertex_idx].bone_weights[idx_vertex_weight] == 0) { 465 mesh->vertices[vertex_idx].bone_idxs[idx_vertex_weight] = idx_found_bone; 466 mesh->vertices[vertex_idx].bone_weights[idx_vertex_weight] = weight; 467 break; 468 } 469 } 470 } 471 } 472} 473 474 475void 476models::load_node( 477 ModelLoader *model_loader, 478 aiNode *node, const aiScene *scene, 479 m4 accumulated_transform, pack::Pack indices_pack 480) { 481 m4 node_transform = util::aimatrix4x4_to_glm(&node->mTransformation); 482 m4 transform = accumulated_transform * node_transform; 483 484 range (0, node->mNumMeshes) { 485 aiMesh *ai_mesh = scene->mMeshes[node->mMeshes[idx]]; 486 geom::Mesh *mesh = &model_loader->meshes[model_loader->n_meshes++]; 487 *mesh = {}; 488 load_mesh(mesh, ai_mesh, scene, model_loader, transform, indices_pack); 489 } 490 491 range (0, node->mNumChildren) { 492 pack::Pack new_indices_pack = indices_pack; 493 // NOTE: We can only store 4 bits per pack element. Our indices can be way 494 // bigger than that, but that's fine. We don't need that much precision. 495 // Just smash the number down to a u8. 496 pack::push(&new_indices_pack, (u8)idx); 497 load_node(model_loader, node->mChildren[idx], scene, transform, new_indices_pack); 498 } 499} 500 501 502void 503models::load_model_from_file(ModelLoader *model_loader) 504{ 505 // NOTE: This function stores its vertex data in the memory::Pool for each 506 // mesh, and so is intended to be called from a separate thread. 507 char full_path[MAX_PATH] = {}; 508 pstr_vcat(full_path, MAX_PATH, MODEL_DIR, model_loader->model_path, NULL); 509 510 START_TIMER(assimp_import); 511 auto flags = 512 aiProcess_Triangulate 513 | aiProcess_JoinIdenticalVertices 514 | aiProcess_SortByPType 515 | aiProcess_GenNormals 516 | aiProcess_FlipUVs 517 // NOTE: This might break something in the future, let's look out for it. 518 | aiProcess_OptimizeMeshes 519 // NOTE: Use with caution, goes full YOLO. 520 /* aiProcess_OptimizeGraph */ 521 /* | aiProcess_CalcTangentSpace */ 522 ; 523 const aiScene *scene = aiImportFile(full_path, flags); 524 END_TIMER(assimp_import); 525 526 if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { 527 logs::fatal("assimp error: %s", aiGetErrorString()); 528 return; 529 } 530 531 anim::Component *animation_component = &model_loader->animation_component; 532 load_bones(animation_component, scene); 533 load_node(model_loader, scene->mRootNode, scene, m4(1.0f), 0ULL); 534 load_animations(animation_component, scene); 535 aiReleaseImport(scene); 536 537 model_loader->state = ModelLoaderState::mesh_data_loaded; 538} 539 540 541void 542models::load_model_from_data(ModelLoader *model_loader) 543{ 544 // NOTE: This function sets up mesh vertex buffers directly, and so is 545 // intended to be called from the main OpenGL thread. 546 memory::Pool temp_memory_pool = {}; 547 548 geom::Vertex *vertex_data = nullptr; 549 u32 n_vertices = 0; 550 u32 *index_data = nullptr; 551 u32 n_indices = 0; 552 GLenum mode = 0; 553 554 if (pstr_eq(model_loader->model_path, "builtin:axes")) { 555 vertex_data = (geom::Vertex*)AXES_VERTICES; 556 n_vertices = 6; 557 index_data = nullptr; 558 n_indices = 0; 559 mode = GL_LINES; 560 } else if (pstr_eq(model_loader->model_path, "builtin:ocean")) { 561 geom::make_plane(&temp_memory_pool, 562 200, 200, 800, 800, &n_vertices, &n_indices, &vertex_data, &index_data); 563 mode = GL_TRIANGLES; 564 } else if (pstr_eq(model_loader->model_path, "builtin:skysphere")) { 565 geom::make_sphere(&temp_memory_pool, 566 64, 64, &n_vertices, &n_indices, &vertex_data, &index_data); 567 mode = GL_TRIANGLE_STRIP; 568 } else if ( 569 pstr_starts_with(model_loader->model_path, "builtin:screenquad") 570 ) { 571 vertex_data = (geom::Vertex*)SCREENQUAD_VERTICES; 572 n_vertices = 6; 573 index_data = nullptr; 574 n_indices = 0; 575 mode = GL_TRIANGLES; 576 } else { 577 logs::fatal("Could not find builtin model: %s", model_loader->model_path); 578 } 579 580 geom::Mesh *mesh = &model_loader->meshes[model_loader->n_meshes++]; 581 *mesh = {}; 582 mesh->transform = m4(1.0f); 583 mesh->mode = mode; 584 mesh->n_vertices = n_vertices; 585 mesh->n_indices = n_indices; 586 mesh->indices_pack = 0UL; 587 588 geom::setup_mesh_vertex_buffers(mesh, vertex_data, n_vertices, index_data, n_indices); 589 model_loader->state = ModelLoaderState::vertex_buffers_set_up; 590 591 memory::destroy_memory_pool(&temp_memory_pool); 592}