summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--game/src/plugins/viewer.c46
-rw-r--r--gfx/CMakeLists.txt1
-rw-r--r--gfx/include/gfx/asset.h15
-rw-r--r--gfx/include/gfx/scene.h1
-rw-r--r--gfx/include/gfx/scene/model.h11
-rw-r--r--gfx/include/gfx/scene/node.h17
-rw-r--r--gfx/include/gfx/scene/scene.h3
-rw-r--r--gfx/include/gfx/sizes.h3
-rw-r--r--gfx/src/asset/asset_cache.c42
-rw-r--r--gfx/src/asset/asset_cache.h10
-rw-r--r--gfx/src/asset/scene.c32
-rw-r--r--gfx/src/asset/scene.h13
-rw-r--r--gfx/src/renderer/renderer.c14
-rw-r--r--gfx/src/scene/model.c41
-rw-r--r--gfx/src/scene/model_impl.h17
-rw-r--r--gfx/src/scene/node.c46
-rw-r--r--gfx/src/scene/node_impl.h1
-rw-r--r--gfx/src/scene/scene.c19
-rw-r--r--gfx/src/scene/scene_memory.c9
-rw-r--r--gfx/src/scene/scene_memory.h2
-rw-r--r--gfx/src/scene/types.h1
21 files changed, 241 insertions, 103 deletions
diff --git a/game/src/plugins/viewer.c b/game/src/plugins/viewer.c
index 40213e4..dd7f451 100644
--- a/game/src/plugins/viewer.c
+++ b/game/src/plugins/viewer.c
@@ -3,7 +3,6 @@
3#include <gfx/asset.h> 3#include <gfx/asset.h>
4#include <gfx/renderer.h> 4#include <gfx/renderer.h>
5#include <gfx/scene.h> 5#include <gfx/scene.h>
6#include <gfx/scene/scene.h>
7#include <gfx/util/skyquad.h> 6#include <gfx/util/skyquad.h>
8#include <math/camera.h> 7#include <math/camera.h>
9#include <math/spatial3.h> 8#include <math/spatial3.h>
@@ -26,6 +25,7 @@ static const char* GIRL =
26 25
27struct State { 26struct State {
28 Scene* scene; 27 Scene* scene;
28 Model* model;
29 SceneCamera* camera; 29 SceneCamera* camera;
30}; 30};
31 31
@@ -65,8 +65,8 @@ static SceneNode* load_skyquad(Gfx* gfx, SceneNode* root) {
65} 65}
66 66
67/// Load the 3D scene. 67/// Load the 3D scene.
68static SceneNode* load_scene( 68/// Return the loaded model.
69 Game* game, State* state, const char* scene_filepath) { 69static Model* load_scene(Game* game, State* state, const char* scene_filepath) {
70 assert(game); 70 assert(game);
71 assert(game->gfx); 71 assert(game->gfx);
72 assert(state); 72 assert(state);
@@ -81,17 +81,22 @@ static SceneNode* load_scene(
81 return 0; // test 81 return 0; // test
82 } 82 }
83 83
84 SceneNode* scene_node = gfx_load_scene( 84 Model* model = gfx_load_model(
85 game->gfx, sky_light_node, 85 game->gfx,
86 &(LoadSceneCmd){ 86 &(LoadModelCmd){
87 .origin = AssetFromFile, .filepath = mstring_make(scene_filepath)}); 87 .origin = AssetFromFile, .filepath = mstring_make(scene_filepath)});
88 if (!scene_node) { 88 if (!model) {
89 return 0; 89 return 0;
90 } 90 }
91 SceneNode* model_node = gfx_make_model_node(model);
92 if (!model_node) {
93 return 0;
94 }
95 gfx_set_node_parent(model_node, sky_light_node);
91 96
92 gfx_log_node_hierarchy(root); 97 gfx_log_node_hierarchy(root);
93 98
94 return scene_node; 99 return model;
95} 100}
96 101
97bool init(Game* game, State** pp_state) { 102bool init(Game* game, State** pp_state) {
@@ -115,13 +120,13 @@ bool init(Game* game, State** pp_state) {
115 // Usage: <scene file> 120 // Usage: <scene file>
116 const char* scene_filepath = argc > 1 ? argv[1] : DEFAULT_SCENE_FILE; 121 const char* scene_filepath = argc > 1 ? argv[1] : DEFAULT_SCENE_FILE;
117 122
118 SceneNode* node = load_scene(game, state, scene_filepath); 123 state->model = load_scene(game, state, scene_filepath);
119 if (!node) { 124 if (!state->model) {
120 goto cleanup; 125 goto cleanup;
121 } 126 }
122 127
123 if (gfx_get_node_type(node) == AnimaNode) { 128 Anima* anima = gfx_get_model_anima(state->model);
124 Anima* anima = gfx_get_node_anima(node); 129 if (anima) {
125 gfx_play_animation( 130 gfx_play_animation(
126 anima, &(AnimationPlaySettings){.name = "Walk", .loop = true}); 131 anima, &(AnimationPlaySettings){.name = "Walk", .loop = true});
127 } 132 }
@@ -156,7 +161,13 @@ void update(Game* game, State* state, double t, double dt) {
156 assert(state->scene); 161 assert(state->scene);
157 assert(state->camera); 162 assert(state->camera);
158 163
159 gfx_animate_scene(state->scene, (R)t); 164 // TODO: Move this to some sort of update_scene(). Note that models do not
165 // need to be animated if they are not visible to the camera. The camera
166 // update also should happen first.
167 Anima* anima = gfx_get_model_anima(state->model);
168 if (anima) {
169 gfx_update_animation(anima, (R)t);
170 }
160 171
161 const vec3 orbit_point = vec3_make(0, 2, 0); 172 const vec3 orbit_point = vec3_make(0, 2, 0);
162 Camera* camera = gfx_get_camera_camera(state->camera); 173 Camera* camera = gfx_get_camera_camera(state->camera);
@@ -171,7 +182,14 @@ void update(Game* game, State* state, double t, double dt) {
171static void render_bounding_boxes_rec(ImmRenderer* imm, const SceneNode* node) { 182static void render_bounding_boxes_rec(ImmRenderer* imm, const SceneNode* node) {
172 assert(imm); 183 assert(imm);
173 assert(node); 184 assert(node);
174 if (gfx_get_node_type(node) == ObjectNode) { 185
186 const NodeType node_type = gfx_get_node_type(node);
187
188 if (node_type == ModelNode) {
189 const Model* model = gfx_get_node_model(node);
190 const SceneNode* root = gfx_get_model_root(model);
191 render_bounding_boxes_rec(imm, root);
192 } else if (node_type == ObjectNode) {
175 // TODO: Look at the scene log. The JointNodes are detached from the 193 // TODO: Look at the scene log. The JointNodes are detached from the
176 // ObjectNodes. This is why the boxes are not being transformed as expected 194 // ObjectNodes. This is why the boxes are not being transformed as expected
177 // here. Anima needs to animate boxes? Use OOBB in addition to AABB? 195 // here. Anima needs to animate boxes? Use OOBB in addition to AABB?
diff --git a/gfx/CMakeLists.txt b/gfx/CMakeLists.txt
index 2d83a7c..b423990 100644
--- a/gfx/CMakeLists.txt
+++ b/gfx/CMakeLists.txt
@@ -51,6 +51,7 @@ add_library(gfx SHARED
51 src/scene/light.c 51 src/scene/light.c
52 src/scene/material.c 52 src/scene/material.c
53 src/scene/mesh.c 53 src/scene/mesh.c
54 src/scene/model.c
54 src/scene/node.c 55 src/scene/node.c
55 src/scene/object.c 56 src/scene/object.c
56 src/scene/scene.c 57 src/scene/scene.c
diff --git a/gfx/include/gfx/asset.h b/gfx/include/gfx/asset.h
index c2bac57..c5cc5f8 100644
--- a/gfx/include/gfx/asset.h
+++ b/gfx/include/gfx/asset.h
@@ -6,7 +6,7 @@
6#include <stddef.h> 6#include <stddef.h>
7 7
8typedef struct Gfx Gfx; 8typedef struct Gfx Gfx;
9typedef struct SceneNode SceneNode; 9typedef struct Model Model;
10typedef struct ShaderProgram ShaderProgram; 10typedef struct ShaderProgram ShaderProgram;
11typedef struct Texture Texture; 11typedef struct Texture Texture;
12 12
@@ -67,12 +67,12 @@ typedef struct LoadTextureCmd {
67 } data; 67 } data;
68} LoadTextureCmd; 68} LoadTextureCmd;
69 69
70/// Describes a command to load a scene. 70/// Describes a command to load a model.
71/// 71///
72/// |shader| is an optional shader program assigned to the loaded scene objects. 72/// |shader| is an optional shader program assigned to the loaded model objects.
73/// If no shader is given, a Cook-Torrance shader based on the object's 73/// If no shader is given, a Cook-Torrance shader based on the object's
74/// characteristics (presence of normals, tangents, etc) is assigned. 74/// characteristics (presence of normals, tangents, etc) is assigned.
75typedef struct LoadSceneCmd { 75typedef struct LoadModelCmd {
76 AssetOrigin origin; 76 AssetOrigin origin;
77 union { 77 union {
78 struct { 78 struct {
@@ -84,7 +84,10 @@ typedef struct LoadSceneCmd {
84 }; 84 };
85 }; 85 };
86 ShaderProgram* shader; 86 ShaderProgram* shader;
87} LoadSceneCmd; 87} LoadModelCmd;
88
89// TODO: We should return const resources. If the client wants a mutable copy,
90// then let them clone the resource.
88 91
89/// Load a scene. 92/// Load a scene.
90/// 93///
@@ -94,7 +97,7 @@ typedef struct LoadSceneCmd {
94/// null. 97/// null.
95/// 98///
96/// Currently only supports the GLTF format. 99/// Currently only supports the GLTF format.
97SceneNode* gfx_load_scene(Gfx*, SceneNode* parent_node, const LoadSceneCmd*); 100Model* gfx_load_model(Gfx*, const LoadModelCmd*);
98 101
99/// Load a texture. 102/// Load a texture.
100Texture* gfx_load_texture(Gfx*, const LoadTextureCmd*); 103Texture* gfx_load_texture(Gfx*, const LoadTextureCmd*);
diff --git a/gfx/include/gfx/scene.h b/gfx/include/gfx/scene.h
index 1d74679..abcaa70 100644
--- a/gfx/include/gfx/scene.h
+++ b/gfx/include/gfx/scene.h
@@ -5,6 +5,7 @@
5#include <gfx/scene/light.h> 5#include <gfx/scene/light.h>
6#include <gfx/scene/material.h> 6#include <gfx/scene/material.h>
7#include <gfx/scene/mesh.h> 7#include <gfx/scene/mesh.h>
8#include <gfx/scene/model.h>
8#include <gfx/scene/node.h> 9#include <gfx/scene/node.h>
9#include <gfx/scene/object.h> 10#include <gfx/scene/object.h>
10#include <gfx/scene/scene.h> 11#include <gfx/scene/scene.h>
diff --git a/gfx/include/gfx/scene/model.h b/gfx/include/gfx/scene/model.h
new file mode 100644
index 0000000..f4972a9
--- /dev/null
+++ b/gfx/include/gfx/scene/model.h
@@ -0,0 +1,11 @@
1#pragma once
2
3typedef struct Anima Anima;
4typedef struct Model Model;
5typedef struct SceneNode SceneNode;
6
7/// Return the model's anima, or null if the model is not animated.
8Anima* gfx_get_model_anima(Model*);
9
10/// Return the model's root node.
11const SceneNode* gfx_get_model_root(const Model*);
diff --git a/gfx/include/gfx/scene/node.h b/gfx/include/gfx/scene/node.h
index 7976ae8..3877670 100644
--- a/gfx/include/gfx/scene/node.h
+++ b/gfx/include/gfx/scene/node.h
@@ -9,6 +9,7 @@
9 9
10typedef struct Anima Anima; 10typedef struct Anima Anima;
11typedef struct Light Light; 11typedef struct Light Light;
12typedef struct Model Model;
12typedef struct SceneCamera SceneCamera; 13typedef struct SceneCamera SceneCamera;
13typedef struct SceneObject SceneObject; 14typedef struct SceneObject SceneObject;
14 15
@@ -21,7 +22,8 @@ typedef enum NodeType {
21 AnimaNode, 22 AnimaNode,
22 CameraNode, 23 CameraNode,
23 LightNode, 24 LightNode,
24 ObjectNode 25 ModelNode,
26 ObjectNode,
25} NodeType; 27} NodeType;
26 28
27/// A node in the scene graph. 29/// A node in the scene graph.
@@ -49,6 +51,9 @@ SceneNode* gfx_make_camera_node(SceneCamera*);
49/// Create a new light node. 51/// Create a new light node.
50SceneNode* gfx_make_light_node(Light*); 52SceneNode* gfx_make_light_node(Light*);
51 53
54/// Create a new model node.
55SceneNode* gfx_make_model_node(Model*);
56
52/// Create a new object node. 57/// Create a new object node.
53SceneNode* gfx_make_object_node(SceneObject*); 58SceneNode* gfx_make_object_node(SceneObject*);
54 59
@@ -61,6 +66,9 @@ void gfx_construct_camera_node(SceneNode*, SceneCamera*);
61/// Make the node a light node. 66/// Make the node a light node.
62void gfx_construct_light_node(SceneNode*, Light*); 67void gfx_construct_light_node(SceneNode*, Light*);
63 68
69/// Make the node a model node.
70void gfx_construct_model_node(SceneNode*, Model*);
71
64/// Make the node an object node. 72/// Make the node an object node.
65void gfx_construct_object_node(SceneNode*, SceneObject*); 73void gfx_construct_object_node(SceneNode*, SceneObject*);
66 74
@@ -75,6 +83,8 @@ void gfx_destroy_node(SceneNode**);
75// Getters. 83// Getters.
76// ----------------------------------------------------------------------------- 84// -----------------------------------------------------------------------------
77 85
86// TODO: Review constness of getters here.
87
78/// Return the node's type. 88/// Return the node's type.
79NodeType gfx_get_node_type(const SceneNode*); 89NodeType gfx_get_node_type(const SceneNode*);
80 90
@@ -93,6 +103,11 @@ SceneCamera* gfx_get_node_camera(const SceneNode* node);
93/// The node must be of type LightNode. 103/// The node must be of type LightNode.
94Light* gfx_get_node_light(const SceneNode*); 104Light* gfx_get_node_light(const SceneNode*);
95 105
106/// Get the node's model.
107///
108/// The node must be of type ModelNode.
109Model* gfx_get_node_model(const SceneNode*);
110
96/// Get the node's scene object. 111/// Get the node's scene object.
97/// 112///
98/// The node must be of type ObjectNode. 113/// The node must be of type ObjectNode.
diff --git a/gfx/include/gfx/scene/scene.h b/gfx/include/gfx/scene/scene.h
index f5c9ddf..0d96210 100644
--- a/gfx/include/gfx/scene/scene.h
+++ b/gfx/include/gfx/scene/scene.h
@@ -19,6 +19,3 @@ void gfx_destroy_scene(Scene**);
19 19
20/// Get the scene's root node. 20/// Get the scene's root node.
21SceneNode* gfx_get_scene_root(Scene*); 21SceneNode* gfx_get_scene_root(Scene*);
22
23/// Update the scene's animations.
24void gfx_animate_scene(Scene*, R t);
diff --git a/gfx/include/gfx/sizes.h b/gfx/include/gfx/sizes.h
index b6f47ef..076113c 100644
--- a/gfx/include/gfx/sizes.h
+++ b/gfx/include/gfx/sizes.h
@@ -18,6 +18,9 @@
18/// Maximum number of mesh links. 18/// Maximum number of mesh links.
19#define GFX_MAX_NUM_MESH_LINKS 1024 19#define GFX_MAX_NUM_MESH_LINKS 1024
20 20
21/// Maximum number of models.
22#define GFX_MAX_NUM_MODELS 64
23
21/// Maximum number of joints per skeleton. 24/// Maximum number of joints per skeleton.
22#define GFX_MAX_NUM_JOINTS 96 25#define GFX_MAX_NUM_JOINTS 96
23 26
diff --git a/gfx/src/asset/asset_cache.c b/gfx/src/asset/asset_cache.c
index 0075d41..037f62b 100644
--- a/gfx/src/asset/asset_cache.c
+++ b/gfx/src/asset/asset_cache.c
@@ -4,15 +4,12 @@
4#include "texture.h" 4#include "texture.h"
5#include <gfx/asset.h> 5#include <gfx/asset.h>
6#include <gfx/gfx.h> 6#include <gfx/gfx.h>
7#include <gfx/scene/node.h>
8#include <gfx_assert.h> 7#include <gfx_assert.h>
9 8
10#include "scene/node_impl.h"
11
12#include <cstring.h> 9#include <cstring.h>
13#include <log/log.h> 10#include <log/log.h>
14 11
15static Hash calc_scene_hash(const LoadSceneCmd* cmd) { 12static Hash calc_model_hash(const LoadModelCmd* cmd) {
16 assert(cmd); 13 assert(cmd);
17 switch (cmd->origin) { 14 switch (cmd->origin) {
18 case AssetFromFile: 15 case AssetFromFile:
@@ -20,7 +17,7 @@ static Hash calc_scene_hash(const LoadSceneCmd* cmd) {
20 case AssetFromMemory: 17 case AssetFromMemory:
21 return (Hash)cmd->data; 18 return (Hash)cmd->data;
22 } 19 }
23 FAIL("Unhandled scene asset origin"); 20 FAIL("Unhandled model asset origin");
24 return 0; 21 return 0;
25} 22}
26 23
@@ -74,7 +71,7 @@ static Asset* lookup_cache(AssetCache* cache, Hash hash) {
74 return 0; 71 return 0;
75} 72}
76 73
77static void log_scene_cache_hit(const LoadSceneCmd* cmd, Hash hash) { 74static void log_model_cache_hit(const LoadModelCmd* cmd, Hash hash) {
78 assert(cmd); 75 assert(cmd);
79 switch (cmd->origin) { 76 switch (cmd->origin) {
80 case AssetFromFile: 77 case AssetFromFile:
@@ -88,7 +85,7 @@ static void log_scene_cache_hit(const LoadSceneCmd* cmd, Hash hash) {
88 } 85 }
89} 86}
90 87
91static void log_scene_loaded(const LoadSceneCmd* cmd) { 88static void log_model_loaded(const LoadModelCmd* cmd) {
92 assert(cmd); 89 assert(cmd);
93 switch (cmd->origin) { 90 switch (cmd->origin) {
94 case AssetFromFile: 91 case AssetFromFile:
@@ -115,32 +112,31 @@ void gfx_destroy_asset_cache(AssetCache* cache) {
115 mempool_del(&cache->assets); 112 mempool_del(&cache->assets);
116} 113}
117 114
118SceneNode* gfx_load_scene( 115Model* gfx_load_model(Gfx* gfx, const LoadModelCmd* cmd) {
119 Gfx* gfx, SceneNode* parent_node, const LoadSceneCmd* cmd) {
120 assert(gfx); 116 assert(gfx);
121 117
122 AssetCache* cache = gfx_get_asset_cache(gfx); 118 AssetCache* cache = gfx_get_asset_cache(gfx);
123 119
124 // First search for the asset in the cache. 120 // First search for the asset in the cache.
125 const uint64_t hash = calc_scene_hash(cmd); 121 const uint64_t hash = calc_model_hash(cmd);
126 Asset* asset = lookup_cache(cache, hash); 122 Asset* asset = lookup_cache(cache, hash);
127 if (asset) { 123 if (asset) {
128 log_scene_cache_hit(cmd, hash); 124 log_model_cache_hit(cmd, hash);
129 return (SceneNode*)asset; 125 return asset->model;
130 } 126 }
131 127
132 // Asset not found in the cache. 128 // Asset not found in the cache.
133 // Load it, insert it into the cache, and return it. 129 // Load it, insert it into the cache, and return it.
134 SceneNode* node = gfx_scene_load(gfx, parent_node, cmd); 130 Model* model = gfx_model_load(gfx, cmd);
135 if (node) { 131 if (model) {
136 *(Asset*)mempool_alloc(&cache->assets) = (Asset){ 132 *(Asset*)mempool_alloc(&cache->assets) = (Asset){
137 .type = SceneAsset, 133 .type = ModelAsset,
138 .hash = hash, 134 .hash = hash,
139 .data = node, 135 .model = model,
140 }; 136 };
141 log_scene_loaded(cmd); 137 log_model_loaded(cmd);
142 } 138 }
143 return node; 139 return model;
144} 140}
145 141
146Texture* gfx_load_texture(Gfx* gfx, const LoadTextureCmd* cmd) { 142Texture* gfx_load_texture(Gfx* gfx, const LoadTextureCmd* cmd) {
@@ -153,7 +149,7 @@ Texture* gfx_load_texture(Gfx* gfx, const LoadTextureCmd* cmd) {
153 const uint64_t hash = calc_texture_hash(cmd); 149 const uint64_t hash = calc_texture_hash(cmd);
154 Asset* asset = lookup_cache(cache, hash); 150 Asset* asset = lookup_cache(cache, hash);
155 if (asset) { 151 if (asset) {
156 return (Texture*)asset; 152 return asset->texture;
157 } 153 }
158 154
159 // Asset not found in the cache. 155 // Asset not found in the cache.
@@ -162,9 +158,9 @@ Texture* gfx_load_texture(Gfx* gfx, const LoadTextureCmd* cmd) {
162 Texture* texture = gfx_texture_load(render_backend, cmd); 158 Texture* texture = gfx_texture_load(render_backend, cmd);
163 if (texture) { 159 if (texture) {
164 *(Asset*)mempool_alloc(&cache->assets) = (Asset){ 160 *(Asset*)mempool_alloc(&cache->assets) = (Asset){
165 .type = TextureAsset, 161 .type = TextureAsset,
166 .hash = hash, 162 .hash = hash,
167 .data = texture, 163 .texture = texture,
168 }; 164 };
169 } 165 }
170 return texture; 166 return texture;
diff --git a/gfx/src/asset/asset_cache.h b/gfx/src/asset/asset_cache.h
index 04baa51..22300fd 100644
--- a/gfx/src/asset/asset_cache.h
+++ b/gfx/src/asset/asset_cache.h
@@ -5,17 +5,23 @@
5#include <cstring.h> 5#include <cstring.h>
6#include <mempool.h> 6#include <mempool.h>
7 7
8typedef struct Model Model;
9typedef struct Texture Texture;
10
8typedef uint64_t Hash; 11typedef uint64_t Hash;
9 12
10typedef enum AssetType { 13typedef enum AssetType {
11 SceneAsset, 14 ModelAsset,
12 TextureAsset, 15 TextureAsset,
13} AssetType; 16} AssetType;
14 17
15typedef struct Asset { 18typedef struct Asset {
16 AssetType type; 19 AssetType type;
17 Hash hash; 20 Hash hash;
18 void* data; 21 union {
22 Model* model;
23 Texture* texture;
24 };
19} Asset; 25} Asset;
20 26
21DEF_MEMPOOL(asset_pool, Asset, GFX_MAX_NUM_ASSETS) 27DEF_MEMPOOL(asset_pool, Asset, GFX_MAX_NUM_ASSETS)
diff --git a/gfx/src/asset/scene.c b/gfx/src/asset/scene.c
index ef2328c..290ade9 100644
--- a/gfx/src/asset/scene.c
+++ b/gfx/src/asset/scene.c
@@ -94,6 +94,8 @@
94#include "gfx/sizes.h" 94#include "gfx/sizes.h"
95#include "gfx/util/shader.h" 95#include "gfx/util/shader.h"
96 96
97#include "scene/model_impl.h"
98
97#include "cstring.h" 99#include "cstring.h"
98#include "error.h" 100#include "error.h"
99#include "log/log.h" 101#include "log/log.h"
@@ -1487,16 +1489,16 @@ static void load_nodes(
1487 } // SceneNode. 1489 } // SceneNode.
1488} 1490}
1489 1491
1490/// Load all scenes from the glTF file into the given gfx Scene. 1492/// Load all scenes from the glTF file.
1491/// 1493///
1492/// If the scene is loaded from memory, set filepath = null. 1494/// If the scene is loaded from memory, set filepath = null.
1493/// 1495///
1494/// This function ignores the many scenes and default scene of the glTF spec 1496/// This function ignores the many scenes and default scene of the glTF spec
1495/// and instead just loads all scenes into a single gfx Scene. 1497/// and instead just loads all scenes into a single Gfx Scene.
1496static SceneNode* load_scene( 1498static Model* load_scene(
1497 cgltf_data* data, Gfx* gfx, SceneNode* parent_node, const mstring* filepath, 1499 cgltf_data* data, Gfx* gfx, const mstring* filepath, ShaderProgram* shader,
1498 ShaderProgram* shader, const cgltfTangentBuffer* cgltf_tangent_buffers, 1500 const cgltfTangentBuffer* cgltf_tangent_buffers,
1499 cgltf_size num_tangent_buffers) { 1501 cgltf_size num_tangent_buffers) {
1500 // In a GLTF scene, buffers can be shared among meshes, meshes among nodes, 1502 // In a GLTF scene, buffers can be shared among meshes, meshes among nodes,
1501 // etc. Each object is referenced by its index in the relevant array. Here we 1503 // etc. Each object is referenced by its index in the relevant array. Here we
1502 // do a button-up construction, first allocating our own graphics objects in 1504 // do a button-up construction, first allocating our own graphics objects in
@@ -1540,6 +1542,7 @@ static SceneNode* load_scene(
1540 SceneNode** scene_nodes = 0; 1542 SceneNode** scene_nodes = 0;
1541 Anima* anima = 0; 1543 Anima* anima = 0;
1542 SceneNode* root_node = 0; 1544 SceneNode* root_node = 0;
1545 Model* model = 0;
1543 1546
1544 tangent_buffers = calloc(num_tangent_buffers, sizeof(Buffer*)); 1547 tangent_buffers = calloc(num_tangent_buffers, sizeof(Buffer*));
1545 buffers = calloc(data->buffers_count, sizeof(Buffer*)); 1548 buffers = calloc(data->buffers_count, sizeof(Buffer*));
@@ -1619,13 +1622,14 @@ static SceneNode* load_scene(
1619 anima = gfx_make_anima(anima_desc); 1622 anima = gfx_make_anima(anima_desc);
1620 gfx_construct_anima_node(root_node, anima); 1623 gfx_construct_anima_node(root_node, anima);
1621 } 1624 }
1622 gfx_set_node_parent(root_node, parent_node);
1623 1625
1624 // The root node becomes the root of all scene nodes. 1626 // The root node becomes the root of all scene nodes.
1625 load_nodes(data, root_node, scene_objects, scene_cameras, anima, scene_nodes); 1627 load_nodes(data, root_node, scene_objects, scene_cameras, anima, scene_nodes);
1626 1628
1627 // TODO: Clean up scene nodes that correspond to joints in the glTF. 1629 // TODO: Clean up scene nodes that correspond to joints in the glTF.
1628 1630
1631 model = gfx_make_model(root_node);
1632
1629 success = true; 1633 success = true;
1630 1634
1631cleanup: 1635cleanup:
@@ -1734,16 +1738,14 @@ cleanup:
1734 gfx_destroy_anima(&anima); 1738 gfx_destroy_anima(&anima);
1735 } 1739 }
1736 } 1740 }
1737 return root_node; 1741 return model;
1738} 1742}
1739 1743
1740SceneNode* gfx_scene_load( 1744Model* gfx_model_load(Gfx* gfx, const LoadModelCmd* cmd) {
1741 Gfx* gfx, SceneNode* parent_node, const LoadSceneCmd* cmd) {
1742 assert(gfx); 1745 assert(gfx);
1743 assert(parent_node);
1744 assert(cmd); 1746 assert(cmd);
1745 1747
1746 SceneNode* scene_node = 0; 1748 Model* model = 0;
1747 1749
1748 cgltf_options options = {0}; 1750 cgltf_options options = {0};
1749 cgltf_data* data = NULL; 1751 cgltf_data* data = NULL;
@@ -1775,8 +1777,8 @@ SceneNode* gfx_scene_load(
1775 cgltf_compute_tangents( 1777 cgltf_compute_tangents(
1776 &options, data, &tangent_buffers, &num_tangent_buffers); 1778 &options, data, &tangent_buffers, &num_tangent_buffers);
1777 1779
1778 scene_node = load_scene( 1780 model = load_scene(
1779 data, gfx, parent_node, &cmd->filepath, cmd->shader, tangent_buffers, 1781 data, gfx, &cmd->filepath, cmd->shader, tangent_buffers,
1780 num_tangent_buffers); 1782 num_tangent_buffers);
1781 1783
1782cleanup: 1784cleanup:
@@ -1786,5 +1788,5 @@ cleanup:
1786 if (tangent_buffers) { 1788 if (tangent_buffers) {
1787 free(tangent_buffers); 1789 free(tangent_buffers);
1788 } 1790 }
1789 return scene_node; 1791 return model;
1790} 1792}
diff --git a/gfx/src/asset/scene.h b/gfx/src/asset/scene.h
index 5c47196..d6399b1 100644
--- a/gfx/src/asset/scene.h
+++ b/gfx/src/asset/scene.h
@@ -3,15 +3,10 @@
3 3
4#include <gfx/asset.h> 4#include <gfx/asset.h>
5 5
6typedef struct Gfx Gfx; 6typedef struct Gfx Gfx;
7typedef struct SceneNode SceneNode; 7typedef struct Model Model;
8 8
9/// Load a scene. 9/// Load a model.
10///
11/// Return the top-level node under which scene elements are rooted.
12///
13/// |parent_node| is made the parent of the returned top-level node. It may be
14/// null.
15/// 10///
16/// Currently only supports the GLTF format. 11/// Currently only supports the GLTF format.
17SceneNode* gfx_scene_load(Gfx*, SceneNode* parent_node, const LoadSceneCmd*); 12Model* gfx_model_load(Gfx*, const LoadModelCmd*);
diff --git a/gfx/src/renderer/renderer.c b/gfx/src/renderer/renderer.c
index 5cc06d6..30704e3 100644
--- a/gfx/src/renderer/renderer.c
+++ b/gfx/src/renderer/renderer.c
@@ -1,9 +1,11 @@
1#include "renderer_impl.h" 1#include "renderer_impl.h"
2 2
3#include "scene/animation_impl.h"
3#include "scene/camera_impl.h" 4#include "scene/camera_impl.h"
4#include "scene/light_impl.h" 5#include "scene/light_impl.h"
5#include "scene/material_impl.h" 6#include "scene/material_impl.h"
6#include "scene/mesh_impl.h" 7#include "scene/mesh_impl.h"
8#include "scene/model_impl.h"
7#include "scene/node_impl.h" 9#include "scene/node_impl.h"
8#include "scene/object_impl.h" 10#include "scene/object_impl.h"
9#include "scene/scene_impl.h" 11#include "scene/scene_impl.h"
@@ -207,10 +209,12 @@ static void draw_recursively(
207 assert(state); 209 assert(state);
208 const mat4 node_transform = mat4_mul(parent_transform, node->transform); 210 const mat4 node_transform = mat4_mul(parent_transform, node->transform);
209 211
210 // Activate light. 212 // Anima.
211 if (node->type == AnimaNode) { 213 if (node->type == AnimaNode) {
212 state->anima = gfx_get_node_anima(node); 214 state->anima = gfx_get_node_anima(node);
213 } else if (node->type == LightNode) { 215 }
216 // Activate light.
217 else if (node->type == LightNode) {
214 Light* light = mem_get_light(node->light); 218 Light* light = mem_get_light(node->light);
215 assert(light); 219 assert(light);
216 220
@@ -222,6 +226,12 @@ static void draw_recursively(
222 state->environment_light = light; 226 state->environment_light = light;
223 } 227 }
224 } 228 }
229 // Model.
230 else if (node->type == ModelNode) {
231 const Model* model = gfx_get_node_model(node);
232 const SceneNode* root = mem_get_node(model->root);
233 draw_recursively(state, parent_transform, root);
234 }
225 // Render object. 235 // Render object.
226 else if (node->type == ObjectNode) { 236 else if (node->type == ObjectNode) {
227 const SceneObject* object = mem_get_object(node->object); 237 const SceneObject* object = mem_get_object(node->object);
diff --git a/gfx/src/scene/model.c b/gfx/src/scene/model.c
new file mode 100644
index 0000000..89ff0c3
--- /dev/null
+++ b/gfx/src/scene/model.c
@@ -0,0 +1,41 @@
1#include "model_impl.h"
2
3#include <gfx/scene/node.h>
4
5#include "scene_memory.h"
6
7#include <assert.h>
8
9Model* gfx_make_model(const SceneNode* root) {
10 assert(root);
11
12 Model* model = mem_alloc_model();
13 model->root = mem_get_node_index(root);
14 return model;
15}
16
17void gfx_del_model(Model** model) {
18 assert(model);
19
20 if (*model) {
21 SceneNode* root = mem_get_node((*model)->root);
22 gfx_destroy_node(&root);
23 *model = 0;
24 }
25}
26
27Anima* gfx_get_model_anima(Model* model) {
28 assert(model);
29
30 SceneNode* root = mem_get_node(model->root);
31 if (gfx_get_node_type(root) == AnimaNode) {
32 return gfx_get_node_anima(root);
33 } else {
34 return 0;
35 }
36}
37
38const SceneNode* gfx_get_model_root(const Model* model) {
39 assert(model);
40 return mem_get_node(model->root);
41}
diff --git a/gfx/src/scene/model_impl.h b/gfx/src/scene/model_impl.h
new file mode 100644
index 0000000..a99d32c
--- /dev/null
+++ b/gfx/src/scene/model_impl.h
@@ -0,0 +1,17 @@
1#pragma once
2
3#include <gfx/scene/model.h>
4
5#include "scene_memory.h"
6
7/// Model.
8typedef struct Model {
9 node_idx root;
10 node_idx parent; // Parent SceneNode.
11} Model;
12
13/// Create a new model.
14Model* gfx_make_model(const SceneNode* root);
15
16/// Destroy the model.
17void gfx_del_model(Model**);
diff --git a/gfx/src/scene/node.c b/gfx/src/scene/node.c
index 1a68216..c48d3dd 100644
--- a/gfx/src/scene/node.c
+++ b/gfx/src/scene/node.c
@@ -1,16 +1,18 @@
1#include "node_impl.h" 1#include "node_impl.h"
2 2
3#include "animation_impl.h"
3#include "camera_impl.h" 4#include "camera_impl.h"
4#include "light_impl.h" 5#include "light_impl.h"
6#include "model_impl.h"
5#include "object_impl.h" 7#include "object_impl.h"
6#include "scene_graph.h" 8#include "scene_graph.h"
7#include "scene_memory.h" 9#include "scene_memory.h"
8 10
11#include "gfx_assert.h"
12
9#include <cstring.h> 13#include <cstring.h>
10#include <log/log.h> 14#include <log/log.h>
11 15
12#include <assert.h>
13
14static void scene_node_make(SceneNode* node) { 16static void scene_node_make(SceneNode* node) {
15 assert(node); 17 assert(node);
16 node->type = LogicalNode; 18 node->type = LogicalNode;
@@ -50,6 +52,15 @@ SceneNode* gfx_make_light_node(Light* light) {
50 return node; 52 return node;
51} 53}
52 54
55SceneNode* gfx_make_model_node(Model* model) {
56 assert(model);
57 SceneNode* node = gfx_make_node();
58 node->type = ModelNode;
59 node->model = mem_get_model_index(model);
60 model->parent = mem_get_node_index(node);
61 return node;
62}
63
53SceneNode* gfx_make_object_node(SceneObject* object) { 64SceneNode* gfx_make_object_node(SceneObject* object) {
54 assert(object); 65 assert(object);
55 SceneNode* node = gfx_make_node(); 66 SceneNode* node = gfx_make_node();
@@ -70,29 +81,33 @@ static void free_node_resource(SceneNode* node) {
70 Anima* anima = mem_get_anima(node->anima); 81 Anima* anima = mem_get_anima(node->anima);
71 anima->parent.val = 0; 82 anima->parent.val = 0;
72 gfx_destroy_anima(&anima); 83 gfx_destroy_anima(&anima);
73 break; 84 return;
74 } 85 }
75 case CameraNode: { 86 case CameraNode: {
76 SceneCamera* camera = mem_get_camera(node->camera); 87 SceneCamera* camera = mem_get_camera(node->camera);
77 camera->parent.val = 0; 88 camera->parent.val = 0;
78 gfx_destroy_camera(&camera); 89 gfx_destroy_camera(&camera);
79 break; 90 return;
80 } 91 }
81 case LightNode: { 92 case LightNode: {
82 Light* light = mem_get_light(node->light); 93 Light* light = mem_get_light(node->light);
83 light->parent.val = 0; 94 light->parent.val = 0;
84 gfx_destroy_light(&light); 95 gfx_destroy_light(&light);
85 break; 96 return;
97 }
98 case ModelNode: {
99 return; // Model data is owned by the asset cache.
86 } 100 }
87 case ObjectNode: { 101 case ObjectNode: {
88 SceneObject* object = mem_get_object(node->object); 102 SceneObject* object = mem_get_object(node->object);
89 object->parent.val = 0; 103 object->parent.val = 0;
90 gfx_destroy_object(&object); 104 gfx_destroy_object(&object);
91 break; 105 return;
92 } 106 }
93 case LogicalNode: 107 case LogicalNode:
94 break; // Logical nodes have no resource. 108 return; // Logical nodes have no resource.
95 } 109 }
110 FAIL("unhandled node type");
96} 111}
97 112
98void gfx_construct_anima_node(SceneNode* node, Anima* anima) { 113void gfx_construct_anima_node(SceneNode* node, Anima* anima) {
@@ -124,6 +139,15 @@ void gfx_construct_light_node(SceneNode* node, Light* light) {
124 light->parent = mem_get_node_index(node); 139 light->parent = mem_get_node_index(node);
125} 140}
126 141
142void gfx_construct_model_node(SceneNode* node, Model* model) {
143 assert(node);
144 assert(model);
145 free_node_resource(node);
146 node->type = ModelNode;
147 node->model = mem_get_model_index(model);
148 model->parent = mem_get_node_index(node);
149}
150
127void gfx_construct_object_node(SceneNode* node, SceneObject* object) { 151void gfx_construct_object_node(SceneNode* node, SceneObject* object) {
128 assert(node); 152 assert(node);
129 assert(object); 153 assert(object);
@@ -197,6 +221,10 @@ Light* gfx_get_node_light(const SceneNode* node) {
197 NODE_GET(node, light, LightNode); 221 NODE_GET(node, light, LightNode);
198} 222}
199 223
224Model* gfx_get_node_model(const SceneNode* node) {
225 NODE_GET(node, model, ModelNode);
226}
227
200SceneObject* gfx_get_node_object(const SceneNode* node) { 228SceneObject* gfx_get_node_object(const SceneNode* node) {
201 NODE_GET(node, object, ObjectNode); 229 NODE_GET(node, object, ObjectNode);
202} 230}
@@ -283,10 +311,12 @@ static const char* get_node_type_str(NodeType type) {
283 return "CameraNode"; 311 return "CameraNode";
284 case LightNode: 312 case LightNode:
285 return "LightNode"; 313 return "LightNode";
314 case ModelNode:
315 return "ModelNode";
286 case ObjectNode: 316 case ObjectNode:
287 return "ObjectNode"; 317 return "ObjectNode";
288 } 318 }
289 assert(false); 319 FAIL("Unhandled node type");
290 return ""; 320 return "";
291} 321}
292 322
diff --git a/gfx/src/scene/node_impl.h b/gfx/src/scene/node_impl.h
index 4592fce..cabdc60 100644
--- a/gfx/src/scene/node_impl.h
+++ b/gfx/src/scene/node_impl.h
@@ -17,6 +17,7 @@ typedef struct SceneNode {
17 anima_idx anima; 17 anima_idx anima;
18 camera_idx camera; 18 camera_idx camera;
19 light_idx light; 19 light_idx light;
20 model_idx model;
20 object_idx object; 21 object_idx object;
21 }; 22 };
22 mat4 transform; // Transformation for this node and its children. 23 mat4 transform; // Transformation for this node and its children.
diff --git a/gfx/src/scene/scene.c b/gfx/src/scene/scene.c
index a6801ba..54452dd 100644
--- a/gfx/src/scene/scene.c
+++ b/gfx/src/scene/scene.c
@@ -23,22 +23,3 @@ SceneNode* gfx_get_scene_root(Scene* scene) {
23 assert(scene); 23 assert(scene);
24 return scene->root; 24 return scene->root;
25} 25}
26
27static void gfx_animate_node(SceneNode* node, R t) {
28 assert(node);
29
30 if (gfx_get_node_type(node) == AnimaNode) {
31 gfx_update_animation(gfx_get_node_anima(node), t);
32 }
33
34 for (NodeIter it = gfx_get_node_child(node); it;
35 it = gfx_get_next_child(it)) {
36 gfx_animate_node(gfx_get_iter_node_mut(it), t);
37 }
38}
39
40void gfx_animate_scene(Scene* scene, R t) {
41 assert(scene);
42 SceneNode* node = gfx_get_scene_root(scene);
43 gfx_animate_node(node, t);
44}
diff --git a/gfx/src/scene/scene_memory.c b/gfx/src/scene/scene_memory.c
index 2b900b9..3030a8a 100644
--- a/gfx/src/scene/scene_memory.c
+++ b/gfx/src/scene/scene_memory.c
@@ -7,6 +7,7 @@
7#include "light_impl.h" 7#include "light_impl.h"
8#include "material_impl.h" 8#include "material_impl.h"
9#include "mesh_impl.h" 9#include "mesh_impl.h"
10#include "model_impl.h"
10#include "node_impl.h" 11#include "node_impl.h"
11#include "object_impl.h" 12#include "object_impl.h"
12#include "scene_impl.h" 13#include "scene_impl.h"
@@ -20,6 +21,7 @@ DEF_MEMPOOL(light_pool, Light, GFX_MAX_NUM_LIGHTS)
20DEF_MEMPOOL(material_pool, Material, GFX_MAX_NUM_MATERIALS) 21DEF_MEMPOOL(material_pool, Material, GFX_MAX_NUM_MATERIALS)
21DEF_MEMPOOL(mesh_pool, Mesh, GFX_MAX_NUM_MESHES) 22DEF_MEMPOOL(mesh_pool, Mesh, GFX_MAX_NUM_MESHES)
22DEF_MEMPOOL(mesh_link_pool, MeshLink, GFX_MAX_NUM_MESH_LINKS) 23DEF_MEMPOOL(mesh_link_pool, MeshLink, GFX_MAX_NUM_MESH_LINKS)
24DEF_MEMPOOL(model_pool, Model, GFX_MAX_NUM_MODELS)
23DEF_MEMPOOL(node_pool, SceneNode, GFX_MAX_NUM_NODES) 25DEF_MEMPOOL(node_pool, SceneNode, GFX_MAX_NUM_NODES)
24DEF_MEMPOOL(object_pool, SceneObject, GFX_MAX_NUM_OBJECTS) 26DEF_MEMPOOL(object_pool, SceneObject, GFX_MAX_NUM_OBJECTS)
25DEF_MEMPOOL(scene_pool, Scene, GFX_MAX_NUM_SCENES) 27DEF_MEMPOOL(scene_pool, Scene, GFX_MAX_NUM_SCENES)
@@ -36,6 +38,7 @@ typedef struct SceneMemory {
36 material_pool materials; 38 material_pool materials;
37 mesh_pool meshs; // Purposeful typo to make the PLURAL() macro work. 39 mesh_pool meshs; // Purposeful typo to make the PLURAL() macro work.
38 mesh_link_pool mesh_links; 40 mesh_link_pool mesh_links;
41 model_pool models;
39 node_pool nodes; 42 node_pool nodes;
40 object_pool objects; 43 object_pool objects;
41 scene_pool scenes; 44 scene_pool scenes;
@@ -61,6 +64,7 @@ void scene_mem_init() {
61 mempool_make(&mem.materials); 64 mempool_make(&mem.materials);
62 mempool_make(&mem.meshs); 65 mempool_make(&mem.meshs);
63 mempool_make(&mem.mesh_links); 66 mempool_make(&mem.mesh_links);
67 mempool_make(&mem.models);
64 mempool_make(&mem.nodes); 68 mempool_make(&mem.nodes);
65 mempool_make(&mem.objects); 69 mempool_make(&mem.objects);
66 mempool_make(&mem.scenes); 70 mempool_make(&mem.scenes);
@@ -75,6 +79,7 @@ void scene_mem_init() {
75 ALLOC_DUMMY(&mem.materials); 79 ALLOC_DUMMY(&mem.materials);
76 ALLOC_DUMMY(&mem.meshs); 80 ALLOC_DUMMY(&mem.meshs);
77 ALLOC_DUMMY(&mem.mesh_links); 81 ALLOC_DUMMY(&mem.mesh_links);
82 ALLOC_DUMMY(&mem.models);
78 ALLOC_DUMMY(&mem.nodes); 83 ALLOC_DUMMY(&mem.nodes);
79 ALLOC_DUMMY(&mem.objects); 84 ALLOC_DUMMY(&mem.objects);
80 ALLOC_DUMMY(&mem.scenes); 85 ALLOC_DUMMY(&mem.scenes);
@@ -92,6 +97,9 @@ void scene_mem_destroy() {
92 } \ 97 } \
93 }) 98 })
94 99
100 // Models contain scene elements. Destruction is handled by the remainder of
101 // scene destructionb elow.
102 //
95 // First destroy the scenes. This will recursively destroy the scene's nodes 103 // First destroy the scenes. This will recursively destroy the scene's nodes
96 // and their objects and avoid a double-free when we then destroy any stray 104 // and their objects and avoid a double-free when we then destroy any stray
97 // scene elements. 105 // scene elements.
@@ -135,6 +143,7 @@ DEF_MEMORY(light, Light)
135DEF_MEMORY(material, Material) 143DEF_MEMORY(material, Material)
136DEF_MEMORY(mesh, Mesh) 144DEF_MEMORY(mesh, Mesh)
137DEF_MEMORY(mesh_link, MeshLink) 145DEF_MEMORY(mesh_link, MeshLink)
146DEF_MEMORY(model, Model)
138DEF_MEMORY(node, SceneNode) 147DEF_MEMORY(node, SceneNode)
139DEF_MEMORY(object, SceneObject) 148DEF_MEMORY(object, SceneObject)
140DEF_MEMORY(scene, Scene) 149DEF_MEMORY(scene, Scene)
diff --git a/gfx/src/scene/scene_memory.h b/gfx/src/scene/scene_memory.h
index 04dbd20..d175cba 100644
--- a/gfx/src/scene/scene_memory.h
+++ b/gfx/src/scene/scene_memory.h
@@ -1,7 +1,6 @@
1/// Memory management of scene objects. 1/// Memory management of scene objects.
2#pragma once 2#pragma once
3 3
4#include "animation_impl.h"
5#include "types.h" 4#include "types.h"
6 5
7/// Initialize scene memory. 6/// Initialize scene memory.
@@ -33,6 +32,7 @@ DECL_MEMORY(light, Light)
33DECL_MEMORY(material, Material) 32DECL_MEMORY(material, Material)
34DECL_MEMORY(mesh, Mesh) 33DECL_MEMORY(mesh, Mesh)
35DECL_MEMORY(mesh_link, MeshLink) 34DECL_MEMORY(mesh_link, MeshLink)
35DECL_MEMORY(model, Model)
36DECL_MEMORY(node, SceneNode) 36DECL_MEMORY(node, SceneNode)
37DECL_MEMORY(object, SceneObject) 37DECL_MEMORY(object, SceneObject)
38DECL_MEMORY(scene, Scene) 38DECL_MEMORY(scene, Scene)
diff --git a/gfx/src/scene/types.h b/gfx/src/scene/types.h
index cd87430..9752bcf 100644
--- a/gfx/src/scene/types.h
+++ b/gfx/src/scene/types.h
@@ -18,6 +18,7 @@ DEF_STRONG_INDEX(light, gfx_idx)
18DEF_STRONG_INDEX(material, gfx_idx) 18DEF_STRONG_INDEX(material, gfx_idx)
19DEF_STRONG_INDEX(mesh, gfx_idx) 19DEF_STRONG_INDEX(mesh, gfx_idx)
20DEF_STRONG_INDEX(mesh_link, gfx_idx) 20DEF_STRONG_INDEX(mesh_link, gfx_idx)
21DEF_STRONG_INDEX(model, gfx_idx)
21DEF_STRONG_INDEX(node, gfx_idx) 22DEF_STRONG_INDEX(node, gfx_idx)
22DEF_STRONG_INDEX(object, gfx_idx) 23DEF_STRONG_INDEX(object, gfx_idx)
23DEF_STRONG_INDEX(scene, gfx_idx) 24DEF_STRONG_INDEX(scene, gfx_idx)