summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gfx/src/util/scene.c471
1 files changed, 156 insertions, 315 deletions
diff --git a/gfx/src/util/scene.c b/gfx/src/util/scene.c
index dc97259..706e518 100644
--- a/gfx/src/util/scene.c
+++ b/gfx/src/util/scene.c
@@ -207,80 +207,44 @@ static size_t get_total_primitives(const cgltf_data* data) {
207/// 207///
208/// Return an array of Buffers such that the index of each glTF buffer in 208/// Return an array of Buffers such that the index of each glTF buffer in
209/// the original array matches the same Buffer in the resulting array. 209/// the original array matches the same Buffer in the resulting array.
210static Buffer** load_buffers( 210static bool load_buffers(
211 const cgltf_data* data, RenderBackend* render_backend, 211 const cgltf_data* data, RenderBackend* render_backend, Buffer** buffers) {
212 cgltf_size* num_buffers) {
213 assert(data); 212 assert(data);
214 assert(render_backend); 213 assert(render_backend);
215 assert(num_buffers); 214 assert(buffers);
216
217 Buffer** buffers = 0;
218
219 buffers = calloc(data->buffers_count, sizeof(Buffer*));
220 if (!buffers) {
221 goto cleanup;
222 }
223 215
224 for (cgltf_size i = 0; i < data->buffers_count; ++i) { 216 for (cgltf_size i = 0; i < data->buffers_count; ++i) {
225 const cgltf_buffer* buffer = &data->buffers[i]; 217 const cgltf_buffer* buffer = &data->buffers[i];
226 assert(buffer->data); 218 assert(buffer->data);
227 buffers[i] = gfx_make_buffer(render_backend, buffer->data, buffer->size); 219 buffers[i] = gfx_make_buffer(render_backend, buffer->data, buffer->size);
228 if (!buffers[i]) { 220 if (!buffers[i]) {
229 goto cleanup; 221 return false;
230 } 222 }
231 } 223 }
232 *num_buffers = data->buffers_count;
233 return buffers;
234 224
235cleanup: 225 return true;
236 if (buffers) {
237 for (cgltf_size i = 0; i < data->buffers_count; ++i) {
238 if (buffers[i]) {
239 gfx_destroy_buffer(render_backend, &buffers[i]);
240 }
241 }
242 free(buffers);
243 }
244 *num_buffers = 0;
245 return 0;
246} 226}
247 227
248/// Load tangent buffers. 228/// Load tangent buffers.
249static Buffer** load_tangent_buffers( 229static bool load_tangent_buffers(
250 const cgltfTangentBuffer* tangent_buffers, cgltf_size num_tangent_buffers, 230 const cgltfTangentBuffer* cgltf_tangent_buffers,
251 RenderBackend* render_backend) { 231 cgltf_size num_tangent_buffers, RenderBackend* render_backend,
252 assert(tangent_buffers); 232 Buffer** tangent_buffers) {
233 assert(cgltf_tangent_buffers);
253 assert(render_backend); 234 assert(render_backend);
254 235 assert(tangent_buffers);
255 Buffer** buffers = 0;
256
257 buffers = calloc(num_tangent_buffers, sizeof(Buffer*));
258 if (!buffers) {
259 goto cleanup;
260 }
261 236
262 for (cgltf_size i = 0; i < num_tangent_buffers; ++i) { 237 for (cgltf_size i = 0; i < num_tangent_buffers; ++i) {
263 const cgltfTangentBuffer* buffer = &tangent_buffers[i]; 238 const cgltfTangentBuffer* buffer = &cgltf_tangent_buffers[i];
264 assert(buffer->data); 239 assert(buffer->data);
265 buffers[i] = 240 tangent_buffers[i] =
266 gfx_make_buffer(render_backend, buffer->data, buffer->size_bytes); 241 gfx_make_buffer(render_backend, buffer->data, buffer->size_bytes);
267 if (!buffers[i]) { 242 if (!tangent_buffers[i]) {
268 goto cleanup; 243 return false;
269 } 244 }
270 } 245 }
271 246
272 return buffers; 247 return true;
273
274cleanup:
275 if (buffers) {
276 for (cgltf_size i = 0; i < num_tangent_buffers; ++i) {
277 if (buffers[i]) {
278 gfx_destroy_buffer(render_backend, &buffers[i]);
279 }
280 }
281 free(buffers);
282 }
283 return 0;
284} 248}
285 249
286/// Lazily load all textures from the glTF scene. 250/// Lazily load all textures from the glTF scene.
@@ -294,24 +258,13 @@ cleanup:
294/// we know their colour space when loading glTF materials. 258/// we know their colour space when loading glTF materials.
295/// 259///
296/// Return an array of LoadTextureCmds such that the index of each cmd matches 260/// Return an array of LoadTextureCmds such that the index of each cmd matches
297/// the index of each glTF texture in the scene. Also return the number of 261/// the index of each glTF texture in the scene.
298/// textures. 262static void load_textures_lazy(
299///
300/// Return true on success (all textures processed or no textures in the
301/// scene), false otherwise.
302static bool load_textures_lazy(
303 const cgltf_data* data, RenderBackend* render_backend, 263 const cgltf_data* data, RenderBackend* render_backend,
304 const char* directory, LoadTextureCmd** load_texture_cmds, 264 const char* directory, LoadTextureCmd* load_texture_cmds) {
305 cgltf_size* num_textures) {
306 assert(data); 265 assert(data);
307 assert(render_backend); 266 assert(render_backend);
308 assert(load_texture_cmds); 267 assert(load_texture_cmds);
309 assert(num_textures);
310
311 *load_texture_cmds = calloc(data->textures_count, sizeof(LoadTextureCmd));
312 if (!*load_texture_cmds) {
313 goto cleanup;
314 }
315 268
316 for (cgltf_size i = 0; i < data->textures_count; ++i) { 269 for (cgltf_size i = 0; i < data->textures_count; ++i) {
317 const cgltf_texture* texture = &data->textures[i]; 270 const cgltf_texture* texture = &data->textures[i];
@@ -359,7 +312,7 @@ static bool load_textures_lazy(
359 mstring fullpath = 312 mstring fullpath =
360 mstring_concat_path(mstring_make(directory), mstring_make(image->uri)); 313 mstring_concat_path(mstring_make(directory), mstring_make(image->uri));
361 314
362 (*load_texture_cmds)[i] = (LoadTextureCmd){ 315 load_texture_cmds[i] = (LoadTextureCmd){
363 .origin = TextureFromFile, 316 .origin = TextureFromFile,
364 .type = LoadTexture, 317 .type = LoadTexture,
365 .colour_space = sRGB, 318 .colour_space = sRGB,
@@ -368,16 +321,6 @@ static bool load_textures_lazy(
368 .mipmaps = mipmaps, 321 .mipmaps = mipmaps,
369 .data.texture.filepath = fullpath}; 322 .data.texture.filepath = fullpath};
370 } 323 }
371
372 *num_textures = data->textures_count;
373 return true;
374
375cleanup:
376 if (*load_texture_cmds) {
377 free(*load_texture_cmds);
378 }
379 *num_textures = 0;
380 return false;
381} 324}
382 325
383/// Load a texture uniform. 326/// Load a texture uniform.
@@ -438,25 +381,15 @@ static bool load_texture_and_uniform(
438/// Return an array of Materials such that the index of each descriptor matches 381/// Return an array of Materials such that the index of each descriptor matches
439/// the index of each glTF material in the scene. Also return the number of 382/// the index of each glTF material in the scene. Also return the number of
440/// materials and the textures used by them. 383/// materials and the textures used by them.
441static Material** load_materials( 384static bool load_materials(
442 const cgltf_data* data, RenderBackend* render_backend, 385 const cgltf_data* data, RenderBackend* render_backend,
443 LoadTextureCmd* load_texture_cmds, Texture*** textures, 386 LoadTextureCmd* load_texture_cmds, Texture** textures,
444 cgltf_size* num_materials) { 387 Material** materials) {
445 assert(data); 388 assert(data);
446 assert(render_backend); 389 assert(render_backend);
447 assert(load_texture_cmds); 390 assert(load_texture_cmds);
448 assert(textures); 391 assert(textures);
449 assert(num_materials); 392 assert(materials);
450
451 Material** materials = calloc(data->materials_count, sizeof(Material*));
452 if (!materials) {
453 goto cleanup;
454 }
455
456 *textures = calloc(data->textures_count, sizeof(Texture*));
457 if (!*textures) {
458 goto cleanup;
459 }
460 393
461 for (cgltf_size i = 0; i < data->materials_count; ++i) { 394 for (cgltf_size i = 0; i < data->materials_count; ++i) {
462 const cgltf_material* mat = &data->materials[i]; 395 const cgltf_material* mat = &data->materials[i];
@@ -495,18 +428,18 @@ static Material** load_materials(
495 if (pbr->base_color_texture.texture) { 428 if (pbr->base_color_texture.texture) {
496 if (!load_texture_and_uniform( 429 if (!load_texture_and_uniform(
497 data, render_backend, &pbr->base_color_texture, 430 data, render_backend, &pbr->base_color_texture,
498 BaseColorTexture, *textures, load_texture_cmds, &next_uniform, 431 BaseColorTexture, textures, load_texture_cmds, &next_uniform,
499 &desc)) { 432 &desc)) {
500 goto cleanup; 433 return false;
501 } 434 }
502 } 435 }
503 436
504 if (pbr->metallic_roughness_texture.texture) { 437 if (pbr->metallic_roughness_texture.texture) {
505 if (!load_texture_and_uniform( 438 if (!load_texture_and_uniform(
506 data, render_backend, &pbr->metallic_roughness_texture, 439 data, render_backend, &pbr->metallic_roughness_texture,
507 MetallicRoughnessTexture, *textures, load_texture_cmds, 440 MetallicRoughnessTexture, textures, load_texture_cmds,
508 &next_uniform, &desc)) { 441 &next_uniform, &desc)) {
509 goto cleanup; 442 return false;
510 } 443 }
511 } 444 }
512 } 445 }
@@ -514,25 +447,25 @@ static Material** load_materials(
514 if (mat->emissive_texture.texture) { 447 if (mat->emissive_texture.texture) {
515 if (!load_texture_and_uniform( 448 if (!load_texture_and_uniform(
516 data, render_backend, &mat->emissive_texture, EmissiveTexture, 449 data, render_backend, &mat->emissive_texture, EmissiveTexture,
517 *textures, load_texture_cmds, &next_uniform, &desc)) { 450 textures, load_texture_cmds, &next_uniform, &desc)) {
518 goto cleanup; 451 return false;
519 } 452 }
520 } 453 }
521 454
522 if (mat->occlusion_texture.texture) { 455 if (mat->occlusion_texture.texture) {
523 if (!load_texture_and_uniform( 456 if (!load_texture_and_uniform(
524 data, render_backend, &mat->occlusion_texture, 457 data, render_backend, &mat->occlusion_texture,
525 AmbientOcclusionTexture, *textures, load_texture_cmds, 458 AmbientOcclusionTexture, textures, load_texture_cmds,
526 &next_uniform, &desc)) { 459 &next_uniform, &desc)) {
527 goto cleanup; 460 return false;
528 } 461 }
529 } 462 }
530 463
531 if (mat->normal_texture.texture) { 464 if (mat->normal_texture.texture) {
532 if (!load_texture_and_uniform( 465 if (!load_texture_and_uniform(
533 data, render_backend, &mat->normal_texture, NormalMap, *textures, 466 data, render_backend, &mat->normal_texture, NormalMap, textures,
534 load_texture_cmds, &next_uniform, &desc)) { 467 load_texture_cmds, &next_uniform, &desc)) {
535 goto cleanup; 468 return false;
536 } 469 }
537 } 470 }
538 471
@@ -541,42 +474,20 @@ static Material** load_materials(
541 474
542 materials[i] = gfx_make_material(&desc); 475 materials[i] = gfx_make_material(&desc);
543 if (!materials[i]) { 476 if (!materials[i]) {
544 goto cleanup; 477 return false;
545 } 478 }
546 } 479 }
547 480
548 *num_materials = data->materials_count; 481 return true;
549 return materials;
550
551cleanup:
552 if (materials) {
553 for (cgltf_size i = 0; i < data->materials_count; ++i) {
554 if (materials[i]) {
555 gfx_destroy_material(&materials[i]);
556 }
557 }
558 free(materials);
559 }
560 if (*textures) {
561 for (cgltf_size i = 0; i < data->textures_count; ++i) {
562 if ((*textures)[i]) {
563 gfx_destroy_texture(render_backend, &(*textures)[i]);
564 }
565 }
566 free(*textures);
567 *textures = 0;
568 }
569 *num_materials = 0;
570 return 0;
571} 482}
572 483
573/// Load all meshes from the glTF scene. 484/// Load all meshes from the glTF scene.
574static SceneObject** load_meshes( 485static bool load_meshes(
575 const cgltf_data* data, Gfx* gfx, Buffer** buffers, 486 const cgltf_data* data, Gfx* gfx, Buffer** buffers,
576 Buffer** tangent_buffers, const cgltfTangentBuffer* cgltf_tangent_buffers, 487 Buffer** tangent_buffers, const cgltfTangentBuffer* cgltf_tangent_buffers,
577 cgltf_size num_tangent_buffers, Material** materials, ShaderProgram* shader, 488 cgltf_size num_tangent_buffers, Material** materials, ShaderProgram* shader,
578 Geometry*** geometries, Mesh*** meshes, cgltf_size* num_geometries, 489 size_t primitive_count, Geometry** geometries, Mesh** meshes,
579 cgltf_size* num_meshes, cgltf_size* num_scene_objects) { 490 SceneObject** scene_objects) {
580 // Walk through the mesh primitives to create Meshes. A GLTF mesh primitive 491 // Walk through the mesh primitives to create Meshes. A GLTF mesh primitive
581 // has a material (Mesh) and vertex data (Geometry). A GLTF mesh maps to 492 // has a material (Mesh) and vertex data (Geometry). A GLTF mesh maps to
582 // a SceneObject. 493 // a SceneObject.
@@ -594,9 +505,7 @@ static SceneObject** load_meshes(
594 assert(shader); 505 assert(shader);
595 assert(geometries); 506 assert(geometries);
596 assert(meshes); 507 assert(meshes);
597 assert(num_geometries); 508 assert(scene_objects);
598 assert(num_meshes);
599 assert(num_scene_objects);
600 if (num_tangent_buffers > 0) { 509 if (num_tangent_buffers > 0) {
601 assert(tangent_buffers); 510 assert(tangent_buffers);
602 assert(cgltf_tangent_buffers); 511 assert(cgltf_tangent_buffers);
@@ -605,21 +514,6 @@ static SceneObject** load_meshes(
605 // TODO: pass render_backend as argument instead of gfx. 514 // TODO: pass render_backend as argument instead of gfx.
606 RenderBackend* render_backend = gfx_get_render_backend(gfx); 515 RenderBackend* render_backend = gfx_get_render_backend(gfx);
607 516
608 const size_t primitive_count = get_total_primitives(data);
609
610 *geometries = calloc(primitive_count, sizeof(Geometry*));
611 if (!*geometries) {
612 goto cleanup;
613 }
614 *meshes = calloc(primitive_count, sizeof(Mesh*));
615 if (!*meshes) {
616 goto cleanup;
617 }
618 SceneObject** objects = calloc(data->meshes_count, sizeof(SceneObject*));
619 if (!objects) {
620 goto cleanup;
621 }
622
623 // Points to the next available Mesh and also the next available Geometry. 517 // Points to the next available Mesh and also the next available Geometry.
624 // There is one (Mesh, Geometry) pair per glTF mesh primitive. 518 // There is one (Mesh, Geometry) pair per glTF mesh primitive.
625 size_t next_mesh = 0; 519 size_t next_mesh = 0;
@@ -627,9 +521,9 @@ static SceneObject** load_meshes(
627 for (cgltf_size m = 0; m < data->meshes_count; ++m) { 521 for (cgltf_size m = 0; m < data->meshes_count; ++m) {
628 const cgltf_mesh* mesh = &data->meshes[m]; 522 const cgltf_mesh* mesh = &data->meshes[m];
629 523
630 objects[m] = gfx_make_object(); 524 scene_objects[m] = gfx_make_object();
631 if (!objects[m]) { 525 if (!scene_objects[m]) {
632 goto cleanup; 526 return false;
633 } 527 }
634 528
635 for (cgltf_size p = 0; p < mesh->primitives_count; ++p) { 529 for (cgltf_size p = 0; p < mesh->primitives_count; ++p) {
@@ -689,7 +583,7 @@ static SceneObject** load_meshes(
689 "Unhandled accessor type %d in vertex positions", 583 "Unhandled accessor type %d in vertex positions",
690 accessor->type); 584 accessor->type);
691 assert(false); 585 assert(false);
692 break; 586 return false;
693 } 587 }
694 // It is assumed that meshes have positions, so there is nothing to 588 // It is assumed that meshes have positions, so there is nothing to
695 // do for the mesh permutation in this case. 589 // do for the mesh permutation in this case.
@@ -776,16 +670,9 @@ static SceneObject** load_meshes(
776 assert(material_index < data->materials_count); 670 assert(material_index < data->materials_count);
777 Material* material = materials[material_index]; 671 Material* material = materials[material_index];
778 672
779 // TODO: We need a better way to handle clean-up, specifically of 673 geometries[next_mesh] = gfx_make_geometry(render_backend, &geometry_desc);
780 // materials. One is to add materials to a dynamically-allocated list or 674 if (!geometries[next_mesh]) {
781 // vector. Another is to expose some kind of scene purge that deletes the 675 return false;
782 // resources of a given scene. The latter would make clean-up much simpler
783 // in general, not just for materials.
784
785 (*geometries)[next_mesh] =
786 gfx_make_geometry(render_backend, &geometry_desc);
787 if (!(*geometries)[next_mesh]) {
788 goto cleanup;
789 } 676 }
790 677
791 // If the user specifies a custom shader, use that instead. 678 // If the user specifies a custom shader, use that instead.
@@ -802,65 +689,31 @@ static SceneObject** load_meshes(
802 // swapping shaders, so shader caching is the most important thing here. 689 // swapping shaders, so shader caching is the most important thing here.
803 assert(shader); 690 assert(shader);
804 691
805 (*meshes)[next_mesh] = gfx_make_mesh(&(MeshDesc){ 692 meshes[next_mesh] = gfx_make_mesh(&(MeshDesc){
806 .geometry = (*geometries)[next_mesh], 693 .geometry = geometries[next_mesh],
807 .material = material, 694 .material = material,
808 .shader = shader}); 695 .shader = shader});
809 696
810 gfx_add_object_mesh(objects[m], (*meshes)[next_mesh]); 697 if (!meshes[next_mesh]) {
698 return false;
699 }
700
701 gfx_add_object_mesh(scene_objects[m], meshes[next_mesh]);
811 702
812 ++next_mesh; 703 ++next_mesh;
813 } // glTF mesh primitive / gfx Mesh. 704 } // glTF mesh primitive / gfx Mesh.
814 } // glTF mesh / gfx SceneObject. 705 } // glTF mesh / gfx SceneObject.
815 706
816 *num_geometries = primitive_count; 707 return true;
817 *num_meshes = primitive_count;
818 *num_scene_objects = data->meshes_count;
819 return objects;
820
821cleanup:
822 // Destroy resources, free pointers arrays.
823 if (*geometries) {
824 for (size_t i = 0; i < primitive_count; ++i) {
825 if ((*geometries)[i]) {
826 gfx_destroy_geometry(render_backend, &(*geometries[i]));
827 }
828 }
829 free(*geometries);
830 *geometries = 0;
831 }
832 if (*meshes) {
833 for (size_t i = 0; i < primitive_count; ++i) {
834 if ((*meshes[i])) {
835 gfx_destroy_mesh(&(*meshes)[i]);
836 }
837 }
838 free(*meshes);
839 *meshes = 0;
840 }
841 if (objects) {
842 for (cgltf_size i = 0; i < data->meshes_count; ++i) {
843 if (objects[i]) {
844 gfx_destroy_object(&objects[i]);
845 }
846 }
847 free(objects);
848 objects = 0;
849 }
850 *num_geometries = 0;
851 *num_meshes = 0;
852 *num_scene_objects = 0;
853 return 0;
854} 708}
855 709
856/// Load all nodes from the glTF scene. 710/// Load all nodes from the glTF scene.
857/// 711///
858/// This function ignores the many scenes and default scene of the glTF spec 712/// This function ignores the many scenes and default scene of the glTF spec
859/// and instead just loads all nodes into a single gfx Scene. 713/// and instead just loads all nodes into a single gfx Scene.
860static SceneNode** load_nodes( 714static void load_nodes(
861 const cgltf_data* data, Gfx* gfx, SceneNode* root_node, 715 const cgltf_data* data, Gfx* gfx, SceneNode* root_node,
862 SceneObject** scene_objects, SceneCamera*** cameras, 716 SceneObject** objects, SceneCamera** cameras, SceneNode** nodes) {
863 cgltf_size* num_cameras, cgltf_size* num_nodes) {
864 // Note that with glTF 2.0, nodes do not form a DAG / scene graph but a 717 // Note that with glTF 2.0, nodes do not form a DAG / scene graph but a
865 // disjount union of strict trees: 718 // disjount union of strict trees:
866 // 719 //
@@ -876,19 +729,9 @@ static SceneNode** load_nodes(
876 // TODO: gfx not needed? 729 // TODO: gfx not needed?
877 assert(gfx); 730 assert(gfx);
878 assert(root_node); 731 assert(root_node);
879 assert(scene_objects); 732 assert(objects);
880 assert(cameras); 733 assert(cameras);
881 assert(num_cameras); 734 assert(nodes);
882 assert(num_nodes);
883
884 SceneNode** nodes = calloc(data->nodes_count, sizeof(SceneNode**));
885 if (!nodes) {
886 goto cleanup;
887 }
888 *cameras = calloc(data->cameras_count, sizeof(SceneCamera**));
889 if (!*cameras) {
890 goto cleanup;
891 }
892 735
893 cgltf_size next_camera = 0; 736 cgltf_size next_camera = 0;
894 737
@@ -902,7 +745,7 @@ static SceneNode** load_nodes(
902 if (node->mesh) { 745 if (node->mesh) {
903 const cgltf_size mesh_index = node->mesh - data->meshes; 746 const cgltf_size mesh_index = node->mesh - data->meshes;
904 assert(mesh_index < data->meshes_count); 747 assert(mesh_index < data->meshes_count);
905 nodes[n] = gfx_make_object_node(scene_objects[mesh_index]); 748 nodes[n] = gfx_make_object_node(objects[mesh_index]);
906 } else if (node->camera) { 749 } else if (node->camera) {
907 assert(next_camera < data->cameras_count); 750 assert(next_camera < data->cameras_count);
908 751
@@ -927,8 +770,8 @@ static SceneNode** load_nodes(
927 break; 770 break;
928 } 771 }
929 772
930 gfx_set_camera_camera((*cameras)[next_camera], &camera); 773 gfx_set_camera_camera(cameras[next_camera], &camera);
931 nodes[n] = gfx_make_camera_node((*cameras)[next_camera]); 774 nodes[n] = gfx_make_camera_node(cameras[next_camera]);
932 ++next_camera; 775 ++next_camera;
933 } else { 776 } else {
934 continue; // TODO: implementation for missing node types. 777 continue; // TODO: implementation for missing node types.
@@ -977,32 +820,6 @@ static SceneNode** load_nodes(
977 gfx_set_node_parent(child_scene_node, parent_scene_node); 820 gfx_set_node_parent(child_scene_node, parent_scene_node);
978 } 821 }
979 } 822 }
980
981 *num_cameras = data->cameras_count;
982 *num_nodes = data->nodes_count;
983 return nodes;
984
985cleanup:
986 // Destroy resources, free pointers arrays.
987 if (nodes) {
988 for (cgltf_size i = 0; i < data->nodes_count; ++i) {
989 if (nodes[i]) {
990 gfx_destroy_node(&nodes[i]);
991 }
992 }
993 free(nodes);
994 }
995 if (cameras) {
996 for (cgltf_size i = 0; i < data->cameras_count; ++i) {
997 if (cameras[i]) {
998 gfx_destroy_camera(&(*cameras)[i]);
999 }
1000 }
1001 free(cameras);
1002 }
1003 *num_cameras = 0;
1004 *num_nodes = 0;
1005 return 0;
1006} 823}
1007 824
1008/// Load all scenes from the glTF file into the given gfx Scene. 825/// Load all scenes from the glTF file into the given gfx Scene.
@@ -1015,143 +832,167 @@ static bool load_scene(
1015 cgltf_data* data, Gfx* gfx, SceneNode* root_node, const char* filepath, 832 cgltf_data* data, Gfx* gfx, SceneNode* root_node, const char* filepath,
1016 ShaderProgram* shader, const cgltfTangentBuffer* cgltf_tangent_buffers, 833 ShaderProgram* shader, const cgltfTangentBuffer* cgltf_tangent_buffers,
1017 cgltf_size num_tangent_buffers) { 834 cgltf_size num_tangent_buffers) {
1018 /// In a GLTF scene, buffers can be shared among meshes, meshes among nodes, 835 // In a GLTF scene, buffers can be shared among meshes, meshes among nodes,
1019 /// etc. Each object is referenced by its index in the relevant array. Here we 836 // etc. Each object is referenced by its index in the relevant array. Here we
1020 /// do a button-up construction, first allocating our own graphics objects in 837 // do a button-up construction, first allocating our own graphics objects in
1021 /// the same quantities and then re-using the GLTF indices to index these 838 // the same quantities and then re-using the GLTF indices to index these
1022 /// arrays. 839 // arrays.
840 //
841 // For simplicity, this function also handles all of the cleanup. Arrays are
842 // allocated up front, and the helper functions construct their elements. If
843 // an error is encountered, the helper functions can simply return and this
844 // function cleans up any intermediate objects that had been created up until
845 // the point of failure.
1023 assert(data); 846 assert(data);
1024 assert(gfx); 847 assert(gfx);
1025 assert(root_node); 848 assert(root_node);
1026 849
1027 RenderBackend* render_backend = gfx_get_render_backend(gfx); 850 RenderBackend* render_backend = gfx_get_render_backend(gfx);
851 const size_t primitive_count = get_total_primitives(data);
1028 852
1029 const mstring directory = mstring_dirname(mstring_make(filepath)); 853 const mstring directory = mstring_dirname(mstring_make(filepath));
1030 LOGD("Filepath: %s", filepath); 854 LOGD("Filepath: %s", filepath);
1031 LOGD("Directory: %s", mstring_cstring(&directory)); 855 LOGD("Directory: %s", mstring_cstring(&directory));
1032 856
1033 Buffer** buffers = 0;
1034 Buffer** tangent_buffers = 0; 857 Buffer** tangent_buffers = 0;
1035 Geometry** geometries = 0; 858 Buffer** buffers = 0;
859 LoadTextureCmd* load_texture_cmds = 0;
860 Texture** textures = 0;
1036 Material** materials = 0; 861 Material** materials = 0;
862 Geometry** geometries = 0;
1037 Mesh** meshes = 0; 863 Mesh** meshes = 0;
1038 SceneObject** scene_objects = 0; 864 SceneObject** scene_objects = 0;
1039 SceneCamera** scene_cameras = 0; 865 SceneCamera** scene_cameras = 0;
1040 SceneNode** scene_nodes = 0; 866 SceneNode** scene_nodes = 0;
1041 Texture** textures = 0; 867
1042 LoadTextureCmd* load_texture_cmds = 0; 868 tangent_buffers = calloc(num_tangent_buffers, sizeof(Buffer*));
1043 cgltf_size num_buffers = 0; 869 buffers = calloc(data->buffers_count, sizeof(Buffer*));
1044 cgltf_size num_geometries = 0; 870 textures = calloc(data->textures_count, sizeof(Texture*));
1045 cgltf_size num_materials = 0; 871 materials = calloc(data->materials_count, sizeof(Material*));
1046 cgltf_size num_meshes = 0; 872 geometries = calloc(primitive_count, sizeof(Geometry*));
1047 cgltf_size num_scene_objects = 0; 873 meshes = calloc(primitive_count, sizeof(Mesh*));
1048 cgltf_size num_scene_cameras = 0; 874 scene_objects = calloc(data->meshes_count, sizeof(SceneObject*));
1049 cgltf_size num_scene_nodes = 0; 875 scene_cameras = calloc(data->cameras_count, sizeof(SceneCamera**));
1050 cgltf_size num_textures = 0; 876 scene_nodes = calloc(data->nodes_count, sizeof(SceneNode**));
1051 877 // A glTF scene does not necessarily have textures. Materials can be given
1052 // TODO: Let this function handle all the cleanup. Let the other functions 878 // as constants, for example.
1053 // return pass/failure booleans and the arrays as in/out parameters. This way 879 if (data->textures_count > 0) {
1054 // we do not need the individual functions to duplicate cleanup code. 880 load_texture_cmds = calloc(data->textures_count, sizeof(LoadTextureCmd));
1055 buffers = load_buffers(data, render_backend, &num_buffers);
1056 if (!buffers) {
1057 goto cleanup;
1058 } 881 }
1059 882
1060 if (num_tangent_buffers > 0) { 883 if (!buffers || !tangent_buffers ||
1061 tangent_buffers = load_tangent_buffers( 884 ((data->textures_count > 0) && !load_texture_cmds) || !textures ||
1062 cgltf_tangent_buffers, num_tangent_buffers, render_backend); 885 !materials || !geometries || !meshes || !scene_objects ||
1063 if (!tangent_buffers) { 886 !scene_cameras || !scene_nodes) {
1064 goto cleanup; 887 goto cleanup;
1065 }
1066 } 888 }
1067 889
1068 if (!load_textures_lazy( 890 if ((num_tangent_buffers > 0) &&
1069 data, render_backend, mstring_cstring(&directory), &load_texture_cmds, 891 !load_tangent_buffers(
1070 &num_textures)) { 892 cgltf_tangent_buffers, num_tangent_buffers, render_backend,
893 tangent_buffers)) {
1071 goto cleanup; 894 goto cleanup;
1072 } 895 }
1073 896
1074 materials = load_materials( 897 if (!load_buffers(data, render_backend, buffers)) {
1075 data, render_backend, load_texture_cmds, &textures, &num_materials);
1076 if (!materials) {
1077 goto cleanup; 898 goto cleanup;
1078 } 899 }
1079 900
1080 scene_objects = load_meshes( 901 load_textures_lazy(
1081 data, gfx, buffers, tangent_buffers, cgltf_tangent_buffers, 902 data, render_backend, mstring_cstring(&directory), load_texture_cmds);
1082 num_tangent_buffers, materials, shader, &geometries, &meshes, 903
1083 &num_geometries, &num_meshes, &num_scene_objects); 904 if (!load_materials(
1084 if (!scene_objects) { 905 data, render_backend, load_texture_cmds, textures, materials)) {
1085 goto cleanup; 906 goto cleanup;
1086 } 907 }
1087 908
1088 scene_nodes = load_nodes( 909 if (!load_meshes(
1089 data, gfx, root_node, scene_objects, &scene_cameras, &num_scene_cameras, 910 data, gfx, buffers, tangent_buffers, cgltf_tangent_buffers,
1090 &num_scene_nodes); 911 num_tangent_buffers, materials, shader, primitive_count, geometries,
1091 if (!scene_nodes) { 912 meshes, scene_objects)) {
1092 goto cleanup; 913 goto cleanup;
1093 } 914 }
1094 915
916 load_nodes(data, gfx, root_node, scene_objects, scene_cameras, scene_nodes);
917
1095 return true; 918 return true;
1096 919
1097cleanup: 920cleanup:
1098 if (buffers) {
1099 for (cgltf_size i = 0; i < num_buffers; ++i) {
1100 gfx_destroy_buffer(render_backend, &buffers[i]);
1101 }
1102 free(buffers);
1103 }
1104 if (tangent_buffers) { 921 if (tangent_buffers) {
1105 for (cgltf_size i = 0; i < num_tangent_buffers; ++i) { 922 for (cgltf_size i = 0; i < num_tangent_buffers; ++i) {
1106 gfx_destroy_buffer(render_backend, &tangent_buffers[i]); 923 if (tangent_buffers[i]) {
924 gfx_destroy_buffer(render_backend, &tangent_buffers[i]);
925 }
1107 } 926 }
1108 free(tangent_buffers); 927 free(tangent_buffers);
1109 } 928 }
929 if (buffers) {
930 for (cgltf_size i = 0; i < data->buffers_count; ++i) {
931 if (buffers[i]) {
932 gfx_destroy_buffer(render_backend, &buffers[i]);
933 }
934 }
935 free(buffers);
936 }
937 if (load_texture_cmds) {
938 free(load_texture_cmds);
939 }
1110 if (textures) { 940 if (textures) {
1111 for (cgltf_size i = 0; i < num_textures; ++i) { 941 for (cgltf_size i = 0; i < data->textures_count; ++i) {
1112 gfx_destroy_texture(render_backend, &textures[i]); 942 if (textures[i]) {
943 gfx_destroy_texture(render_backend, &textures[i]);
944 }
1113 } 945 }
1114 free(textures); 946 free(textures);
1115 } 947 }
1116 if (materials) { 948 if (materials) {
1117 for (cgltf_size i = 0; i < num_materials; ++i) { 949 for (cgltf_size i = 0; i < data->materials_count; ++i) {
1118 gfx_destroy_material(&materials[i]); 950 if (materials[i]) {
951 gfx_destroy_material(&materials[i]);
952 }
1119 } 953 }
1120 free(materials); 954 free(materials);
1121 } 955 }
1122 if (geometries) { 956 if (geometries) {
1123 for (cgltf_size i = 0; i < num_geometries; ++i) { 957 for (size_t i = 0; i < primitive_count; ++i) {
1124 gfx_destroy_geometry(render_backend, &geometries[i]); 958 if (geometries[i]) {
959 gfx_destroy_geometry(render_backend, &geometries[i]);
960 }
1125 } 961 }
1126 free(geometries); 962 free(geometries);
1127 } 963 }
1128 if (meshes) { 964 if (meshes) {
1129 for (cgltf_size i = 0; i < num_meshes; ++i) { 965 for (size_t i = 0; i < primitive_count; ++i) {
1130 gfx_destroy_mesh(&meshes[i]); 966 if (meshes[i]) {
967 gfx_destroy_mesh(&meshes[i]);
968 }
1131 } 969 }
1132 free(meshes); 970 free(meshes);
1133 } 971 }
1134 if (scene_objects) { 972 if (scene_objects) {
1135 for (cgltf_size i = 0; i < num_scene_objects; ++i) { 973 for (cgltf_size i = 0; i < data->meshes_count; ++i) {
1136 gfx_destroy_object(&scene_objects[i]); 974 if (scene_objects[i]) {
975 gfx_destroy_object(&scene_objects[i]);
976 }
1137 } 977 }
1138 free(scene_objects); 978 free(scene_objects);
1139 } 979 }
1140 if (scene_cameras) { 980 if (scene_cameras) {
1141 for (cgltf_size i = 0; i < num_scene_cameras; ++i) { 981 for (cgltf_size i = 0; i < data->cameras_count; ++i) {
1142 gfx_destroy_camera(&scene_cameras[i]); 982 if (scene_cameras[i]) {
983 gfx_destroy_camera(&scene_cameras[i]);
984 }
1143 } 985 }
1144 free(scene_cameras); 986 free(scene_cameras);
1145 } 987 }
1146 if (scene_nodes) { 988 if (scene_nodes) {
1147 for (cgltf_size i = 0; i < num_scene_nodes; ++i) { 989 for (cgltf_size i = 0; i < data->nodes_count; ++i) {
1148 gfx_destroy_node(&scene_nodes[i]); 990 if (scene_nodes[i]) {
991 gfx_destroy_node(&scene_nodes[i]);
992 }
1149 } 993 }
1150 free(scene_nodes); 994 free(scene_nodes);
1151 } 995 }
1152 if (load_texture_cmds) {
1153 free(load_texture_cmds);
1154 }
1155 return false; 996 return false;
1156} 997}
1157 998