aboutsummaryrefslogtreecommitdiff
path: root/src/asset/model.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/asset/model.c')
-rw-r--r--src/asset/model.c161
1 files changed, 81 insertions, 80 deletions
diff --git a/src/asset/model.c b/src/asset/model.c
index 1e05a85..ccda27d 100644
--- a/src/asset/model.c
+++ b/src/asset/model.c
@@ -1489,6 +1489,66 @@ static void load_animations(
1489 } 1489 }
1490} 1490}
1491 1491
1492/// Remove joint nodes from the Gfx Scene.
1493///
1494/// Joint nodes are not needed because joints are packed into the Anima.
1495static void remove_joint_nodes(
1496 const cgltf_data* data, SceneNode** scene_nodes) {
1497 assert(data);
1498 assert(scene_nodes);
1499
1500 // This works assuming the joint nodes are contiguous. Contiguity is checked
1501 // when loading skins. See load_skins().
1502 size_t min_joint_index = (size_t)-1;
1503 size_t max_joint_index = 0;
1504
1505 // First get the minimum and maximum indices of all joint nodes.
1506 for (cgltf_size s = 0; s < data->skins_count; ++s) {
1507 const cgltf_skin* skin = &data->skins[s];
1508
1509 for (cgltf_size j = 0; j < skin->joints_count; ++j) {
1510 // Joint is an index/pointer into the nodes array.
1511 const cgltf_size joint_index = skin->joints[j] - data->nodes;
1512 assert(joint_index < data->nodes_count);
1513
1514 if (joint_index < min_joint_index) {
1515 min_joint_index = joint_index;
1516 }
1517 if (joint_index > max_joint_index) {
1518 max_joint_index = joint_index;
1519 }
1520 }
1521 }
1522
1523 assert(min_joint_index < data->nodes_count);
1524 assert(max_joint_index < data->nodes_count);
1525
1526 // Now walk over the joint nodes. If a joint's parent is itself not a joint
1527 // node, then that joint is a root of a joint hierarchy (skins in glTF may
1528 // have multiple roots). In such case, delete the root joint recursively.
1529 for (cgltf_size s = 0; s < data->skins_count; ++s) {
1530 const cgltf_skin* skin = &data->skins[s];
1531
1532 for (cgltf_size j = 0; j < skin->joints_count; ++j) {
1533 // Joint is an index/pointer into the nodes array.
1534 const cgltf_size joint_index = skin->joints[j] - data->nodes;
1535 assert(joint_index < data->nodes_count);
1536
1537 const cgltf_node* joint = &data->nodes[joint_index];
1538
1539 // Parent node index.
1540 const cgltf_size parent_index = joint->parent - data->nodes;
1541 assert(parent_index < data->nodes_count);
1542
1543 // If the parent is not a joint node, recursively delete this joint node.
1544 if ((parent_index < min_joint_index) ||
1545 (parent_index > max_joint_index)) {
1546 gfx_destroy_node(&scene_nodes[joint_index]);
1547 }
1548 }
1549 }
1550}
1551
1492/// Load all nodes from the glTF scene. 1552/// Load all nodes from the glTF scene.
1493/// 1553///
1494/// This function ignores the many scenes and default scene of the glTF spec 1554/// This function ignores the many scenes and default scene of the glTF spec
@@ -1497,7 +1557,7 @@ static void load_nodes(
1497 const cgltf_data* data, SceneNode* root_node, SceneObject** objects, 1557 const cgltf_data* data, SceneNode* root_node, SceneObject** objects,
1498 SceneCamera** cameras, const Anima* anima, SceneNode** nodes) { 1558 SceneCamera** cameras, const Anima* anima, SceneNode** nodes) {
1499 // Note that with glTF 2.0, nodes do not form a DAG / scene graph but a 1559 // Note that with glTF 2.0, nodes do not form a DAG / scene graph but a
1500 // disjount union of strict trees: 1560 // disjoint union of strict trees:
1501 // 1561 //
1502 // "For Version 2.0 conformance, the glTF node hierarchy is not a directed 1562 // "For Version 2.0 conformance, the glTF node hierarchy is not a directed
1503 // acyclic graph (DAG) or scene graph, but a disjoint union of strict trees. 1563 // acyclic graph (DAG) or scene graph, but a disjoint union of strict trees.
@@ -1515,20 +1575,22 @@ static void load_nodes(
1515 1575
1516 cgltf_size next_camera = 0; 1576 cgltf_size next_camera = 0;
1517 1577
1578 // First pass: create the nodes.
1518 for (cgltf_size n = 0; n < data->nodes_count; ++n) { 1579 for (cgltf_size n = 0; n < data->nodes_count; ++n) {
1519 const cgltf_node* node = &data->nodes[n]; 1580 const cgltf_node* node = &data->nodes[n];
1520 1581
1521 // Add SceneObject, SceneCamera or Lights. 1582 // Add SceneObject, SceneCamera or Lights.
1522 // TODO: Handle lights once they are implemented in the gfx library. 1583 // TODO: Handle lights once they are implemented in the gfx library.
1584 assert(!nodes[n]);
1523 if (node->mesh) { 1585 if (node->mesh) {
1524 const cgltf_size mesh_index = node->mesh - data->meshes; 1586 const cgltf_size mesh_index = node->mesh - data->meshes;
1525 assert(mesh_index < data->meshes_count); 1587 assert(mesh_index < data->meshes_count);
1526 SceneObject* object = objects[mesh_index]; 1588 SceneObject* object = objects[mesh_index];
1527 gfx_construct_object_node(nodes[n], object); 1589
1590 nodes[n] = gfx_make_object_node(object);
1528 1591
1529 if (node->skin) { 1592 if (node->skin) {
1530 assert(anima); 1593 assert(anima);
1531
1532 const cgltf_size skin_index = node->skin - data->skins; 1594 const cgltf_size skin_index = node->skin - data->skins;
1533 assert(skin_index < data->skins_count); 1595 assert(skin_index < data->skins_count);
1534 const Skeleton* skeleton = gfx_get_anima_skeleton(anima, skin_index); 1596 const Skeleton* skeleton = gfx_get_anima_skeleton(anima, skin_index);
@@ -1559,11 +1621,12 @@ static void load_nodes(
1559 } 1621 }
1560 1622
1561 gfx_set_camera_camera(cameras[next_camera], &camera); 1623 gfx_set_camera_camera(cameras[next_camera], &camera);
1562 gfx_construct_camera_node(nodes[n], cameras[next_camera]); 1624 nodes[n] = gfx_make_camera_node(cameras[next_camera]);
1563 ++next_camera; 1625 ++next_camera;
1564 } else { 1626 } else {
1565 // TODO: implementation for missing node types. 1627 // TODO: implementation for missing node types.
1566 // These nodes currently default to logical nodes. 1628 // These nodes currently default to logical nodes.
1629 nodes[n] = gfx_make_node();
1567 } 1630 }
1568 assert(nodes[n]); 1631 assert(nodes[n]);
1569 1632
@@ -1589,6 +1652,11 @@ static void load_nodes(
1589 } 1652 }
1590 } 1653 }
1591 gfx_set_node_transform(nodes[n], &transform); 1654 gfx_set_node_transform(nodes[n], &transform);
1655 }
1656
1657 // Second pass: wire up the node hierarchy.
1658 for (cgltf_size n = 0; n < data->nodes_count; ++n) {
1659 const cgltf_node* node = &data->nodes[n];
1592 1660
1593 // If this is a top-level node in the glTF scene, set its parent to the 1661 // If this is a top-level node in the glTF scene, set its parent to the
1594 // given root node. 1662 // given root node.
@@ -1601,66 +1669,12 @@ static void load_nodes(
1601 assert(parent); 1669 assert(parent);
1602 gfx_set_node_parent(nodes[n], parent); 1670 gfx_set_node_parent(nodes[n], parent);
1603 } 1671 }
1604 } // SceneNode.
1605}
1606
1607/// Remove joint nodes from the Gfx Scene.
1608///
1609/// Joint nodes are not needed because joints are packed into the Anima.
1610static void remove_joint_nodes(
1611 const cgltf_data* data, SceneNode** scene_nodes) {
1612 assert(data);
1613 assert(scene_nodes);
1614
1615 // This works assuming the joint nodes are contiguous. Contiguity is checked
1616 // when loading skins. See load_skins().
1617 size_t min_joint_index = (size_t)-1;
1618 size_t max_joint_index = 0;
1619
1620 // First get the minimum and maximum indices of all joint nodes.
1621 for (cgltf_size s = 0; s < data->skins_count; ++s) {
1622 const cgltf_skin* skin = &data->skins[s];
1623
1624 for (cgltf_size j = 0; j < skin->joints_count; ++j) {
1625 // Joint is an index/pointer into the nodes array.
1626 const cgltf_size joint_index = skin->joints[j] - data->nodes;
1627 assert(joint_index < data->nodes_count);
1628
1629 if (joint_index < min_joint_index) {
1630 min_joint_index = joint_index;
1631 }
1632 if (joint_index > max_joint_index) {
1633 max_joint_index = joint_index;
1634 }
1635 }
1636 } 1672 }
1637 1673
1638 assert(min_joint_index < data->nodes_count); 1674 // Clean up scene nodes that correspond to joints in the glTF. These are not
1639 assert(max_joint_index < data->nodes_count); 1675 // needed anymore.
1640 1676 if (data->skins_count > 0) {
1641 // Now walk over the joint nodes. If a joint's parent is itself not a joint 1677 remove_joint_nodes(data, nodes);
1642 // node, then that joint is a root of a joint hierarchy (skins in glTF may
1643 // have multiple roots). In such case, delete the root joint recursively.
1644 for (cgltf_size s = 0; s < data->skins_count; ++s) {
1645 const cgltf_skin* skin = &data->skins[s];
1646
1647 for (cgltf_size j = 0; j < skin->joints_count; ++j) {
1648 // Joint is an index/pointer into the nodes array.
1649 const cgltf_size joint_index = skin->joints[j] - data->nodes;
1650 assert(joint_index < data->nodes_count);
1651
1652 const cgltf_node* joint = &data->nodes[joint_index];
1653
1654 // Parent node index.
1655 const cgltf_size parent_index = joint->parent - data->nodes;
1656 assert(parent_index < data->nodes_count);
1657
1658 // If the parent is not a joint node, recursively delete this joint node.
1659 if ((parent_index < min_joint_index) ||
1660 (parent_index > max_joint_index)) {
1661 gfx_destroy_node(&scene_nodes[joint_index]);
1662 }
1663 }
1664 } 1678 }
1665} 1679}
1666 1680
@@ -1768,19 +1782,9 @@ static Model* load_scene(
1768 goto cleanup; 1782 goto cleanup;
1769 } 1783 }
1770 1784
1771 // Skins refer to nodes, and nodes may refer to skins. To break this circular
1772 // dependency, glTF defines skins in terms of node indices. We could do the
1773 // same if Gfx allowed allocating nodes contiguously in memory. For now,
1774 // create the nodes up front and use the indices of the array to map to the
1775 // node_idx.
1776 for (cgltf_size i = 0; i < data->nodes_count; ++i) {
1777 scene_nodes[i] = gfx_make_node();
1778 }
1779
1780 // Create the scene's root node. 1785 // Create the scene's root node.
1781 // This is an anima node if the scene has skins; otherwise it is a logical 1786 // This is an anima node if the scene has skins; otherwise it is a logical
1782 // node. 1787 // node.
1783 root_node = gfx_make_node();
1784 if (data->skins_count > 0) { 1788 if (data->skins_count > 0) {
1785 anima_desc = calloc(1, sizeof(AnimaDesc)); 1789 anima_desc = calloc(1, sizeof(AnimaDesc));
1786 if (!anima_desc) { 1790 if (!anima_desc) {
@@ -1797,19 +1801,16 @@ static Model* load_scene(
1797 compute_joint_bounding_boxes( 1801 compute_joint_bounding_boxes(
1798 data, anima_desc->num_joints, anima_desc->joints); 1802 data, anima_desc->num_joints, anima_desc->joints);
1799 1803
1800 anima = gfx_make_anima(anima_desc); 1804 anima = gfx_make_anima(anima_desc);
1801 gfx_construct_anima_node(root_node, anima); 1805 root_node = gfx_make_anima_node(anima);
1806 } else {
1807 root_node = gfx_make_node();
1802 } 1808 }
1809 assert(root_node);
1803 1810
1804 // The root node becomes the root of all scene nodes. 1811 // The root node becomes the root of all scene nodes.
1805 load_nodes(data, root_node, scene_objects, scene_cameras, anima, scene_nodes); 1812 load_nodes(data, root_node, scene_objects, scene_cameras, anima, scene_nodes);
1806 1813
1807 // Clean up scene nodes that correspond to joints in the glTF. These are
1808 // not needed anymore.
1809 if (data->skins_count > 0) {
1810 remove_joint_nodes(data, scene_nodes);
1811 }
1812
1813 model = gfx_make_model(root_node); 1814 model = gfx_make_model(root_node);
1814 1815
1815 success = true; 1816 success = true;