diff options
-rw-r--r-- | gfx/include/gfx/asset.h | 12 | ||||
-rw-r--r-- | gfx/include/gfx/scene/node.h | 5 | ||||
-rw-r--r-- | gfx/src/asset/asset_cache.c | 35 | ||||
-rw-r--r-- | gfx/src/scene/node.c | 37 | ||||
-rw-r--r-- | gfx/src/scene/node_impl.h | 4 |
5 files changed, 82 insertions, 11 deletions
diff --git a/gfx/include/gfx/asset.h b/gfx/include/gfx/asset.h index 9845b03..1a4e551 100644 --- a/gfx/include/gfx/asset.h +++ b/gfx/include/gfx/asset.h | |||
@@ -86,15 +86,11 @@ typedef struct LoadModelCmd { | |||
86 | ShaderProgram* shader; | 86 | ShaderProgram* shader; |
87 | } LoadModelCmd; | 87 | } LoadModelCmd; |
88 | 88 | ||
89 | // TODO: We should return const resources. If the client wants a mutable copy, | 89 | /// Load a model. |
90 | // then let them clone the resource. | ||
91 | |||
92 | /// Load a scene. | ||
93 | /// | ||
94 | /// Return a top-level node under which scene elements are rooted. | ||
95 | /// | 90 | /// |
96 | /// |parent_node| is made the parent of the returned top-level node. It may be | 91 | /// For animated models, this function returns a (shallow) clone of the model |
97 | /// null. | 92 | /// that is safe to mutate. For static models, this returns the original model |
93 | /// in the cache. | ||
98 | /// | 94 | /// |
99 | /// Currently only supports the GLTF format. | 95 | /// Currently only supports the GLTF format. |
100 | Model* gfx_load_model(Gfx*, const LoadModelCmd*); | 96 | Model* gfx_load_model(Gfx*, const LoadModelCmd*); |
diff --git a/gfx/include/gfx/scene/node.h b/gfx/include/gfx/scene/node.h index 3877670..d048894 100644 --- a/gfx/include/gfx/scene/node.h +++ b/gfx/include/gfx/scene/node.h | |||
@@ -85,7 +85,7 @@ void gfx_destroy_node(SceneNode**); | |||
85 | 85 | ||
86 | // TODO: Review constness of getters here. | 86 | // TODO: Review constness of getters here. |
87 | 87 | ||
88 | /// Return the node's type. | 88 | /// Get the node's type. |
89 | NodeType gfx_get_node_type(const SceneNode*); | 89 | NodeType gfx_get_node_type(const SceneNode*); |
90 | 90 | ||
91 | /// Get the node's anima. | 91 | /// Get the node's anima. |
@@ -113,6 +113,9 @@ Model* gfx_get_node_model(const SceneNode*); | |||
113 | /// The node must be of type ObjectNode. | 113 | /// The node must be of type ObjectNode. |
114 | SceneObject* gfx_get_node_object(const SceneNode*); | 114 | SceneObject* gfx_get_node_object(const SceneNode*); |
115 | 115 | ||
116 | /// Get the node's parent. | ||
117 | const SceneNode* gfx_get_node_parent(const SceneNode*); | ||
118 | |||
116 | /// Get an iterator to the node's first child. | 119 | /// Get an iterator to the node's first child. |
117 | NodeIter gfx_get_node_child(const SceneNode*); | 120 | NodeIter gfx_get_node_child(const SceneNode*); |
118 | 121 | ||
diff --git a/gfx/src/asset/asset_cache.c b/gfx/src/asset/asset_cache.c index 0320954..e17de9d 100644 --- a/gfx/src/asset/asset_cache.c +++ b/gfx/src/asset/asset_cache.c | |||
@@ -1,9 +1,15 @@ | |||
1 | #include "asset_cache.h" | 1 | #include "asset_cache.h" |
2 | 2 | ||
3 | #include "scene.h" | 3 | #include "scene.h" |
4 | #include "scene/animation_impl.h" | ||
5 | #include "scene/model_impl.h" | ||
6 | #include "scene/node_impl.h" | ||
7 | #include "scene/scene_memory.h" | ||
4 | #include "texture.h" | 8 | #include "texture.h" |
9 | |||
5 | #include <gfx/asset.h> | 10 | #include <gfx/asset.h> |
6 | #include <gfx/gfx.h> | 11 | #include <gfx/gfx.h> |
12 | #include <gfx/scene/node.h> | ||
7 | #include <gfx_assert.h> | 13 | #include <gfx_assert.h> |
8 | 14 | ||
9 | #include <cstring.h> | 15 | #include <cstring.h> |
@@ -97,6 +103,31 @@ static void log_model_loaded(const LoadModelCmd* cmd) { | |||
97 | } | 103 | } |
98 | } | 104 | } |
99 | 105 | ||
106 | static Model* clone_model(const Model* model) { | ||
107 | assert(model); | ||
108 | |||
109 | // Only the Anima needs to be (shallow) cloned since everything else in the | ||
110 | // model is static. Also note that only the Anima's joints and animation state | ||
111 | // need to be cloned; all other members can be shared. So a shallow clone of | ||
112 | // the anima is sufficient. | ||
113 | const SceneNode* root = mem_get_node(model->root); | ||
114 | if (gfx_get_node_type(root) == AnimaNode) { | ||
115 | const Anima* anima = gfx_get_node_anima(root); | ||
116 | Anima* anima_copy = mem_alloc_anima(); | ||
117 | *anima_copy = *anima; // Shallow copy. | ||
118 | |||
119 | SceneNode* root_copy = gfx_clone_scene_shallow(root); | ||
120 | root_copy->anima = mem_get_anima_index(anima_copy); | ||
121 | anima_copy->parent = mem_get_node_index(root_copy); | ||
122 | |||
123 | Model* copy = mem_alloc_model(); | ||
124 | copy->root = mem_get_node_index(root_copy); | ||
125 | return copy; | ||
126 | } else { | ||
127 | return (Model*)model; // Static model, can't be mutated. | ||
128 | } | ||
129 | } | ||
130 | |||
100 | void gfx_init_asset_cache(AssetCache* cache) { | 131 | void gfx_init_asset_cache(AssetCache* cache) { |
101 | assert(cache); | 132 | assert(cache); |
102 | mempool_make(&cache->assets); | 133 | mempool_make(&cache->assets); |
@@ -122,7 +153,7 @@ Model* gfx_load_model(Gfx* gfx, const LoadModelCmd* cmd) { | |||
122 | Asset* asset = lookup_cache(cache, hash); | 153 | Asset* asset = lookup_cache(cache, hash); |
123 | if (asset) { | 154 | if (asset) { |
124 | log_model_cache_hit(cmd, hash); | 155 | log_model_cache_hit(cmd, hash); |
125 | return asset->model; | 156 | return clone_model(asset->model); |
126 | } | 157 | } |
127 | 158 | ||
128 | // Asset not found in the cache. | 159 | // Asset not found in the cache. |
@@ -136,7 +167,7 @@ Model* gfx_load_model(Gfx* gfx, const LoadModelCmd* cmd) { | |||
136 | }; | 167 | }; |
137 | log_model_loaded(cmd); | 168 | log_model_loaded(cmd); |
138 | } | 169 | } |
139 | return model; | 170 | return clone_model(model); |
140 | } | 171 | } |
141 | 172 | ||
142 | const Texture* gfx_load_texture(Gfx* gfx, const LoadTextureCmd* cmd) { | 173 | const Texture* gfx_load_texture(Gfx* gfx, const LoadTextureCmd* cmd) { |
diff --git a/gfx/src/scene/node.c b/gfx/src/scene/node.c index c48d3dd..0fbb696 100644 --- a/gfx/src/scene/node.c +++ b/gfx/src/scene/node.c | |||
@@ -229,6 +229,11 @@ SceneObject* gfx_get_node_object(const SceneNode* node) { | |||
229 | NODE_GET(node, object, ObjectNode); | 229 | NODE_GET(node, object, ObjectNode); |
230 | } | 230 | } |
231 | 231 | ||
232 | const SceneNode* gfx_get_node_parent(const SceneNode* node) { | ||
233 | assert(node); | ||
234 | return mem_get_node(node->parent); | ||
235 | } | ||
236 | |||
232 | NodeIter gfx_get_node_child(const SceneNode* node) { | 237 | NodeIter gfx_get_node_child(const SceneNode* node) { |
233 | assert(node); | 238 | assert(node); |
234 | return (NodeIter)node->child.val; | 239 | return (NodeIter)node->child.val; |
@@ -344,3 +349,35 @@ void gfx_log_node_hierarchy(const SceneNode* node) { | |||
344 | const sstring pad = sstring_make(""); | 349 | const sstring pad = sstring_make(""); |
345 | log_node_hierarchy_rec(node, &pad); | 350 | log_node_hierarchy_rec(node, &pad); |
346 | } | 351 | } |
352 | |||
353 | static SceneNode* clone_scene_rec(const SceneNode* node) { | ||
354 | assert(node); | ||
355 | |||
356 | SceneNode* copy = mem_alloc_node(); | ||
357 | *copy = *node; // Shallow clone of the node's resource. | ||
358 | |||
359 | if (node->child.val) { | ||
360 | SceneNode* child = mem_get_node(node->child); | ||
361 | SceneNode* child_copy = clone_scene_rec(child); | ||
362 | copy->child = mem_get_node_index(child_copy); | ||
363 | child_copy->parent = mem_get_node_index(copy); | ||
364 | } | ||
365 | |||
366 | if (node->next.val) { | ||
367 | SceneNode* next = mem_get_node(node->next); | ||
368 | SceneNode* next_copy = clone_scene_rec(next); | ||
369 | copy->next = mem_get_node_index(next_copy); | ||
370 | next_copy->prev = mem_get_node_index(copy); | ||
371 | } | ||
372 | |||
373 | return copy; | ||
374 | } | ||
375 | |||
376 | SceneNode* gfx_clone_scene_shallow(const SceneNode* node) { | ||
377 | assert(node); | ||
378 | // Must be a root node; not allowed to have siblings. | ||
379 | assert(!node->prev.val); | ||
380 | assert(!node->next.val); | ||
381 | |||
382 | return clone_scene_rec(node); | ||
383 | } | ||
diff --git a/gfx/src/scene/node_impl.h b/gfx/src/scene/node_impl.h index cabdc60..c79f252 100644 --- a/gfx/src/scene/node_impl.h +++ b/gfx/src/scene/node_impl.h | |||
@@ -34,3 +34,7 @@ typedef struct SceneNode { | |||
34 | /// | 34 | /// |
35 | /// This function is for the library's internal use only. | 35 | /// This function is for the library's internal use only. |
36 | void gfx_del_node(node_idx); | 36 | void gfx_del_node(node_idx); |
37 | |||
38 | /// Return a shallow clone of the scene rooted at the given node. | ||
39 | /// The given node must have no siblings (must be a root node). | ||
40 | SceneNode* gfx_clone_scene_shallow(const SceneNode*); | ||