summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gfx/include/gfx/asset.h12
-rw-r--r--gfx/include/gfx/scene/node.h5
-rw-r--r--gfx/src/asset/asset_cache.c35
-rw-r--r--gfx/src/scene/node.c37
-rw-r--r--gfx/src/scene/node_impl.h4
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.
100Model* gfx_load_model(Gfx*, const LoadModelCmd*); 96Model* 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.
89NodeType gfx_get_node_type(const SceneNode*); 89NodeType 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.
114SceneObject* gfx_get_node_object(const SceneNode*); 114SceneObject* gfx_get_node_object(const SceneNode*);
115 115
116/// Get the node's parent.
117const 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.
117NodeIter gfx_get_node_child(const SceneNode*); 120NodeIter 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
106static 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
100void gfx_init_asset_cache(AssetCache* cache) { 131void 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
142const Texture* gfx_load_texture(Gfx* gfx, const LoadTextureCmd* cmd) { 173const 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
232const SceneNode* gfx_get_node_parent(const SceneNode* node) {
233 assert(node);
234 return mem_get_node(node->parent);
235}
236
232NodeIter gfx_get_node_child(const SceneNode* node) { 237NodeIter 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
353static 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
376SceneNode* 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.
36void gfx_del_node(node_idx); 36void 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).
40SceneNode* gfx_clone_scene_shallow(const SceneNode*);