diff options
| -rw-r--r-- | gfx/include/gfx/scene/node.h | 5 | ||||
| -rw-r--r-- | gfx/src/scene/node.c | 62 | ||||
| -rw-r--r-- | gfx/src/scene/node_impl.h | 18 | ||||
| -rw-r--r-- | gfx/src/scene/scene_graph.h | 173 | ||||
| -rw-r--r-- | gfx/src/scene/scene_impl.h | 2 | ||||
| -rw-r--r-- | gfx/src/scene/scene_memory.c | 32 | ||||
| -rw-r--r-- | gfx/src/scene/scene_memory.h | 12 | ||||
| -rw-r--r-- | gfx/src/scene/types.h | 6 | ||||
| -rw-r--r-- | gfx/src/util/scene.c | 27 | ||||
| -rw-r--r-- | gltfview/src/game.c | 2 |
10 files changed, 226 insertions, 113 deletions
diff --git a/gfx/include/gfx/scene/node.h b/gfx/include/gfx/scene/node.h index 736ff21..a09bdbc 100644 --- a/gfx/include/gfx/scene/node.h +++ b/gfx/include/gfx/scene/node.h | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | #include <math/fwd.h> | 3 | #include <math/fwd.h> |
| 4 | 4 | ||
| 5 | typedef struct Light Light; | 5 | typedef struct Light Light; |
| 6 | typedef struct SceneCamera SceneCamera; | 6 | typedef struct SceneCamera SceneCamera; |
| 7 | typedef struct SceneObject SceneObject; | 7 | typedef struct SceneObject SceneObject; |
| 8 | 8 | ||
| @@ -43,3 +43,6 @@ void gfx_set_node_position(SceneNode*, const vec3* position); | |||
| 43 | 43 | ||
| 44 | /// Set the node's rotation. | 44 | /// Set the node's rotation. |
| 45 | void gfx_set_node_rotation(SceneNode*, const mat4* rotation); | 45 | void gfx_set_node_rotation(SceneNode*, const mat4* rotation); |
| 46 | |||
| 47 | /// Log the node's hierarchy. | ||
| 48 | void gfx_log_node_hierarchy(const SceneNode*); | ||
diff --git a/gfx/src/scene/node.c b/gfx/src/scene/node.c index 7d7f69f..ee2f169 100644 --- a/gfx/src/scene/node.c +++ b/gfx/src/scene/node.c | |||
| @@ -6,11 +6,14 @@ | |||
| 6 | #include "scene_graph.h" | 6 | #include "scene_graph.h" |
| 7 | #include "scene_memory.h" | 7 | #include "scene_memory.h" |
| 8 | 8 | ||
| 9 | #include <cstring.h> | ||
| 10 | #include <log/log.h> | ||
| 11 | |||
| 9 | #include <assert.h> | 12 | #include <assert.h> |
| 10 | 13 | ||
| 11 | static void scene_node_make(SceneNode* node) { | 14 | static void scene_node_make(SceneNode* node) { |
| 12 | assert(node); | 15 | assert(node); |
| 13 | node->type = LogicalNode; | 16 | node->type = LogicalNode; |
| 14 | node->transform = mat4_id(); | 17 | node->transform = mat4_id(); |
| 15 | } | 18 | } |
| 16 | 19 | ||
| @@ -29,8 +32,8 @@ SceneNode* gfx_make_camera_node(SceneCamera* camera) { | |||
| 29 | if (!node) { | 32 | if (!node) { |
| 30 | return 0; | 33 | return 0; |
| 31 | } | 34 | } |
| 32 | node->type = CameraNode; | 35 | node->type = CameraNode; |
| 33 | node->camera = mem_get_camera_index(camera); | 36 | node->camera = mem_get_camera_index(camera); |
| 34 | camera->parent = mem_get_node_index(node); | 37 | camera->parent = mem_get_node_index(node); |
| 35 | return node; | 38 | return node; |
| 36 | } | 39 | } |
| @@ -41,8 +44,8 @@ SceneNode* gfx_make_light_node(Light* light) { | |||
| 41 | if (!node) { | 44 | if (!node) { |
| 42 | return 0; | 45 | return 0; |
| 43 | } | 46 | } |
| 44 | node->type = LightNode; | 47 | node->type = LightNode; |
| 45 | node->light = mem_get_light_index(light); | 48 | node->light = mem_get_light_index(light); |
| 46 | light->parent = mem_get_node_index(node); | 49 | light->parent = mem_get_node_index(node); |
| 47 | return node; | 50 | return node; |
| 48 | } | 51 | } |
| @@ -53,8 +56,8 @@ SceneNode* gfx_make_object_node(SceneObject* object) { | |||
| 53 | if (!node) { | 56 | if (!node) { |
| 54 | return 0; | 57 | return 0; |
| 55 | } | 58 | } |
| 56 | node->type = ObjectNode; | 59 | node->type = ObjectNode; |
| 57 | node->object = mem_get_object_index(object); | 60 | node->object = mem_get_object_index(object); |
| 58 | object->parent = mem_get_node_index(node); | 61 | object->parent = mem_get_node_index(node); |
| 59 | return node; | 62 | return node; |
| 60 | } | 63 | } |
| @@ -63,36 +66,40 @@ void gfx_destroy_node(SceneNode** node) { | |||
| 63 | assert(node); | 66 | assert(node); |
| 64 | assert(*node); | 67 | assert(*node); |
| 65 | 68 | ||
| 66 | // Destroy the node's resources. | 69 | // Destroy the node's resource. |
| 67 | // Camera. | ||
| 68 | if ((*node)->type == CameraNode) { | 70 | if ((*node)->type == CameraNode) { |
| 69 | SceneCamera* camera = mem_get_camera((*node)->camera); | 71 | SceneCamera* camera = mem_get_camera((*node)->camera); |
| 70 | camera->parent.val = 0; // Avoid recursive call into gfx_destroy_node(). | 72 | camera->parent.val = 0; // Avoid call into gfx_del_node(). |
| 71 | gfx_destroy_camera(&camera); | 73 | gfx_destroy_camera(&camera); |
| 72 | } | 74 | } else if ((*node)->type == LightNode) { |
| 73 | // TODO: free light. | 75 | Light* light = mem_get_light((*node)->light); |
| 74 | // Object. | 76 | light->parent.val = 0; // Avoid call into gfx_del_node(). |
| 75 | if ((*node)->type == ObjectNode) { | 77 | gfx_destroy_light(&light); |
| 78 | } else if ((*node)->type == ObjectNode) { | ||
| 76 | SceneObject* object = mem_get_object((*node)->object); | 79 | SceneObject* object = mem_get_object((*node)->object); |
| 77 | object->parent.val = 0; // Avoid recursive call into gfx_destroy_node(). | 80 | object->parent.val = 0; // Avoid call into gfx_del_node(). |
| 78 | gfx_destroy_object(&object); | 81 | gfx_destroy_object(&object); |
| 79 | } | 82 | } |
| 80 | 83 | ||
| 84 | // TODO: Should destroy children recursively? | ||
| 81 | TREE_REMOVE(*node); | 85 | TREE_REMOVE(*node); |
| 82 | mem_free_node(node); | 86 | mem_free_node(node); |
| 83 | } | 87 | } |
| 84 | 88 | ||
| 89 | // TODO: Think more about ownership of nodes and resources. Should this function | ||
| 90 | // even exist? | ||
| 85 | void gfx_del_node(node_idx index) { | 91 | void gfx_del_node(node_idx index) { |
| 86 | assert(index.val); | 92 | assert(index.val); |
| 87 | SceneNode* node = mem_get_node(index); | 93 | SceneNode* node = mem_get_node(index); |
| 88 | assert(node); | 94 | assert(node); |
| 95 | // TODO: Should destroy children recursively? | ||
| 89 | TREE_REMOVE(node); | 96 | TREE_REMOVE(node); |
| 90 | mem_free_node(&node); | 97 | mem_free_node(&node); |
| 91 | } | 98 | } |
| 92 | 99 | ||
| 93 | void gfx_set_node_parent(SceneNode* child, SceneNode* parent) { | 100 | void gfx_set_node_parent(SceneNode* child, SceneNode* parent) { |
| 94 | assert(child); | 101 | assert(child); |
| 95 | assert(parent); | 102 | // Parent can be null. |
| 96 | SET_PARENT(child, parent); | 103 | SET_PARENT(child, parent); |
| 97 | } | 104 | } |
| 98 | 105 | ||
| @@ -113,3 +120,26 @@ void gfx_set_node_rotation(SceneNode* node, const mat4* rotation) { | |||
| 113 | assert(rotation); | 120 | assert(rotation); |
| 114 | mat4_set_3x3(&node->transform, *rotation); | 121 | mat4_set_3x3(&node->transform, *rotation); |
| 115 | } | 122 | } |
| 123 | |||
| 124 | static void log_node_hierarchy_rec(const SceneNode* node, const sstring* pad) { | ||
| 125 | assert(node); | ||
| 126 | assert(pad); | ||
| 127 | |||
| 128 | LOGD("%sNode (%u)", sstring_cstring(pad), mem_get_node_index(node).val); | ||
| 129 | |||
| 130 | // Log the children. | ||
| 131 | if (node->child.val) { | ||
| 132 | const sstring new_pad = sstring_concat_cstr(*pad, " "); | ||
| 133 | log_node_hierarchy_rec(mem_get_node(node->child), &new_pad); | ||
| 134 | } | ||
| 135 | |||
| 136 | // Then log the siblings. | ||
| 137 | if (node->next.val) { | ||
| 138 | log_node_hierarchy_rec(mem_get_node(node->next), pad); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | void gfx_log_node_hierarchy(const SceneNode* node) { | ||
| 143 | const sstring pad = sstring_make(""); | ||
| 144 | log_node_hierarchy_rec(node, &pad); | ||
| 145 | } | ||
diff --git a/gfx/src/scene/node_impl.h b/gfx/src/scene/node_impl.h index ce3b769..f4aea79 100644 --- a/gfx/src/scene/node_impl.h +++ b/gfx/src/scene/node_impl.h | |||
| @@ -8,9 +8,9 @@ | |||
| 8 | 8 | ||
| 9 | /// Scene node type. | 9 | /// Scene node type. |
| 10 | typedef enum NodeType { | 10 | typedef enum NodeType { |
| 11 | LogicalNode, | ||
| 11 | CameraNode, | 12 | CameraNode, |
| 12 | LightNode, | 13 | LightNode, |
| 13 | LogicalNode, | ||
| 14 | ObjectNode | 14 | ObjectNode |
| 15 | } NodeType; | 15 | } NodeType; |
| 16 | 16 | ||
| @@ -22,17 +22,19 @@ typedef struct SceneNode { | |||
| 22 | NodeType type; | 22 | NodeType type; |
| 23 | union { | 23 | union { |
| 24 | camera_idx camera; | 24 | camera_idx camera; |
| 25 | light_idx light; | 25 | light_idx light; |
| 26 | object_idx object; | 26 | object_idx object; |
| 27 | }; | 27 | }; |
| 28 | mat4 transform; // Transformation for this node and its children. | 28 | mat4 transform; // Transformation for this node and its children. |
| 29 | node_idx parent; // Parent SceneNode. | 29 | node_idx parent; // Parent SceneNode. |
| 30 | node_idx child; // First child SceneNode. | 30 | node_idx child; // First child SceneNode. |
| 31 | node_idx next; // Next sibling SceneNode. | 31 | node_idx next; // Next sibling SceneNode. |
| 32 | node_idx prev; // Previous sibling SceneNode. | 32 | node_idx prev; // Previous sibling SceneNode. |
| 33 | } SceneNode; | 33 | } SceneNode; |
| 34 | 34 | ||
| 35 | /// Destroy a node given its index. | 35 | /// Destroy a node given its index without destroying its resource. |
| 36 | /// | 36 | /// |
| 37 | /// The node is conveniently removed from the scene graph. | 37 | /// The node is conveniently removed from the scene graph. |
| 38 | /// | ||
| 39 | /// This function is for the library's internal use only. | ||
| 38 | void gfx_del_node(node_idx); | 40 | void gfx_del_node(node_idx); |
diff --git a/gfx/src/scene/scene_graph.h b/gfx/src/scene/scene_graph.h index b9b3a14..93d2e38 100644 --- a/gfx/src/scene/scene_graph.h +++ b/gfx/src/scene/scene_graph.h | |||
| @@ -3,65 +3,136 @@ | |||
| 3 | 3 | ||
| 4 | #include "scene_memory.h" | 4 | #include "scene_memory.h" |
| 5 | 5 | ||
| 6 | // Note that SceneMemory guarantees that index 0 can be regarded as an invalid | 6 | // NOTE: SceneMemory guarantees that index 0 can be regarded as an invalid |
| 7 | // index. | 7 | // index. |
| 8 | 8 | ||
| 9 | #define MEM_GET(INDEX) \ | 9 | #define MEM_GET(INDEX) \ |
| 10 | _Generic((INDEX), camera_idx \ | 10 | _Generic((INDEX), camera_idx \ |
| 11 | : mem_get_camera, material_idx \ | 11 | : mem_get_camera, material_idx \ |
| 12 | : mem_get_material, mesh_idx \ | 12 | : mem_get_material, mesh_idx \ |
| 13 | : mem_get_mesh, mesh_link_idx \ | 13 | : mem_get_mesh, mesh_link_idx \ |
| 14 | : mem_get_mesh_link, node_idx \ | 14 | : mem_get_mesh_link, node_idx \ |
| 15 | : mem_get_node, object_idx \ | 15 | : mem_get_node, object_idx \ |
| 16 | : mem_get_object, scene_idx \ | 16 | : mem_get_object, scene_idx \ |
| 17 | : mem_get_scene)(INDEX) | 17 | : mem_get_scene)(INDEX) |
| 18 | 18 | ||
| 19 | #define MEM_GET_INDEX(ITEM) \ | 19 | #define MEM_GET_INDEX(ITEM) \ |
| 20 | _Generic((ITEM), SceneCamera * \ | 20 | _Generic((ITEM), SceneCamera * \ |
| 21 | : mem_get_camera_index, Material * \ | 21 | : mem_get_camera_index, Material * \ |
| 22 | : mem_get_material_index, Mesh * \ | 22 | : mem_get_material_index, Mesh * \ |
| 23 | : mem_get_mesh_index, MeshLink * \ | 23 | : mem_get_mesh_index, MeshLink * \ |
| 24 | : mem_get_mesh_link_index, SceneNode * \ | 24 | : mem_get_mesh_link_index, SceneNode * \ |
| 25 | : mem_get_node_index, SceneObject * \ | 25 | : mem_get_node_index, SceneObject * \ |
| 26 | : mem_get_object_index, Scene * \ | 26 | : mem_get_object_index, Scene * \ |
| 27 | : mem_get_scene_index)(ITEM) | 27 | : mem_get_scene_index)(ITEM) |
| 28 | 28 | ||
| 29 | #define LIST_PREPEND(HEAD_INDEX, ITEM) \ | 29 | /// Assert the list node invariant. |
| 30 | ITEM->next = HEAD_INDEX; \ | 30 | /// |
| 31 | if (HEAD_INDEX.val) { \ | 31 | /// - A node does not point to itself. |
| 32 | typeof(ITEM) old_head = MEM_GET(HEAD_INDEX); \ | 32 | #define ASSERT_LIST_NODE_INVARIANT(ITEM) \ |
| 33 | old_head->prev = MEM_GET_INDEX(ITEM); \ | 33 | { \ |
| 34 | } \ | 34 | const gfx_idx item_idx = MEM_GET_INDEX(ITEM).val; \ |
| 35 | HEAD_INDEX = MEM_GET_INDEX(ITEM); | 35 | assert((ITEM)->prev.val != item_idx); \ |
| 36 | 36 | assert((ITEM)->next.val != item_idx); \ | |
| 37 | #define LIST_REMOVE(ITEM) \ | ||
| 38 | if ((ITEM)->prev.val) { \ | ||
| 39 | typeof(ITEM) prev_sibling = MEM_GET((ITEM)->prev); \ | ||
| 40 | prev_sibling->next = (ITEM)->next; \ | ||
| 41 | } \ | ||
| 42 | if ((ITEM)->next.val) { \ | ||
| 43 | typeof(ITEM) next_sibling = MEM_GET((ITEM)->next); \ | ||
| 44 | next_sibling->prev = (ITEM)->prev; \ | ||
| 45 | } | 37 | } |
| 46 | 38 | ||
| 47 | #define SET_PARENT(CHILD, PARENT) \ | 39 | /// Assert the tree node invariant. |
| 48 | assert(CHILD); \ | 40 | /// |
| 49 | if (CHILD->parent.val) { \ | 41 | /// - A node does not point to itself. |
| 50 | LIST_REMOVE(CHILD); \ | 42 | /// - The node's left and right siblings cannot be equal, unless both are 0. |
| 51 | } \ | 43 | /// - The node's left/right sibling cannot be its child, unless both are 0. |
| 52 | if (parent) { \ | 44 | /// - The node's parent cannot be the node's child or sibling, unless it's 0. |
| 53 | LIST_PREPEND(PARENT->CHILD, CHILD); \ | 45 | /// - If the node has a parent and the node is the leftmost sibling, then the |
| 46 | /// parent's child is the node. | ||
| 47 | #define ASSERT_TREE_NODE_INVARIANT(ITEM) \ | ||
| 48 | { \ | ||
| 49 | const gfx_idx item_idx = MEM_GET_INDEX(ITEM).val; \ | ||
| 50 | assert((ITEM)->prev.val != item_idx); \ | ||
| 51 | assert((ITEM)->next.val != item_idx); \ | ||
| 52 | if ((ITEM)->prev.val) { \ | ||
| 53 | assert((ITEM)->prev.val != (ITEM)->next.val); \ | ||
| 54 | } \ | ||
| 55 | if ((ITEM)->child.val) { \ | ||
| 56 | assert((ITEM)->child.val != (ITEM)->prev.val); \ | ||
| 57 | assert((ITEM)->child.val != (ITEM)->next.val); \ | ||
| 58 | } \ | ||
| 59 | assert((ITEM)->parent.val != item_idx); \ | ||
| 60 | if ((ITEM)->parent.val && !(ITEM)->prev.val) { \ | ||
| 61 | assert((ITEM)->parent.val != (ITEM)->prev.val); \ | ||
| 62 | assert((ITEM)->parent.val != (ITEM)->next.val); \ | ||
| 63 | const typeof(ITEM) item_parent = MEM_GET((ITEM)->parent); \ | ||
| 64 | assert(item_parent->child.val == item_idx); \ | ||
| 65 | } \ | ||
| 54 | } | 66 | } |
| 55 | 67 | ||
| 56 | #define TREE_REMOVE(ITEM) \ | 68 | /// Prepend an item to a list. |
| 57 | if ((ITEM)->prev.val) { \ | 69 | /// Modify HEAD_INDEX to equal the index of the new head. |
| 58 | typeof(ITEM) prev_sibling = MEM_GET((ITEM)->prev); \ | 70 | #define LIST_PREPEND(HEAD_INDEX, ITEM) \ |
| 59 | prev_sibling->next = (ITEM)->next; \ | 71 | (ITEM)->next = HEAD_INDEX; \ |
| 60 | } \ | 72 | if (HEAD_INDEX.val) { \ |
| 61 | if ((ITEM)->next.val) { \ | 73 | typeof(ITEM) old_head = MEM_GET(HEAD_INDEX); \ |
| 62 | typeof(ITEM) next_sibling = MEM_GET((ITEM)->next); \ | 74 | old_head->prev = MEM_GET_INDEX(ITEM); \ |
| 63 | next_sibling->prev = (ITEM)->prev; \ | 75 | } \ |
| 64 | } \ | 76 | HEAD_INDEX = MEM_GET_INDEX(ITEM); \ |
| 65 | if ((ITEM)->parent.val) { \ | 77 | ASSERT_LIST_NODE_INVARIANT(ITEM); |
| 66 | MEM_GET((ITEM)->parent)->child.val = 0; \ | 78 | |
| 79 | /// Disconnect an item from its siblings. | ||
| 80 | #define LIST_REMOVE(ITEM) \ | ||
| 81 | if ((ITEM)->prev.val) { \ | ||
| 82 | typeof(ITEM) prev_sibling = MEM_GET((ITEM)->prev); \ | ||
| 83 | prev_sibling->next = (ITEM)->next; \ | ||
| 84 | } \ | ||
| 85 | if ((ITEM)->next.val) { \ | ||
| 86 | typeof(ITEM) next_sibling = MEM_GET((ITEM)->next); \ | ||
| 87 | next_sibling->prev = (ITEM)->prev; \ | ||
| 88 | } \ | ||
| 89 | (ITEM)->prev.val = 0; \ | ||
| 90 | (ITEM)->next.val = 0; \ | ||
| 91 | ASSERT_LIST_NODE_INVARIANT(ITEM); | ||
| 92 | |||
| 93 | /// Set the child's parent. | ||
| 94 | /// | ||
| 95 | /// The hierarchy is a strict tree hierarchy and a parent node points to its | ||
| 96 | /// first/leftmost child only. To add a new child, the new child becomes the | ||
| 97 | /// leftmost node in the list of siblings, the one that the parent then points | ||
| 98 | /// to. | ||
| 99 | /// | ||
| 100 | /// The child is also completely disconnected from its previous hierarchy. This | ||
| 101 | /// is because siblings in a hierarchy must all point to the same parent. | ||
| 102 | #define SET_PARENT(CHILD, PARENT) \ | ||
| 103 | assert(CHILD); \ | ||
| 104 | assert(CHILD != PARENT); \ | ||
| 105 | ASSERT_TREE_NODE_INVARIANT(CHILD); \ | ||
| 106 | ASSERT_TREE_NODE_INVARIANT(PARENT); \ | ||
| 107 | TREE_REMOVE(CHILD); /* Disconnect CHILD from its previous hierarchy. */ \ | ||
| 108 | if (PARENT) { \ | ||
| 109 | LIST_PREPEND((PARENT)->child, CHILD); \ | ||
| 110 | (CHILD)->parent = MEM_GET_INDEX(PARENT); \ | ||
| 111 | } else { \ | ||
| 112 | (CHILD)->parent.val = 0; \ | ||
| 113 | } \ | ||
| 114 | ASSERT_TREE_NODE_INVARIANT(CHILD); \ | ||
| 115 | if (PARENT) { \ | ||
| 116 | ASSERT_TREE_NODE_INVARIANT(PARENT); \ | ||
| 67 | } | 117 | } |
| 118 | |||
| 119 | /// Remove an item from its hierarchy. | ||
| 120 | /// | ||
| 121 | /// The item is disconnected from its parents and siblings. The hierarchy rooted | ||
| 122 | /// under the item remains intact. | ||
| 123 | #define TREE_REMOVE(ITEM) \ | ||
| 124 | assert(ITEM); \ | ||
| 125 | if ((ITEM)->parent.val) { \ | ||
| 126 | /* The parent points only to its first/leftmost child. If this item is */ \ | ||
| 127 | /* the leftmost sibling, then we need to rewire the parent to point to */ \ | ||
| 128 | /* the next sibling to keep the parent connected to its children. */ \ | ||
| 129 | typeof(ITEM) parent = MEM_GET((ITEM)->parent); \ | ||
| 130 | const typeof(ITEM) parent_child = MEM_GET(parent->child); \ | ||
| 131 | if (parent_child == ITEM) { \ | ||
| 132 | assert((ITEM)->prev.val == 0); \ | ||
| 133 | parent->child = (ITEM)->next; \ | ||
| 134 | } \ | ||
| 135 | } \ | ||
| 136 | (ITEM)->parent.val = 0; \ | ||
| 137 | LIST_REMOVE(ITEM); /* Disconnect ITEM from its siblings. */ \ | ||
| 138 | ASSERT_TREE_NODE_INVARIANT(ITEM); | ||
diff --git a/gfx/src/scene/scene_impl.h b/gfx/src/scene/scene_impl.h index e0c25bf..e6544dd 100644 --- a/gfx/src/scene/scene_impl.h +++ b/gfx/src/scene/scene_impl.h | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | #include "types.h" | 5 | #include "types.h" |
| 6 | 6 | ||
| 7 | typedef struct Scene { | 7 | typedef struct Scene { |
| 8 | node_idx root; | 8 | node_idx root; |
| 9 | scene_idx next; | 9 | scene_idx next; |
| 10 | scene_idx prev; | 10 | scene_idx prev; |
| 11 | } Scene; | 11 | } Scene; |
diff --git a/gfx/src/scene/scene_memory.c b/gfx/src/scene/scene_memory.c index cd4a79c..7355ad2 100644 --- a/gfx/src/scene/scene_memory.c +++ b/gfx/src/scene/scene_memory.c | |||
| @@ -26,19 +26,19 @@ DEF_MEMPOOL(scene_pool, Scene, GFX_MAX_NUM_SCENES) | |||
| 26 | /// | 26 | /// |
| 27 | /// Holds memory pools for every type of scene object. | 27 | /// Holds memory pools for every type of scene object. |
| 28 | typedef struct SceneMemory { | 28 | typedef struct SceneMemory { |
| 29 | camera_pool cameras; | 29 | camera_pool cameras; |
| 30 | light_pool lights; | 30 | light_pool lights; |
| 31 | material_pool materials; | 31 | material_pool materials; |
| 32 | mesh_pool meshes; | 32 | mesh_pool meshes; |
| 33 | mesh_link_pool mesh_links; | 33 | mesh_link_pool mesh_links; |
| 34 | node_pool nodes; | 34 | node_pool nodes; |
| 35 | object_pool objects; | 35 | object_pool objects; |
| 36 | scene_pool scenes; | 36 | scene_pool scenes; |
| 37 | } SceneMemory; | 37 | } SceneMemory; |
| 38 | 38 | ||
| 39 | static SceneMemory mem; | 39 | static SceneMemory mem; |
| 40 | 40 | ||
| 41 | #define ALLOC_DUMMY(POOL) \ | 41 | #define ALLOC_DUMMY(POOL) \ |
| 42 | assert(mempool_get_block_index(POOL, mempool_alloc(POOL)) == 0) | 42 | assert(mempool_get_block_index(POOL, mempool_alloc(POOL)) == 0) |
| 43 | 43 | ||
| 44 | void scene_mem_init() { | 44 | void scene_mem_init() { |
| @@ -67,13 +67,13 @@ void scene_mem_destroy() {} | |||
| 67 | 67 | ||
| 68 | // Memory allocation. | 68 | // Memory allocation. |
| 69 | SceneCamera* mem_alloc_camera() { return mempool_alloc(&mem.cameras); } | 69 | SceneCamera* mem_alloc_camera() { return mempool_alloc(&mem.cameras); } |
| 70 | Light* mem_alloc_light() { return mempool_alloc(&mem.lights); } | 70 | Light* mem_alloc_light() { return mempool_alloc(&mem.lights); } |
| 71 | Material* mem_alloc_material() { return mempool_alloc(&mem.materials); } | 71 | Material* mem_alloc_material() { return mempool_alloc(&mem.materials); } |
| 72 | Mesh* mem_alloc_mesh() { return mempool_alloc(&mem.meshes); } | 72 | Mesh* mem_alloc_mesh() { return mempool_alloc(&mem.meshes); } |
| 73 | MeshLink* mem_alloc_mesh_link() { return mempool_alloc(&mem.mesh_links); } | 73 | MeshLink* mem_alloc_mesh_link() { return mempool_alloc(&mem.mesh_links); } |
| 74 | SceneNode* mem_alloc_node() { return mempool_alloc(&mem.nodes); } | 74 | SceneNode* mem_alloc_node() { return mempool_alloc(&mem.nodes); } |
| 75 | SceneObject* mem_alloc_object() { return mempool_alloc(&mem.objects); } | 75 | SceneObject* mem_alloc_object() { return mempool_alloc(&mem.objects); } |
| 76 | Scene* mem_alloc_scene() { return mempool_alloc(&mem.scenes); } | 76 | Scene* mem_alloc_scene() { return mempool_alloc(&mem.scenes); } |
| 77 | 77 | ||
| 78 | // Memory free. | 78 | // Memory free. |
| 79 | void mem_free_camera(SceneCamera** camera) { | 79 | void mem_free_camera(SceneCamera** camera) { |
| @@ -127,8 +127,8 @@ light_idx mem_get_light_index(const Light* light) { | |||
| 127 | return (light_idx){.val = mempool_get_block_index(&mem.lights, light)}; | 127 | return (light_idx){.val = mempool_get_block_index(&mem.lights, light)}; |
| 128 | } | 128 | } |
| 129 | material_idx mem_get_material_index(const Material* material) { | 129 | material_idx mem_get_material_index(const Material* material) { |
| 130 | return (material_idx){.val = | 130 | return (material_idx){ |
| 131 | mempool_get_block_index(&mem.materials, material)}; | 131 | .val = mempool_get_block_index(&mem.materials, material)}; |
| 132 | } | 132 | } |
| 133 | mesh_idx mem_get_mesh_index(const Mesh* mesh) { | 133 | mesh_idx mem_get_mesh_index(const Mesh* mesh) { |
| 134 | return (mesh_idx){.val = mempool_get_block_index(&mem.meshes, mesh)}; | 134 | return (mesh_idx){.val = mempool_get_block_index(&mem.meshes, mesh)}; |
diff --git a/gfx/src/scene/scene_memory.h b/gfx/src/scene/scene_memory.h index dff5bd8..b0fa73c 100644 --- a/gfx/src/scene/scene_memory.h +++ b/gfx/src/scene/scene_memory.h | |||
| @@ -3,14 +3,14 @@ | |||
| 3 | 3 | ||
| 4 | #include "types.h" | 4 | #include "types.h" |
| 5 | 5 | ||
| 6 | typedef struct Light Light; | 6 | typedef struct Light Light; |
| 7 | typedef struct Material Material; | 7 | typedef struct Material Material; |
| 8 | typedef struct Mesh Mesh; | 8 | typedef struct Mesh Mesh; |
| 9 | typedef struct MeshLink MeshLink; | 9 | typedef struct MeshLink MeshLink; |
| 10 | typedef struct SceneCamera SceneCamera; | 10 | typedef struct SceneCamera SceneCamera; |
| 11 | typedef struct SceneNode SceneNode; | 11 | typedef struct SceneNode SceneNode; |
| 12 | typedef struct SceneObject SceneObject; | 12 | typedef struct SceneObject SceneObject; |
| 13 | typedef struct Scene Scene; | 13 | typedef struct Scene Scene; |
| 14 | 14 | ||
| 15 | /// Initialize scene memory. | 15 | /// Initialize scene memory. |
| 16 | /// | 16 | /// |
diff --git a/gfx/src/scene/types.h b/gfx/src/scene/types.h index 2863ac7..1c52991 100644 --- a/gfx/src/scene/types.h +++ b/gfx/src/scene/types.h | |||
| @@ -6,9 +6,9 @@ typedef uint16_t gfx_idx; | |||
| 6 | 6 | ||
| 7 | // Strongly-typed indices. | 7 | // Strongly-typed indices. |
| 8 | 8 | ||
| 9 | #define DEF_STRONG_INDEX(TYPE_NAME) \ | 9 | #define DEF_STRONG_INDEX(TYPE_NAME) \ |
| 10 | typedef struct TYPE_NAME##_idx { \ | 10 | typedef struct TYPE_NAME##_idx { \ |
| 11 | gfx_idx val; \ | 11 | gfx_idx val; \ |
| 12 | } TYPE_NAME##_idx; | 12 | } TYPE_NAME##_idx; |
| 13 | 13 | ||
| 14 | DEF_STRONG_INDEX(camera) | 14 | DEF_STRONG_INDEX(camera) |
diff --git a/gfx/src/util/scene.c b/gfx/src/util/scene.c index 35d6dd0..87d775c 100644 --- a/gfx/src/util/scene.c +++ b/gfx/src/util/scene.c | |||
| @@ -779,8 +779,8 @@ static bool load_meshes( | |||
| 779 | /// This function ignores the many scenes and default scene of the glTF spec | 779 | /// This function ignores the many scenes and default scene of the glTF spec |
| 780 | /// and instead just loads all nodes into a single gfx Scene. | 780 | /// and instead just loads all nodes into a single gfx Scene. |
| 781 | static void load_nodes( | 781 | static void load_nodes( |
| 782 | const cgltf_data* data, Gfx* gfx, SceneNode* root_node, | 782 | const cgltf_data* data, SceneNode* root_node, SceneObject** objects, |
| 783 | SceneObject** objects, SceneCamera** cameras, SceneNode** nodes) { | 783 | SceneCamera** cameras, SceneNode** nodes) { |
| 784 | // Note that with glTF 2.0, nodes do not form a DAG / scene graph but a | 784 | // Note that with glTF 2.0, nodes do not form a DAG / scene graph but a |
| 785 | // disjount union of strict trees: | 785 | // disjount union of strict trees: |
| 786 | // | 786 | // |
| @@ -793,8 +793,6 @@ static void load_nodes( | |||
| 793 | // This matches the gfx library implementation, where every node can have at | 793 | // This matches the gfx library implementation, where every node can have at |
| 794 | // most one parent. | 794 | // most one parent. |
| 795 | assert(data); | 795 | assert(data); |
| 796 | // TODO: gfx not needed? | ||
| 797 | assert(gfx); | ||
| 798 | assert(root_node); | 796 | assert(root_node); |
| 799 | assert(objects); | 797 | assert(objects); |
| 800 | assert(cameras); | 798 | assert(cameras); |
| @@ -841,7 +839,13 @@ static void load_nodes( | |||
| 841 | nodes[n] = gfx_make_camera_node(cameras[next_camera]); | 839 | nodes[n] = gfx_make_camera_node(cameras[next_camera]); |
| 842 | ++next_camera; | 840 | ++next_camera; |
| 843 | } else { | 841 | } else { |
| 844 | continue; // TODO: implementation for missing node types. | 842 | // TODO: implementation for missing node types. |
| 843 | // Create a vanilla SceneNode for unhandled node types for the sake of | ||
| 844 | // being able to complete the hierarchy. Otherwise, wiring nodes in pass 2 | ||
| 845 | // fails. | ||
| 846 | LOGW("Unhandled node type, creating vanilla SceneNode for hierarchy " | ||
| 847 | "completeness"); | ||
| 848 | nodes[n] = gfx_make_node(); | ||
| 845 | } | 849 | } |
| 846 | assert(nodes[n]); | 850 | assert(nodes[n]); |
| 847 | 851 | ||
| @@ -868,10 +872,11 @@ static void load_nodes( | |||
| 868 | } | 872 | } |
| 869 | gfx_set_node_transform(nodes[n], &transform); | 873 | gfx_set_node_transform(nodes[n], &transform); |
| 870 | 874 | ||
| 871 | // By default, set nodes as children of the root node. The second pass will | 875 | // If this is a top-level node in the glTF scene, set its parent to the |
| 872 | // properly set the parent of the relevant nodes, and leave the root node as | 876 | // given root node. |
| 873 | // the parent for top-level nodes. | 877 | if (!node->parent) { |
| 874 | gfx_set_node_parent(nodes[n], root_node); | 878 | gfx_set_node_parent(nodes[n], root_node); |
| 879 | } | ||
| 875 | } // SceneNode. | 880 | } // SceneNode. |
| 876 | 881 | ||
| 877 | // Second pass: wire nodes together to build the hierarchy. | 882 | // Second pass: wire nodes together to build the hierarchy. |
| @@ -883,7 +888,7 @@ static void load_nodes( | |||
| 883 | const cgltf_size child_index = parent->children[c] - data->nodes; | 888 | const cgltf_size child_index = parent->children[c] - data->nodes; |
| 884 | assert(child_index < data->nodes_count); | 889 | assert(child_index < data->nodes_count); |
| 885 | SceneNode* child_scene_node = nodes[child_index]; | 890 | SceneNode* child_scene_node = nodes[child_index]; |
| 886 | 891 | assert(child_scene_node); | |
| 887 | gfx_set_node_parent(child_scene_node, parent_scene_node); | 892 | gfx_set_node_parent(child_scene_node, parent_scene_node); |
| 888 | } | 893 | } |
| 889 | } | 894 | } |
| @@ -982,7 +987,7 @@ static bool load_scene( | |||
| 982 | goto cleanup; | 987 | goto cleanup; |
| 983 | } | 988 | } |
| 984 | 989 | ||
| 985 | load_nodes(data, gfx, root_node, scene_objects, scene_cameras, scene_nodes); | 990 | load_nodes(data, root_node, scene_objects, scene_cameras, scene_nodes); |
| 986 | 991 | ||
| 987 | return true; | 992 | return true; |
| 988 | 993 | ||
diff --git a/gltfview/src/game.c b/gltfview/src/game.c index 224200d..93755e7 100644 --- a/gltfview/src/game.c +++ b/gltfview/src/game.c | |||
| @@ -121,6 +121,8 @@ static bool load_scene( | |||
| 121 | return false; | 121 | return false; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | gfx_log_node_hierarchy(gfx_get_scene_root(game->scene)); | ||
| 125 | |||
| 124 | return true; | 126 | return true; |
| 125 | } | 127 | } |
| 126 | 128 | ||
