summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2023-01-07 13:28:02 -0800
committer3gg <3gg@shellblade.net>2023-01-07 13:28:02 -0800
commit3f186ba1570f61d8cc5a1b8cdbb4c1d5f18bd848 (patch)
tree7d22f0834d270ef5c9f55494ec214b009d9fd50d
parentc447ba1064ec9b170dfbee30d3b49da4cf8e0ffd (diff)
Let scene loader create logical nodes for other unhandled nodes; fix scene graph node wiring.
-rw-r--r--gfx/include/gfx/scene/node.h5
-rw-r--r--gfx/src/scene/node.c62
-rw-r--r--gfx/src/scene/node_impl.h18
-rw-r--r--gfx/src/scene/scene_graph.h173
-rw-r--r--gfx/src/scene/scene_impl.h2
-rw-r--r--gfx/src/scene/scene_memory.c32
-rw-r--r--gfx/src/scene/scene_memory.h12
-rw-r--r--gfx/src/scene/types.h6
-rw-r--r--gfx/src/util/scene.c27
-rw-r--r--gltfview/src/game.c2
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
5typedef struct Light Light; 5typedef struct Light Light;
6typedef struct SceneCamera SceneCamera; 6typedef struct SceneCamera SceneCamera;
7typedef struct SceneObject SceneObject; 7typedef 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.
45void gfx_set_node_rotation(SceneNode*, const mat4* rotation); 45void gfx_set_node_rotation(SceneNode*, const mat4* rotation);
46
47/// Log the node's hierarchy.
48void 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
11static void scene_node_make(SceneNode* node) { 14static 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?
85void gfx_del_node(node_idx index) { 91void 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
93void gfx_set_node_parent(SceneNode* child, SceneNode* parent) { 100void 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
124static 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
142void 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.
10typedef enum NodeType { 10typedef 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.
38void gfx_del_node(node_idx); 40void 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
7typedef struct Scene { 7typedef 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.
28typedef struct SceneMemory { 28typedef 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
39static SceneMemory mem; 39static 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
44void scene_mem_init() { 44void scene_mem_init() {
@@ -67,13 +67,13 @@ void scene_mem_destroy() {}
67 67
68// Memory allocation. 68// Memory allocation.
69SceneCamera* mem_alloc_camera() { return mempool_alloc(&mem.cameras); } 69SceneCamera* mem_alloc_camera() { return mempool_alloc(&mem.cameras); }
70Light* mem_alloc_light() { return mempool_alloc(&mem.lights); } 70Light* mem_alloc_light() { return mempool_alloc(&mem.lights); }
71Material* mem_alloc_material() { return mempool_alloc(&mem.materials); } 71Material* mem_alloc_material() { return mempool_alloc(&mem.materials); }
72Mesh* mem_alloc_mesh() { return mempool_alloc(&mem.meshes); } 72Mesh* mem_alloc_mesh() { return mempool_alloc(&mem.meshes); }
73MeshLink* mem_alloc_mesh_link() { return mempool_alloc(&mem.mesh_links); } 73MeshLink* mem_alloc_mesh_link() { return mempool_alloc(&mem.mesh_links); }
74SceneNode* mem_alloc_node() { return mempool_alloc(&mem.nodes); } 74SceneNode* mem_alloc_node() { return mempool_alloc(&mem.nodes); }
75SceneObject* mem_alloc_object() { return mempool_alloc(&mem.objects); } 75SceneObject* mem_alloc_object() { return mempool_alloc(&mem.objects); }
76Scene* mem_alloc_scene() { return mempool_alloc(&mem.scenes); } 76Scene* mem_alloc_scene() { return mempool_alloc(&mem.scenes); }
77 77
78// Memory free. 78// Memory free.
79void mem_free_camera(SceneCamera** camera) { 79void 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}
129material_idx mem_get_material_index(const Material* material) { 129material_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}
133mesh_idx mem_get_mesh_index(const Mesh* mesh) { 133mesh_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
6typedef struct Light Light; 6typedef struct Light Light;
7typedef struct Material Material; 7typedef struct Material Material;
8typedef struct Mesh Mesh; 8typedef struct Mesh Mesh;
9typedef struct MeshLink MeshLink; 9typedef struct MeshLink MeshLink;
10typedef struct SceneCamera SceneCamera; 10typedef struct SceneCamera SceneCamera;
11typedef struct SceneNode SceneNode; 11typedef struct SceneNode SceneNode;
12typedef struct SceneObject SceneObject; 12typedef struct SceneObject SceneObject;
13typedef struct Scene Scene; 13typedef 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
14DEF_STRONG_INDEX(camera) 14DEF_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.
781static void load_nodes( 781static 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