From f03ee01bc593ad2271f697bf286ebc04c91da0b1 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Tue, 13 Feb 2024 18:27:18 -0800 Subject: Make loaded scene node an anima node only if the scene has skins/skeletons. --- game/src/plugins/viewer.c | 8 ++++-- gfx/include/gfx/asset.h | 14 ++++++---- gfx/include/gfx/scene/node.h | 2 +- gfx/include/gfx/util/scene.h | 10 +++---- gfx/src/asset/asset_cache.c | 4 +-- gfx/src/scene/node.c | 4 +-- gfx/src/util/scene.c | 65 ++++++++++++++++++++++++++------------------ 7 files changed, 60 insertions(+), 47 deletions(-) diff --git a/game/src/plugins/viewer.c b/game/src/plugins/viewer.c index 3000b30..769887f 100644 --- a/game/src/plugins/viewer.c +++ b/game/src/plugins/viewer.c @@ -120,9 +120,11 @@ bool init(Game* game, State** pp_state) { goto cleanup; } - Anima* anima = gfx_get_node_anima(node); - gfx_play_animation( - anima, &(AnimationPlaySettings){.name = "Walk", .loop = true}); + if (gfx_get_node_type(node) == AnimaNode) { + Anima* anima = gfx_get_node_anima(node); + gfx_play_animation( + anima, &(AnimationPlaySettings){.name = "Walk", .loop = true}); + } *pp_state = state; return true; diff --git a/gfx/include/gfx/asset.h b/gfx/include/gfx/asset.h index 28b8557..c2bac57 100644 --- a/gfx/include/gfx/asset.h +++ b/gfx/include/gfx/asset.h @@ -68,6 +68,10 @@ typedef struct LoadTextureCmd { } LoadTextureCmd; /// Describes a command to load a scene. +/// +/// |shader| is an optional shader program assigned to the loaded scene objects. +/// If no shader is given, a Cook-Torrance shader based on the object's +/// characteristics (presence of normals, tangents, etc) is assigned. typedef struct LoadSceneCmd { AssetOrigin origin; union { @@ -84,15 +88,13 @@ typedef struct LoadSceneCmd { /// Load a scene. /// -/// Return a top-level node under which scene elements are rooted. |root_node| -/// is made the parent of this top-level node. +/// Return a top-level node under which scene elements are rooted. /// -/// |shader| is an optional shader program assigned to the loaded scene objects. -/// If no shader is given, a Cook-Torrance shader based on the object's -/// characteristics (presence of normals, tangents, etc) is assigned. +/// |parent_node| is made the parent of the returned top-level node. It may be +/// null. /// /// Currently only supports the GLTF format. -SceneNode* gfx_load_scene(Gfx*, SceneNode* root_node, const LoadSceneCmd*); +SceneNode* gfx_load_scene(Gfx*, SceneNode* parent_node, const LoadSceneCmd*); /// Load a texture. Texture* gfx_load_texture(Gfx*, const LoadTextureCmd*); diff --git a/gfx/include/gfx/scene/node.h b/gfx/include/gfx/scene/node.h index 9507392..aedac92 100644 --- a/gfx/include/gfx/scene/node.h +++ b/gfx/include/gfx/scene/node.h @@ -138,7 +138,7 @@ mat4 gfx_get_node_global_transform(const SceneNode*); /// Set the node's parent. /// /// Pass in null to unwire from the existing parent, if one exists. -void gfx_set_node_parent(SceneNode*, SceneNode* parent); +void gfx_set_node_parent(SceneNode*, SceneNode* parent_node); /// Set the node's (local) transform. void gfx_set_node_transform(SceneNode*, const mat4* transform); diff --git a/gfx/include/gfx/util/scene.h b/gfx/include/gfx/util/scene.h index c03e2cb..5c47196 100644 --- a/gfx/include/gfx/util/scene.h +++ b/gfx/include/gfx/util/scene.h @@ -8,12 +8,10 @@ typedef struct SceneNode SceneNode; /// Load a scene. /// -/// Return a top-level node under which scene elements are rooted. |root_node| -/// is made the parent of this top-level node. +/// Return the top-level node under which scene elements are rooted. /// -/// |shader| is an optional shader program assigned to the loaded scene objects. -/// If no shader is given, a Cook-Torrance shader based on the object's -/// characteristics (presence of normals, tangents, etc) is assigned. +/// |parent_node| is made the parent of the returned top-level node. It may be +/// null. /// /// Currently only supports the GLTF format. -SceneNode* gfx_scene_load(Gfx*, SceneNode* root_node, const LoadSceneCmd*); +SceneNode* gfx_scene_load(Gfx*, SceneNode* parent_node, const LoadSceneCmd*); diff --git a/gfx/src/asset/asset_cache.c b/gfx/src/asset/asset_cache.c index 2fa57ad..fd9f1f8 100644 --- a/gfx/src/asset/asset_cache.c +++ b/gfx/src/asset/asset_cache.c @@ -113,7 +113,7 @@ void gfx_destroy_asset_cache(AssetCache* cache) { } SceneNode* gfx_load_scene( - Gfx* gfx, SceneNode* root_node, const LoadSceneCmd* cmd) { + Gfx* gfx, SceneNode* parent_node, const LoadSceneCmd* cmd) { assert(gfx); AssetCache* cache = gfx_get_asset_cache(gfx); @@ -130,7 +130,7 @@ SceneNode* gfx_load_scene( // Asset not found in the cache. // Load it, insert it into the cache, and return it. - SceneNode* node = gfx_scene_load(gfx, root_node, cmd); + SceneNode* node = gfx_scene_load(gfx, parent_node, cmd); if (node) { *(Asset*)mempool_alloc(&cache->assets) = (Asset){ .type = SceneAsset, diff --git a/gfx/src/scene/node.c b/gfx/src/scene/node.c index 2f761a2..333dc28 100644 --- a/gfx/src/scene/node.c +++ b/gfx/src/scene/node.c @@ -271,10 +271,10 @@ mat4 gfx_get_node_global_transform(const SceneNode* node) { return transform; } -void gfx_set_node_parent(SceneNode* child, SceneNode* parent) { +void gfx_set_node_parent(SceneNode* child, SceneNode* parent_node) { assert(child); // Parent can be null. - SET_PARENT(child, parent); + SET_PARENT(child, parent_node); } void gfx_set_node_transform(SceneNode* node, const mat4* transform) { diff --git a/gfx/src/util/scene.c b/gfx/src/util/scene.c index 5bf45aa..a491238 100644 --- a/gfx/src/util/scene.c +++ b/gfx/src/util/scene.c @@ -1303,7 +1303,6 @@ static void load_nodes( assert(root_node); assert(objects); assert(cameras); - assert(anima); assert(nodes); cgltf_size next_camera = 0; @@ -1320,6 +1319,8 @@ static void load_nodes( gfx_construct_object_node(nodes[n], object); if (node->skin) { + assert(anima); + const cgltf_size skin_index = node->skin - data->skins; assert(skin_index < data->skins_count); const Skeleton* skeleton = gfx_get_anima_skeleton(anima, skin_index); @@ -1406,7 +1407,7 @@ static void load_nodes( /// This function ignores the many scenes and default scene of the glTF spec /// and instead just loads all scenes into a single gfx Scene. static SceneNode* load_scene( - cgltf_data* data, Gfx* gfx, SceneNode* root_node, const mstring* filepath, + cgltf_data* data, Gfx* gfx, SceneNode* parent_node, const mstring* filepath, ShaderProgram* shader, const cgltfTangentBuffer* cgltf_tangent_buffers, cgltf_size num_tangent_buffers) { // In a GLTF scene, buffers can be shared among meshes, meshes among nodes, @@ -1427,7 +1428,8 @@ static SceneNode* load_scene( // stage. assert(data); assert(gfx); - assert(root_node); + assert(filepath); + assert((num_tangent_buffers == 0) || (cgltf_tangent_buffers != 0)); bool success = false; @@ -1450,7 +1452,7 @@ static SceneNode* load_scene( SceneCamera** scene_cameras = 0; SceneNode** scene_nodes = 0; Anima* anima = 0; - SceneNode* anima_node = 0; + SceneNode* root_node = 0; tangent_buffers = calloc(num_tangent_buffers, sizeof(Buffer*)); buffers = calloc(data->buffers_count, sizeof(Buffer*)); @@ -1458,7 +1460,6 @@ static SceneNode* load_scene( materials = calloc(data->materials_count, sizeof(Material*)); geometries = calloc(primitive_count, sizeof(Geometry*)); meshes = calloc(primitive_count, sizeof(Mesh*)); - anima_desc = calloc(1, sizeof(AnimaDesc)); scene_objects = calloc(data->meshes_count, sizeof(SceneObject*)); scene_cameras = calloc(data->cameras_count, sizeof(SceneCamera**)); scene_nodes = calloc(data->nodes_count, sizeof(SceneNode**)); @@ -1511,22 +1512,30 @@ static SceneNode* load_scene( scene_nodes[i] = gfx_make_node(); } - // TODO: If the scene does not have animations, then a top-level LogicalNode - // would make more sense than an AnimaNode. - anima_node = gfx_make_node(); - load_skins(data, buffers, scene_nodes, anima_desc->skeletons); - load_animations(data, scene_nodes, anima_desc->animations); - anima_desc->num_skeletons = data->skins_count; - anima_desc->num_animations = data->animations_count; - anima = gfx_make_anima(anima_desc); - gfx_construct_anima_node(anima_node, anima); - gfx_set_node_parent(anima_node, root_node); + // Create the scene's root node. + // This is an anima node if the scene has skins; otherwise it is a logical + // node. + root_node = gfx_make_node(); + if (data->skins_count > 0) { + anima_desc = calloc(1, sizeof(AnimaDesc)); + if (!anima_desc) { + goto cleanup; + } + + load_skins(data, buffers, scene_nodes, anima_desc->skeletons); + load_animations(data, scene_nodes, anima_desc->animations); - // The anima node becomes the root of all scene nodes. - load_nodes( - data, anima_node, scene_objects, scene_cameras, anima, scene_nodes); + anima_desc->num_skeletons = data->skins_count; + anima_desc->num_animations = data->animations_count; + anima = gfx_make_anima(anima_desc); + gfx_construct_anima_node(root_node, anima); + } + gfx_set_node_parent(root_node, parent_node); + + // The root node becomes the root of all scene nodes. + load_nodes(data, root_node, scene_objects, scene_cameras, anima, scene_nodes); - success = anima_node != 0; + success = true; cleanup: // The arrays of resources are no longer needed. The resources themselves are @@ -1627,18 +1636,20 @@ cleanup: } free(scene_nodes); } - if (!success && anima_node) { - gfx_destroy_node(&anima_node); // Node owns the anima. - } else if (!success && anima) { - gfx_destroy_anima(&anima); + if (!success) { + if (root_node) { + gfx_destroy_node(&root_node); // Node owns the anima. + } else if (anima) { + gfx_destroy_anima(&anima); + } } - return anima_node; + return root_node; } SceneNode* gfx_scene_load( - Gfx* gfx, SceneNode* root_node, const LoadSceneCmd* cmd) { + Gfx* gfx, SceneNode* parent_node, const LoadSceneCmd* cmd) { assert(gfx); - assert(root_node); + assert(parent_node); assert(cmd); SceneNode* scene_node = 0; @@ -1674,7 +1685,7 @@ SceneNode* gfx_scene_load( &options, data, &tangent_buffers, &num_tangent_buffers); scene_node = load_scene( - data, gfx, root_node, &cmd->filepath, cmd->shader, tangent_buffers, + data, gfx, parent_node, &cmd->filepath, cmd->shader, tangent_buffers, num_tangent_buffers); cleanup: -- cgit v1.2.3