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*); | ||
