diff options
| -rw-r--r-- | game/src/plugins/viewer.c | 8 | ||||
| -rw-r--r-- | gfx/include/gfx/asset.h | 14 | ||||
| -rw-r--r-- | gfx/include/gfx/scene/node.h | 2 | ||||
| -rw-r--r-- | gfx/include/gfx/util/scene.h | 10 | ||||
| -rw-r--r-- | gfx/src/asset/asset_cache.c | 4 | ||||
| -rw-r--r-- | gfx/src/scene/node.c | 4 | ||||
| -rw-r--r-- | 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) { | |||
| 120 | goto cleanup; | 120 | goto cleanup; |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | Anima* anima = gfx_get_node_anima(node); | 123 | if (gfx_get_node_type(node) == AnimaNode) { |
| 124 | gfx_play_animation( | 124 | Anima* anima = gfx_get_node_anima(node); |
| 125 | anima, &(AnimationPlaySettings){.name = "Walk", .loop = true}); | 125 | gfx_play_animation( |
| 126 | anima, &(AnimationPlaySettings){.name = "Walk", .loop = true}); | ||
| 127 | } | ||
| 126 | 128 | ||
| 127 | *pp_state = state; | 129 | *pp_state = state; |
| 128 | return true; | 130 | 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 { | |||
| 68 | } LoadTextureCmd; | 68 | } LoadTextureCmd; |
| 69 | 69 | ||
| 70 | /// Describes a command to load a scene. | 70 | /// Describes a command to load a scene. |
| 71 | /// | ||
| 72 | /// |shader| is an optional shader program assigned to the loaded scene objects. | ||
| 73 | /// If no shader is given, a Cook-Torrance shader based on the object's | ||
| 74 | /// characteristics (presence of normals, tangents, etc) is assigned. | ||
| 71 | typedef struct LoadSceneCmd { | 75 | typedef struct LoadSceneCmd { |
| 72 | AssetOrigin origin; | 76 | AssetOrigin origin; |
| 73 | union { | 77 | union { |
| @@ -84,15 +88,13 @@ typedef struct LoadSceneCmd { | |||
| 84 | 88 | ||
| 85 | /// Load a scene. | 89 | /// Load a scene. |
| 86 | /// | 90 | /// |
| 87 | /// Return a top-level node under which scene elements are rooted. |root_node| | 91 | /// Return a top-level node under which scene elements are rooted. |
| 88 | /// is made the parent of this top-level node. | ||
| 89 | /// | 92 | /// |
| 90 | /// |shader| is an optional shader program assigned to the loaded scene objects. | 93 | /// |parent_node| is made the parent of the returned top-level node. It may be |
| 91 | /// If no shader is given, a Cook-Torrance shader based on the object's | 94 | /// null. |
| 92 | /// characteristics (presence of normals, tangents, etc) is assigned. | ||
| 93 | /// | 95 | /// |
| 94 | /// Currently only supports the GLTF format. | 96 | /// Currently only supports the GLTF format. |
| 95 | SceneNode* gfx_load_scene(Gfx*, SceneNode* root_node, const LoadSceneCmd*); | 97 | SceneNode* gfx_load_scene(Gfx*, SceneNode* parent_node, const LoadSceneCmd*); |
| 96 | 98 | ||
| 97 | /// Load a texture. | 99 | /// Load a texture. |
| 98 | Texture* gfx_load_texture(Gfx*, const LoadTextureCmd*); | 100 | 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*); | |||
| 138 | /// Set the node's parent. | 138 | /// Set the node's parent. |
| 139 | /// | 139 | /// |
| 140 | /// Pass in null to unwire from the existing parent, if one exists. | 140 | /// Pass in null to unwire from the existing parent, if one exists. |
| 141 | void gfx_set_node_parent(SceneNode*, SceneNode* parent); | 141 | void gfx_set_node_parent(SceneNode*, SceneNode* parent_node); |
| 142 | 142 | ||
| 143 | /// Set the node's (local) transform. | 143 | /// Set the node's (local) transform. |
| 144 | void gfx_set_node_transform(SceneNode*, const mat4* transform); | 144 | 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; | |||
| 8 | 8 | ||
| 9 | /// Load a scene. | 9 | /// Load a scene. |
| 10 | /// | 10 | /// |
| 11 | /// Return a top-level node under which scene elements are rooted. |root_node| | 11 | /// Return the top-level node under which scene elements are rooted. |
| 12 | /// is made the parent of this top-level node. | ||
| 13 | /// | 12 | /// |
| 14 | /// |shader| is an optional shader program assigned to the loaded scene objects. | 13 | /// |parent_node| is made the parent of the returned top-level node. It may be |
| 15 | /// If no shader is given, a Cook-Torrance shader based on the object's | 14 | /// null. |
| 16 | /// characteristics (presence of normals, tangents, etc) is assigned. | ||
| 17 | /// | 15 | /// |
| 18 | /// Currently only supports the GLTF format. | 16 | /// Currently only supports the GLTF format. |
| 19 | SceneNode* gfx_scene_load(Gfx*, SceneNode* root_node, const LoadSceneCmd*); | 17 | 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) { | |||
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | SceneNode* gfx_load_scene( | 115 | SceneNode* gfx_load_scene( |
| 116 | Gfx* gfx, SceneNode* root_node, const LoadSceneCmd* cmd) { | 116 | Gfx* gfx, SceneNode* parent_node, const LoadSceneCmd* cmd) { |
| 117 | assert(gfx); | 117 | assert(gfx); |
| 118 | 118 | ||
| 119 | AssetCache* cache = gfx_get_asset_cache(gfx); | 119 | AssetCache* cache = gfx_get_asset_cache(gfx); |
| @@ -130,7 +130,7 @@ SceneNode* gfx_load_scene( | |||
| 130 | 130 | ||
| 131 | // Asset not found in the cache. | 131 | // Asset not found in the cache. |
| 132 | // Load it, insert it into the cache, and return it. | 132 | // Load it, insert it into the cache, and return it. |
| 133 | SceneNode* node = gfx_scene_load(gfx, root_node, cmd); | 133 | SceneNode* node = gfx_scene_load(gfx, parent_node, cmd); |
| 134 | if (node) { | 134 | if (node) { |
| 135 | *(Asset*)mempool_alloc(&cache->assets) = (Asset){ | 135 | *(Asset*)mempool_alloc(&cache->assets) = (Asset){ |
| 136 | .type = SceneAsset, | 136 | .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) { | |||
| 271 | return transform; | 271 | return transform; |
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | void gfx_set_node_parent(SceneNode* child, SceneNode* parent) { | 274 | void gfx_set_node_parent(SceneNode* child, SceneNode* parent_node) { |
| 275 | assert(child); | 275 | assert(child); |
| 276 | // Parent can be null. | 276 | // Parent can be null. |
| 277 | SET_PARENT(child, parent); | 277 | SET_PARENT(child, parent_node); |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | void gfx_set_node_transform(SceneNode* node, const mat4* transform) { | 280 | 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( | |||
| 1303 | assert(root_node); | 1303 | assert(root_node); |
| 1304 | assert(objects); | 1304 | assert(objects); |
| 1305 | assert(cameras); | 1305 | assert(cameras); |
| 1306 | assert(anima); | ||
| 1307 | assert(nodes); | 1306 | assert(nodes); |
| 1308 | 1307 | ||
| 1309 | cgltf_size next_camera = 0; | 1308 | cgltf_size next_camera = 0; |
| @@ -1320,6 +1319,8 @@ static void load_nodes( | |||
| 1320 | 1319 | ||
| 1321 | gfx_construct_object_node(nodes[n], object); | 1320 | gfx_construct_object_node(nodes[n], object); |
| 1322 | if (node->skin) { | 1321 | if (node->skin) { |
| 1322 | assert(anima); | ||
| 1323 | |||
| 1323 | const cgltf_size skin_index = node->skin - data->skins; | 1324 | const cgltf_size skin_index = node->skin - data->skins; |
| 1324 | assert(skin_index < data->skins_count); | 1325 | assert(skin_index < data->skins_count); |
| 1325 | const Skeleton* skeleton = gfx_get_anima_skeleton(anima, skin_index); | 1326 | const Skeleton* skeleton = gfx_get_anima_skeleton(anima, skin_index); |
| @@ -1406,7 +1407,7 @@ static void load_nodes( | |||
| 1406 | /// This function ignores the many scenes and default scene of the glTF spec | 1407 | /// This function ignores the many scenes and default scene of the glTF spec |
| 1407 | /// and instead just loads all scenes into a single gfx Scene. | 1408 | /// and instead just loads all scenes into a single gfx Scene. |
| 1408 | static SceneNode* load_scene( | 1409 | static SceneNode* load_scene( |
| 1409 | cgltf_data* data, Gfx* gfx, SceneNode* root_node, const mstring* filepath, | 1410 | cgltf_data* data, Gfx* gfx, SceneNode* parent_node, const mstring* filepath, |
| 1410 | ShaderProgram* shader, const cgltfTangentBuffer* cgltf_tangent_buffers, | 1411 | ShaderProgram* shader, const cgltfTangentBuffer* cgltf_tangent_buffers, |
| 1411 | cgltf_size num_tangent_buffers) { | 1412 | cgltf_size num_tangent_buffers) { |
| 1412 | // In a GLTF scene, buffers can be shared among meshes, meshes among nodes, | 1413 | // In a GLTF scene, buffers can be shared among meshes, meshes among nodes, |
| @@ -1427,7 +1428,8 @@ static SceneNode* load_scene( | |||
| 1427 | // stage. | 1428 | // stage. |
| 1428 | assert(data); | 1429 | assert(data); |
| 1429 | assert(gfx); | 1430 | assert(gfx); |
| 1430 | assert(root_node); | 1431 | assert(filepath); |
| 1432 | assert((num_tangent_buffers == 0) || (cgltf_tangent_buffers != 0)); | ||
| 1431 | 1433 | ||
| 1432 | bool success = false; | 1434 | bool success = false; |
| 1433 | 1435 | ||
| @@ -1450,7 +1452,7 @@ static SceneNode* load_scene( | |||
| 1450 | SceneCamera** scene_cameras = 0; | 1452 | SceneCamera** scene_cameras = 0; |
| 1451 | SceneNode** scene_nodes = 0; | 1453 | SceneNode** scene_nodes = 0; |
| 1452 | Anima* anima = 0; | 1454 | Anima* anima = 0; |
| 1453 | SceneNode* anima_node = 0; | 1455 | SceneNode* root_node = 0; |
| 1454 | 1456 | ||
| 1455 | tangent_buffers = calloc(num_tangent_buffers, sizeof(Buffer*)); | 1457 | tangent_buffers = calloc(num_tangent_buffers, sizeof(Buffer*)); |
| 1456 | buffers = calloc(data->buffers_count, sizeof(Buffer*)); | 1458 | buffers = calloc(data->buffers_count, sizeof(Buffer*)); |
| @@ -1458,7 +1460,6 @@ static SceneNode* load_scene( | |||
| 1458 | materials = calloc(data->materials_count, sizeof(Material*)); | 1460 | materials = calloc(data->materials_count, sizeof(Material*)); |
| 1459 | geometries = calloc(primitive_count, sizeof(Geometry*)); | 1461 | geometries = calloc(primitive_count, sizeof(Geometry*)); |
| 1460 | meshes = calloc(primitive_count, sizeof(Mesh*)); | 1462 | meshes = calloc(primitive_count, sizeof(Mesh*)); |
| 1461 | anima_desc = calloc(1, sizeof(AnimaDesc)); | ||
| 1462 | scene_objects = calloc(data->meshes_count, sizeof(SceneObject*)); | 1463 | scene_objects = calloc(data->meshes_count, sizeof(SceneObject*)); |
| 1463 | scene_cameras = calloc(data->cameras_count, sizeof(SceneCamera**)); | 1464 | scene_cameras = calloc(data->cameras_count, sizeof(SceneCamera**)); |
| 1464 | scene_nodes = calloc(data->nodes_count, sizeof(SceneNode**)); | 1465 | scene_nodes = calloc(data->nodes_count, sizeof(SceneNode**)); |
| @@ -1511,22 +1512,30 @@ static SceneNode* load_scene( | |||
| 1511 | scene_nodes[i] = gfx_make_node(); | 1512 | scene_nodes[i] = gfx_make_node(); |
| 1512 | } | 1513 | } |
| 1513 | 1514 | ||
| 1514 | // TODO: If the scene does not have animations, then a top-level LogicalNode | 1515 | // Create the scene's root node. |
| 1515 | // would make more sense than an AnimaNode. | 1516 | // This is an anima node if the scene has skins; otherwise it is a logical |
| 1516 | anima_node = gfx_make_node(); | 1517 | // node. |
| 1517 | load_skins(data, buffers, scene_nodes, anima_desc->skeletons); | 1518 | root_node = gfx_make_node(); |
| 1518 | load_animations(data, scene_nodes, anima_desc->animations); | 1519 | if (data->skins_count > 0) { |
| 1519 | anima_desc->num_skeletons = data->skins_count; | 1520 | anima_desc = calloc(1, sizeof(AnimaDesc)); |
| 1520 | anima_desc->num_animations = data->animations_count; | 1521 | if (!anima_desc) { |
| 1521 | anima = gfx_make_anima(anima_desc); | 1522 | goto cleanup; |
| 1522 | gfx_construct_anima_node(anima_node, anima); | 1523 | } |
| 1523 | gfx_set_node_parent(anima_node, root_node); | 1524 | |
| 1525 | load_skins(data, buffers, scene_nodes, anima_desc->skeletons); | ||
| 1526 | load_animations(data, scene_nodes, anima_desc->animations); | ||
| 1524 | 1527 | ||
| 1525 | // The anima node becomes the root of all scene nodes. | 1528 | anima_desc->num_skeletons = data->skins_count; |
| 1526 | load_nodes( | 1529 | anima_desc->num_animations = data->animations_count; |
| 1527 | data, anima_node, scene_objects, scene_cameras, anima, scene_nodes); | 1530 | anima = gfx_make_anima(anima_desc); |
| 1531 | gfx_construct_anima_node(root_node, anima); | ||
| 1532 | } | ||
| 1533 | gfx_set_node_parent(root_node, parent_node); | ||
| 1534 | |||
| 1535 | // The root node becomes the root of all scene nodes. | ||
| 1536 | load_nodes(data, root_node, scene_objects, scene_cameras, anima, scene_nodes); | ||
| 1528 | 1537 | ||
| 1529 | success = anima_node != 0; | 1538 | success = true; |
| 1530 | 1539 | ||
| 1531 | cleanup: | 1540 | cleanup: |
| 1532 | // The arrays of resources are no longer needed. The resources themselves are | 1541 | // The arrays of resources are no longer needed. The resources themselves are |
| @@ -1627,18 +1636,20 @@ cleanup: | |||
| 1627 | } | 1636 | } |
| 1628 | free(scene_nodes); | 1637 | free(scene_nodes); |
| 1629 | } | 1638 | } |
| 1630 | if (!success && anima_node) { | 1639 | if (!success) { |
| 1631 | gfx_destroy_node(&anima_node); // Node owns the anima. | 1640 | if (root_node) { |
| 1632 | } else if (!success && anima) { | 1641 | gfx_destroy_node(&root_node); // Node owns the anima. |
| 1633 | gfx_destroy_anima(&anima); | 1642 | } else if (anima) { |
| 1643 | gfx_destroy_anima(&anima); | ||
| 1644 | } | ||
| 1634 | } | 1645 | } |
| 1635 | return anima_node; | 1646 | return root_node; |
| 1636 | } | 1647 | } |
| 1637 | 1648 | ||
| 1638 | SceneNode* gfx_scene_load( | 1649 | SceneNode* gfx_scene_load( |
| 1639 | Gfx* gfx, SceneNode* root_node, const LoadSceneCmd* cmd) { | 1650 | Gfx* gfx, SceneNode* parent_node, const LoadSceneCmd* cmd) { |
| 1640 | assert(gfx); | 1651 | assert(gfx); |
| 1641 | assert(root_node); | 1652 | assert(parent_node); |
| 1642 | assert(cmd); | 1653 | assert(cmd); |
| 1643 | 1654 | ||
| 1644 | SceneNode* scene_node = 0; | 1655 | SceneNode* scene_node = 0; |
| @@ -1674,7 +1685,7 @@ SceneNode* gfx_scene_load( | |||
| 1674 | &options, data, &tangent_buffers, &num_tangent_buffers); | 1685 | &options, data, &tangent_buffers, &num_tangent_buffers); |
| 1675 | 1686 | ||
| 1676 | scene_node = load_scene( | 1687 | scene_node = load_scene( |
| 1677 | data, gfx, root_node, &cmd->filepath, cmd->shader, tangent_buffers, | 1688 | data, gfx, parent_node, &cmd->filepath, cmd->shader, tangent_buffers, |
| 1678 | num_tangent_buffers); | 1689 | num_tangent_buffers); |
| 1679 | 1690 | ||
| 1680 | cleanup: | 1691 | cleanup: |
