diff options
author | 3gg <3gg@shellblade.net> | 2023-01-07 13:28:02 -0800 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2023-01-07 13:28:02 -0800 |
commit | 3f186ba1570f61d8cc5a1b8cdbb4c1d5f18bd848 (patch) | |
tree | 7d22f0834d270ef5c9f55494ec214b009d9fd50d | |
parent | c447ba1064ec9b170dfbee30d3b49da4cf8e0ffd (diff) |
Let scene loader create logical nodes for other unhandled nodes; fix scene graph node wiring.
-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 | ||