diff options
Diffstat (limited to 'src/asset/model.c')
-rw-r--r-- | src/asset/model.c | 1968 |
1 files changed, 1968 insertions, 0 deletions
diff --git a/src/asset/model.c b/src/asset/model.c new file mode 100644 index 0000000..25f2780 --- /dev/null +++ b/src/asset/model.c | |||
@@ -0,0 +1,1968 @@ | |||
1 | /// Loads scenes from memory and files. | ||
2 | /// | ||
3 | /// Only the GLTF scene format is current supported. | ||
4 | /// | ||
5 | /// ---------------------------------------------------------------------------- | ||
6 | /// glTF File Format Documentation | ||
7 | /// ---------------------------------------------------------------------------- | ||
8 | /// | ||
9 | /// cgltf: | ||
10 | /// https://github.com/jkuhlmann/cgltf | ||
11 | /// | ||
12 | /// gltf overview: | ||
13 | /// https://raw.githubusercontent.com/KhronosGroup/glTF/master/specification/2.0/figures/gltfOverview-2.0.0b.png | ||
14 | /// | ||
15 | /// gltf spec: | ||
16 | /// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md | ||
17 | /// | ||
18 | /// Sample models: | ||
19 | /// https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0 | ||
20 | /// https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Sponza/glTF/Sponza.gltf | ||
21 | /// https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/AlphaBlendModeTest/glTF/AlphaBlendModeTest.gltf | ||
22 | /// https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Buggy/glTF/Buggy.gltf | ||
23 | /// https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/AntiqueCamera/glTF/AntiqueCamera.gltf | ||
24 | /// https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf | ||
25 | /// | ||
26 | /// ---------------------------------------------------------------------------- | ||
27 | /// Implementation Notes | ||
28 | /// ---------------------------------------------------------------------------- | ||
29 | /// | ||
30 | /// # glTF and the gfx library | ||
31 | /// | ||
32 | /// glTF has concepts that are similar to those in the gfx library, but there | ||
33 | /// isn't an exact 1-1 mapping. Concepts map as follows: | ||
34 | /// | ||
35 | /// glTF gfx | ||
36 | /// ---- --- | ||
37 | /// buffer Buffer | ||
38 | /// accessor + buffer view BufferView | ||
39 | /// mesh primitive (geom + mat) Mesh (also geom + mat) | ||
40 | /// mesh SceneObject | ||
41 | /// node SceneNode | ||
42 | /// | ||
43 | /// glTF buffers map 1-1 with gfx Buffers. glTF scenes make heavy re-use of | ||
44 | /// buffers across views/accessors/meshes, so it is important to make that same | ||
45 | /// re-use in the gfx library to use the data effectively and without | ||
46 | /// duplication. The Sponza scene, for example, has all of its data in one giant | ||
47 | /// buffer. | ||
48 | /// | ||
49 | /// glTF accessors and buffer views are combined and mapped to gfx BufferViews. | ||
50 | /// The glTF buffer view's offset/length/stride are combined with the accessor's | ||
51 | /// offset, and together with the remaining information of both data structures | ||
52 | /// baked into a BufferView. Internally, this information is fed into | ||
53 | /// glVertexAttribPointer() calls, wrapped in a VAO (index view/accessor | ||
54 | /// information is fed into glDrawElements()). This baking should not hurt | ||
55 | /// re-use, at least in the OpenGL world. | ||
56 | /// | ||
57 | /// A glTF mesh primitive contains a piece of geometry and a material. This maps | ||
58 | /// directly to a gfx Mesh. | ||
59 | /// | ||
60 | /// A glTF mesh is a list of mesh primitives. This maps nicely to a gfx | ||
61 | /// SceneObject, with the only inconvenience that terminology gets a little | ||
62 | /// confusing. | ||
63 | /// | ||
64 | /// Finally, glTF nodes map directly to gfx SceneNodes. Both enforce a strict | ||
65 | /// tree hierarchy; DAGs are not supported. | ||
66 | /// | ||
67 | /// # Materials | ||
68 | /// | ||
69 | /// glTF uses the metallic-roughness material model. However, an extension | ||
70 | /// allows a scene to use the specular-glossiness model as well and cgltf | ||
71 | /// supports it: | ||
72 | /// | ||
73 | /// https://kcoley.github.io/glTF/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/ | ||
74 | /// | ||
75 | /// From the docs, the specular-glossiness model can represent more materials | ||
76 | /// than the metallic-roughness model, but it is also more computationally | ||
77 | /// expensive. Furthermore, a material in glTF can specify parameters for both | ||
78 | /// models, leaving it up to the implementation to decide which one to use. | ||
79 | /// In our case, we use the specular-glosiness model if parameters for it are | ||
80 | /// provided, otherwise we use the metallic-roughness model. | ||
81 | |||
82 | #include "asset/model.h" | ||
83 | |||
84 | #include "asset/texture.h" | ||
85 | #include "gfx/core.h" | ||
86 | #include "gfx/gfx.h" | ||
87 | #include "gfx/scene/animation.h" | ||
88 | #include "gfx/scene/camera.h" | ||
89 | #include "gfx/scene/material.h" | ||
90 | #include "gfx/scene/mesh.h" | ||
91 | #include "gfx/scene/node.h" | ||
92 | #include "gfx/scene/object.h" | ||
93 | #include "gfx/scene/scene.h" | ||
94 | #include "gfx/sizes.h" | ||
95 | #include "gfx/util/shader.h" | ||
96 | |||
97 | #include "gfx_assert.h" | ||
98 | #include "scene/model_impl.h" | ||
99 | |||
100 | #include "cstring.h" | ||
101 | #include "error.h" | ||
102 | #include "log/log.h" | ||
103 | #include "math/camera.h" | ||
104 | #include "math/defs.h" | ||
105 | #include "math/mat4.h" | ||
106 | #include "math/quat.h" | ||
107 | #include "math/vec2.h" | ||
108 | #include "math/vec3.h" | ||
109 | |||
110 | #include "cgltf_tangents.h" | ||
111 | #define CGLTF_IMPLEMENTATION | ||
112 | #include "cgltf.h" | ||
113 | |||
114 | #include <stdbool.h> | ||
115 | #include <stdlib.h> | ||
116 | |||
117 | // Taken from the GL header file. | ||
118 | #define GL_NEAREST 0x2600 | ||
119 | #define GL_LINEAR 0x2601 | ||
120 | #define GL_NEAREST_MIPMAP_NEAREST 0x2700 | ||
121 | #define GL_LINEAR_MIPMAP_NEAREST 0x2701 | ||
122 | #define GL_NEAREST_MIPMAP_LINEAR 0x2702 | ||
123 | #define GL_LINEAR_MIPMAP_LINEAR 0x2703 | ||
124 | |||
125 | // Uniforms names. Must match the names in shaders. | ||
126 | #define UNIFORM_BASE_COLOR_FACTOR "BaseColorFactor" | ||
127 | #define UNIFORM_METALLIC_FACTOR "MetallicFactor" | ||
128 | #define UNIFORM_ROUGHNESS_FACTOR "RoughnessFactor" | ||
129 | #define UNIFORM_EMISSIVE_FACTOR "EmissiveFactor" | ||
130 | #define UNIFORM_BASE_COLOR_TEXTURE "BaseColorTexture" | ||
131 | #define UNIFORM_METALLIC_ROUGHNESS_TEXTURE "MetallicRoughnessTexture" | ||
132 | #define UNIFORM_EMISSIVE_TEXTURE "EmissiveTexture" | ||
133 | #define UNIFORM_AMBIENT_OCCLUSION_TEXTURE "AmbientOcclusionTexture" | ||
134 | #define UNIFORM_NORMAL_MAP "NormalMap" | ||
135 | |||
136 | // Shader compiler defines. Must match the names in shaders. | ||
137 | #define DEFINE_HAS_TEXCOORDS "HAS_TEXCOORDS" | ||
138 | #define DEFINE_HAS_NORMALS "HAS_NORMALS" | ||
139 | #define DEFINE_HAS_TANGENTS "HAS_TANGENTS" | ||
140 | #define DEFINE_HAS_ALBEDO_MAP "HAS_ALBEDO_MAP" | ||
141 | #define DEFINE_HAS_METALLIC_ROUGHNESS_MAP "HAS_METALLIC_ROUGHNESS_MAP" | ||
142 | #define DEFINE_HAS_NORMAL_MAP "HAS_NORMAL_MAP" | ||
143 | #define DEFINE_HAS_OCCLUSION_MAP "HAS_OCCLUSION_MAP" | ||
144 | #define DEFINE_HAS_EMISSIVE_MAP "HAS_EMISSIVE_MAP" | ||
145 | #define DEFINE_HAS_JOINTS "HAS_JOINTS" | ||
146 | #define DEFINE_MAX_JOINTS "MAX_JOINTS" | ||
147 | |||
148 | typedef enum TextureType { | ||
149 | BaseColorTexture, | ||
150 | MetallicRoughnessTexture, | ||
151 | EmissiveTexture, | ||
152 | AmbientOcclusionTexture, | ||
153 | NormalMap, | ||
154 | } TextureType; | ||
155 | |||
156 | /// Describes the properties of a mesh. | ||
157 | /// This is used to create shader permutations. | ||
158 | typedef struct MeshPermutation { | ||
159 | union { | ||
160 | struct { | ||
161 | // Vertex attributes. | ||
162 | bool has_texcoords : 1; | ||
163 | bool has_normals : 1; | ||
164 | bool has_tangents : 1; | ||
165 | bool has_joints : 1; | ||
166 | bool has_weights : 1; | ||
167 | // Textures. | ||
168 | bool has_albedo_map : 1; | ||
169 | bool has_metallic_roughness_map : 1; | ||
170 | bool has_normal_map : 1; | ||
171 | bool has_occlusion_map : 1; | ||
172 | bool has_emissive_map : 1; | ||
173 | }; | ||
174 | int32_t all; | ||
175 | }; | ||
176 | } MeshPermutation; | ||
177 | |||
178 | /// Build shader compiler defines from a mesh permutation. | ||
179 | static size_t make_defines( | ||
180 | MeshPermutation perm, ShaderCompilerDefine* defines) { | ||
181 | static const char* str_true = "1"; | ||
182 | size_t next = 0; | ||
183 | |||
184 | #define check(field, define) \ | ||
185 | if (perm.field) { \ | ||
186 | defines[next].name = sstring_make(define); \ | ||
187 | defines[next].value = sstring_make(str_true); \ | ||
188 | next++; \ | ||
189 | } | ||
190 | check(has_texcoords, DEFINE_HAS_TEXCOORDS); | ||
191 | check(has_normals, DEFINE_HAS_NORMALS); | ||
192 | check(has_tangents, DEFINE_HAS_TANGENTS); | ||
193 | check(has_joints, DEFINE_HAS_JOINTS); | ||
194 | check(has_albedo_map, DEFINE_HAS_ALBEDO_MAP); | ||
195 | check(has_metallic_roughness_map, DEFINE_HAS_METALLIC_ROUGHNESS_MAP); | ||
196 | check(has_normal_map, DEFINE_HAS_NORMAL_MAP); | ||
197 | check(has_occlusion_map, DEFINE_HAS_OCCLUSION_MAP); | ||
198 | check(has_emissive_map, DEFINE_HAS_EMISSIVE_MAP); | ||
199 | |||
200 | if (perm.has_joints) { | ||
201 | defines[next].name = sstring_make(DEFINE_MAX_JOINTS); | ||
202 | defines[next].value = sstring_itoa(GFX_MAX_NUM_JOINTS); | ||
203 | next++; | ||
204 | } | ||
205 | |||
206 | return next; | ||
207 | } | ||
208 | |||
209 | /// Compile a shader permutation. | ||
210 | static ShaderProgram* make_shader_permutation( | ||
211 | GfxCore* gfxcore, MeshPermutation perm) { | ||
212 | LOGD( | ||
213 | "Compiling Cook-Torrance shader permutation: texcoords: %d, normals: " | ||
214 | "%d, tangents: %d, joints: %d, weights: %d, albedo map: %d, " | ||
215 | "metallic-roughness map: " | ||
216 | "%d, normal " | ||
217 | "map: %d, AO map: %d, emissive map: %d", | ||
218 | perm.has_texcoords, perm.has_normals, perm.has_tangents, perm.has_joints, | ||
219 | perm.has_weights, perm.has_albedo_map, perm.has_metallic_roughness_map, | ||
220 | perm.has_normal_map, perm.has_occlusion_map, perm.has_emissive_map); | ||
221 | |||
222 | ShaderCompilerDefine defines[GFX_MAX_SHADER_COMPILER_DEFINES]; | ||
223 | const size_t num_defines = make_defines(perm, defines); | ||
224 | return gfx_make_cook_torrance_shader_perm(gfxcore, defines, num_defines); | ||
225 | } | ||
226 | |||
227 | /// Map a texture type to the name of the shader uniform used to access the | ||
228 | /// texture. | ||
229 | static const char* get_texture_uniform_name(TextureType type) { | ||
230 | switch (type) { | ||
231 | case BaseColorTexture: | ||
232 | return UNIFORM_BASE_COLOR_TEXTURE; | ||
233 | case MetallicRoughnessTexture: | ||
234 | return UNIFORM_METALLIC_ROUGHNESS_TEXTURE; | ||
235 | case EmissiveTexture: | ||
236 | return UNIFORM_EMISSIVE_TEXTURE; | ||
237 | case AmbientOcclusionTexture: | ||
238 | return UNIFORM_AMBIENT_OCCLUSION_TEXTURE; | ||
239 | case NormalMap: | ||
240 | return UNIFORM_NORMAL_MAP; | ||
241 | } | ||
242 | assert(false); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | /// Map a glTF primitive type to a gfx primitive type. | ||
247 | static PrimitiveType from_gltf_primitive_type(cgltf_primitive_type type) { | ||
248 | switch (type) { | ||
249 | case cgltf_primitive_type_triangles: | ||
250 | return Triangles; | ||
251 | case cgltf_primitive_type_triangle_fan: | ||
252 | return TriangleFan; | ||
253 | case cgltf_primitive_type_triangle_strip: | ||
254 | return TriangleStrip; | ||
255 | // Not yet implemented. | ||
256 | case cgltf_primitive_type_lines: | ||
257 | case cgltf_primitive_type_line_loop: | ||
258 | case cgltf_primitive_type_line_strip: | ||
259 | case cgltf_primitive_type_points: | ||
260 | break; | ||
261 | } | ||
262 | LOGE("Unsupported primitive type: %d", type); | ||
263 | assert(false); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | /// Map a glTF animation path type to its Gfx equivalent. | ||
268 | static ChannelType from_gltf_animation_path_type( | ||
269 | cgltf_animation_path_type type) { | ||
270 | switch (type) { | ||
271 | case cgltf_animation_path_type_translation: | ||
272 | return TranslationChannel; | ||
273 | case cgltf_animation_path_type_rotation: | ||
274 | return RotationChannel; | ||
275 | case cgltf_animation_path_type_scale: | ||
276 | return ScaleChannel; | ||
277 | case cgltf_animation_path_type_weights: | ||
278 | return WeightsChannel; | ||
279 | case cgltf_animation_path_type_invalid: | ||
280 | assert(false); | ||
281 | break; | ||
282 | } | ||
283 | assert(false); | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | /// Map a glTF interpolation to its Gfx equivalent. | ||
288 | static AnimationInterpolation from_gltf_interpolation_type( | ||
289 | cgltf_interpolation_type type) { | ||
290 | switch (type) { | ||
291 | case cgltf_interpolation_type_linear: | ||
292 | return LinearInterpolation; | ||
293 | case cgltf_interpolation_type_step: | ||
294 | return StepInterpolation; | ||
295 | case cgltf_interpolation_type_cubic_spline: | ||
296 | return CubicSplineInterpolation; | ||
297 | } | ||
298 | assert(false); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /// Return the component's size in bytes. | ||
303 | static cgltf_size get_component_size(cgltf_component_type type) { | ||
304 | switch (type) { | ||
305 | case cgltf_component_type_r_8: | ||
306 | return 1; | ||
307 | case cgltf_component_type_r_8u: | ||
308 | return 1; | ||
309 | case cgltf_component_type_r_16: | ||
310 | return 2; | ||
311 | case cgltf_component_type_r_16u: | ||
312 | return 2; | ||
313 | case cgltf_component_type_r_32u: | ||
314 | return 4; | ||
315 | case cgltf_component_type_r_32f: | ||
316 | return 4; | ||
317 | case cgltf_component_type_invalid: | ||
318 | assert(false); | ||
319 | break; | ||
320 | } | ||
321 | assert(false); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | /// Return the number dimensionality of the given data type. | ||
326 | int get_num_dimensions(cgltf_type type) { | ||
327 | switch (type) { | ||
328 | case cgltf_type_scalar: | ||
329 | return 1; | ||
330 | case cgltf_type_vec2: | ||
331 | return 2; | ||
332 | case cgltf_type_vec3: | ||
333 | return 3; | ||
334 | case cgltf_type_vec4: | ||
335 | return 4; | ||
336 | case cgltf_type_mat2: | ||
337 | return 4; // 2x2 | ||
338 | case cgltf_type_mat3: | ||
339 | return 9; // 3x3 | ||
340 | case cgltf_type_mat4: | ||
341 | return 16; // 4x4 | ||
342 | case cgltf_type_invalid: | ||
343 | FAIL(); | ||
344 | break; | ||
345 | } | ||
346 | FAIL(); | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | /// Read an int64 from the given data pointer and accessor. | ||
351 | /// The largest integer in glTF is u32, so we can fit all integers in an int64. | ||
352 | static int64_t read_int(const void* component, const cgltf_accessor* accessor) { | ||
353 | assert(component); | ||
354 | assert(accessor); | ||
355 | |||
356 | switch (accessor->component_type) { | ||
357 | case cgltf_component_type_r_8: { | ||
358 | const int8_t c = *((int8_t*)component); | ||
359 | return c; | ||
360 | } | ||
361 | case cgltf_component_type_r_8u: { | ||
362 | const uint8_t c = *((uint8_t*)component); | ||
363 | return c; | ||
364 | } | ||
365 | case cgltf_component_type_r_16: { | ||
366 | const int16_t c = *((int16_t*)component); | ||
367 | return c; | ||
368 | } | ||
369 | case cgltf_component_type_r_16u: { | ||
370 | const uint16_t c = *((uint16_t*)component); | ||
371 | return c; | ||
372 | } | ||
373 | case cgltf_component_type_r_32u: { | ||
374 | const uint32_t c = *((uint32_t*)component); | ||
375 | return c; | ||
376 | } | ||
377 | case cgltf_component_type_r_32f: { | ||
378 | const float c = *((float*)component); | ||
379 | return (int64_t)c; | ||
380 | } | ||
381 | case cgltf_component_type_invalid: | ||
382 | FAIL(); | ||
383 | break; | ||
384 | } | ||
385 | FAIL(); | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | /// Read a float from the given data pointer and accessor. | ||
390 | /// | ||
391 | /// This function uses the normalization equations from the spec. See the | ||
392 | /// animation section: | ||
393 | /// | ||
394 | /// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#animations | ||
395 | static float read_float(const void* component, const cgltf_accessor* accessor) { | ||
396 | assert(component); | ||
397 | assert(accessor); | ||
398 | |||
399 | switch (accessor->component_type) { | ||
400 | case cgltf_component_type_r_8: { | ||
401 | // assert(accessor->normalized); | ||
402 | const int8_t c = *((int8_t*)component); | ||
403 | return max((float)c / 127.0, -1.0); | ||
404 | } | ||
405 | case cgltf_component_type_r_8u: { | ||
406 | // assert(accessor->normalized); | ||
407 | const uint8_t c = *((uint8_t*)component); | ||
408 | return (float)c / 255.0; | ||
409 | } | ||
410 | case cgltf_component_type_r_16: { | ||
411 | // assert(accessor->normalized); | ||
412 | const int16_t c = *((int16_t*)component); | ||
413 | return max((float)c / 32767.0, -1.0); | ||
414 | } | ||
415 | case cgltf_component_type_r_16u: { | ||
416 | // assert(accessor->normalized); | ||
417 | const uint16_t c = *((uint16_t*)component); | ||
418 | return (float)c / 65535.0; | ||
419 | } | ||
420 | case cgltf_component_type_r_32u: { | ||
421 | // assert(accessor->normalized); | ||
422 | const uint32_t c = *((uint32_t*)component); | ||
423 | return (float)c / 4294967295.0; | ||
424 | } | ||
425 | case cgltf_component_type_r_32f: { | ||
426 | const float c = *((float*)component); | ||
427 | return c; | ||
428 | } | ||
429 | case cgltf_component_type_invalid: | ||
430 | FAIL(); | ||
431 | break; | ||
432 | } | ||
433 | FAIL(); | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | typedef struct AccessorIter { | ||
438 | const cgltf_accessor* accessor; | ||
439 | const uint8_t* next_element; | ||
440 | cgltf_size comp_size; // Component size in bytes. | ||
441 | cgltf_size stride; // ELement stride in bytes. | ||
442 | cgltf_size index; // Index of the next element. | ||
443 | bool is_matrix; | ||
444 | } AccessorIter; | ||
445 | |||
446 | typedef struct AccessorData { | ||
447 | union { | ||
448 | struct { | ||
449 | float x, y, z, w; // Possibly normalized. | ||
450 | int64_t xi, yi, zi, wi; // Always unnormalized. | ||
451 | }; | ||
452 | const float* floats; | ||
453 | }; | ||
454 | } AccessorData; | ||
455 | |||
456 | bool accessor_iter_next(AccessorIter* iter, AccessorData* data) { | ||
457 | assert(iter); | ||
458 | assert(data); | ||
459 | |||
460 | if (iter->index < iter->accessor->count) { | ||
461 | const int dimensions = get_num_dimensions(iter->accessor->type); | ||
462 | const uint8_t* component = iter->next_element; | ||
463 | |||
464 | // So that the caller can access the element's components as an array. | ||
465 | data->floats = (const float*)component; | ||
466 | |||
467 | if (!iter->is_matrix) { // Scalar or vector. | ||
468 | // x | ||
469 | data->x = read_float(component, iter->accessor); | ||
470 | data->xi = read_int(component, iter->accessor); | ||
471 | component += iter->comp_size; | ||
472 | // y | ||
473 | if (dimensions > 1) { | ||
474 | data->y = read_float(component, iter->accessor); | ||
475 | data->yi = read_int(component, iter->accessor); | ||
476 | component += iter->comp_size; | ||
477 | } | ||
478 | // z | ||
479 | if (dimensions > 2) { | ||
480 | data->z = read_float(component, iter->accessor); | ||
481 | data->zi = read_int(component, iter->accessor); | ||
482 | component += iter->comp_size; | ||
483 | } | ||
484 | // w | ||
485 | if (dimensions > 3) { | ||
486 | data->w = read_float(component, iter->accessor); | ||
487 | data->wi = read_int(component, iter->accessor); | ||
488 | component += iter->comp_size; | ||
489 | } | ||
490 | } | ||
491 | |||
492 | iter->next_element += iter->stride; | ||
493 | iter->index++; | ||
494 | return true; | ||
495 | } | ||
496 | |||
497 | return false; | ||
498 | } | ||
499 | |||
500 | AccessorIter make_accessor_iter(const cgltf_accessor* accessor) { | ||
501 | assert(accessor); | ||
502 | |||
503 | const bool is_matrix = (accessor->type == cgltf_type_mat2) || | ||
504 | (accessor->type == cgltf_type_mat3) || | ||
505 | (accessor->type == cgltf_type_mat4); | ||
506 | |||
507 | const int dimensions = get_num_dimensions(accessor->type); | ||
508 | assert( | ||
509 | ((dimensions == 1) && (accessor->type == cgltf_type_scalar)) || | ||
510 | ((dimensions == 2) && (accessor->type == cgltf_type_vec2)) || | ||
511 | ((dimensions == 3) && (accessor->type == cgltf_type_vec3)) || | ||
512 | ((dimensions == 4) && (accessor->type == cgltf_type_vec4)) || | ||
513 | ((dimensions == 4) && (accessor->type == cgltf_type_mat2)) || | ||
514 | ((dimensions == 9) && (accessor->type == cgltf_type_mat3)) || | ||
515 | ((dimensions == 16) && (accessor->type == cgltf_type_mat4))); | ||
516 | |||
517 | const cgltf_buffer_view* view = accessor->buffer_view; | ||
518 | const cgltf_buffer* buffer = view->buffer; | ||
519 | const cgltf_size offset = accessor->offset + view->offset; | ||
520 | const uint8_t* bytes = (const uint8_t*)buffer->data + offset; | ||
521 | // Component size in bytes. | ||
522 | const cgltf_size comp_size = get_component_size(accessor->component_type); | ||
523 | // Element size in bytes. | ||
524 | const cgltf_size elem_size = dimensions * comp_size; | ||
525 | // Stride in bytes. If the view stride is 0, then the elements are tightly | ||
526 | // packed. | ||
527 | const cgltf_size stride = view->stride != 0 ? view->stride : elem_size; | ||
528 | |||
529 | // There isn't an accessor stride in the spec, but cgltf still specifies one. | ||
530 | assert(accessor->stride == elem_size); | ||
531 | |||
532 | // Accessor data must fit inside the view. | ||
533 | assert(accessor->offset + (accessor->count * accessor->stride) <= view->size); | ||
534 | |||
535 | // Accessor data must fit inside the buffer. | ||
536 | assert( | ||
537 | (offset + (accessor->count * elem_size) + | ||
538 | ((accessor->count - 1) * view->stride)) <= buffer->size); | ||
539 | |||
540 | return (AccessorIter){ | ||
541 | .accessor = accessor, | ||
542 | .next_element = bytes, | ||
543 | .comp_size = comp_size, | ||
544 | .stride = stride, | ||
545 | .index = 0, | ||
546 | .is_matrix = is_matrix, | ||
547 | }; | ||
548 | } | ||
549 | |||
550 | /// Return the total number of primitives in the scene. Each mesh may contain | ||
551 | /// multiple primitives. | ||
552 | /// | ||
553 | /// Note that this function scans all of the scenes in the glTF data. | ||
554 | static size_t get_total_primitives(const cgltf_data* data) { | ||
555 | size_t total = 0; | ||
556 | for (cgltf_size i = 0; i < data->meshes_count; ++i) { | ||
557 | total += data->meshes[i].primitives_count; | ||
558 | } | ||
559 | return total; | ||
560 | } | ||
561 | |||
562 | /// Load all buffers from the glTF scene. | ||
563 | /// | ||
564 | /// If buffer data is loaded from memory, set filepath = null. | ||
565 | /// | ||
566 | /// Return an array of Buffers such that the index of each glTF buffer in the | ||
567 | /// original array matches the same Buffer in the resulting array. | ||
568 | /// | ||
569 | /// TODO: There is no need to load the inverse bind matrices buffer into the | ||
570 | /// GPU. Might need to lazily load buffers. | ||
571 | static bool load_buffers( | ||
572 | const cgltf_data* data, GfxCore* gfxcore, Buffer** buffers) { | ||
573 | assert(data); | ||
574 | assert(gfxcore); | ||
575 | assert(buffers); | ||
576 | |||
577 | for (cgltf_size i = 0; i < data->buffers_count; ++i) { | ||
578 | const cgltf_buffer* buffer = &data->buffers[i]; | ||
579 | assert(buffer->data); | ||
580 | buffers[i] = gfx_make_buffer( | ||
581 | gfxcore, &(BufferDesc){ | ||
582 | .usage = BufferStatic, | ||
583 | .type = BufferUntyped, | ||
584 | .data.data = buffer->data, | ||
585 | .data.count = buffer->size}); | ||
586 | if (!buffers[i]) { | ||
587 | return false; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | return true; | ||
592 | } | ||
593 | |||
594 | /// Load tangent buffers. | ||
595 | static bool load_tangent_buffers( | ||
596 | const cgltfTangentBuffer* cgltf_tangent_buffers, | ||
597 | cgltf_size num_tangent_buffers, GfxCore* gfxcore, | ||
598 | Buffer** tangent_buffers) { | ||
599 | assert(cgltf_tangent_buffers); | ||
600 | assert(gfxcore); | ||
601 | assert(tangent_buffers); | ||
602 | |||
603 | for (cgltf_size i = 0; i < num_tangent_buffers; ++i) { | ||
604 | const cgltfTangentBuffer* buffer = &cgltf_tangent_buffers[i]; | ||
605 | assert(buffer->data); | ||
606 | tangent_buffers[i] = gfx_make_buffer( | ||
607 | gfxcore, &(BufferDesc){ | ||
608 | .usage = BufferStatic, | ||
609 | .type = BufferUntyped, | ||
610 | .data.data = buffer->data, | ||
611 | .data.count = buffer->size_bytes}); | ||
612 | if (!tangent_buffers[i]) { | ||
613 | return false; | ||
614 | } | ||
615 | } | ||
616 | |||
617 | return true; | ||
618 | } | ||
619 | |||
620 | /// Lazily load all textures from the glTF scene. | ||
621 | /// | ||
622 | /// Colour textures like albedo are in sRGB colour space. Non-colour textures | ||
623 | /// like normal maps are in linear space (e.g. DamagedHelmet sample). Since we | ||
624 | /// don't know how the texture is going to be used at this point, we can't tell | ||
625 | /// what colour space it should be loaded in (ideally this would be part of the | ||
626 | /// image file format, but not all formats specify colour space.) Therefore, we | ||
627 | /// load the textures lazily and don't actually commit them to GPU memory until | ||
628 | /// we know their colour space when loading glTF materials. | ||
629 | /// | ||
630 | /// Return an array of LoadTextureCmds such that the index of each cmd matches | ||
631 | /// the index of each glTF texture in the scene. | ||
632 | static void load_textures_lazy( | ||
633 | const cgltf_data* data, GfxCore* gfxcore, const char* directory, | ||
634 | LoadTextureCmd* load_texture_cmds) { | ||
635 | assert(data); | ||
636 | assert(gfxcore); | ||
637 | assert(load_texture_cmds); | ||
638 | |||
639 | for (cgltf_size i = 0; i < data->textures_count; ++i) { | ||
640 | const cgltf_texture* texture = &data->textures[i]; | ||
641 | const cgltf_image* image = texture->image; | ||
642 | const cgltf_sampler* sampler = texture->sampler; | ||
643 | |||
644 | // glTF models might not specify a sampler. In such case, the client can | ||
645 | // pick its own defaults. | ||
646 | // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#samplers | ||
647 | bool mipmaps = true; | ||
648 | TextureFiltering filtering = LinearFiltering; | ||
649 | TextureWrapping wrap = Repeat; | ||
650 | |||
651 | if (sampler) { | ||
652 | // The gfx library does not distinguish between sampling the texture and | ||
653 | // combining the mipmap levels. | ||
654 | const cgltf_int filter = | ||
655 | sampler->min_filter == 0 ? sampler->mag_filter : sampler->min_filter; | ||
656 | |||
657 | switch (filter) { | ||
658 | case GL_NEAREST_MIPMAP_NEAREST: | ||
659 | mipmaps = true; | ||
660 | filtering = NearestFiltering; | ||
661 | break; | ||
662 | case GL_NEAREST_MIPMAP_LINEAR: | ||
663 | case GL_LINEAR_MIPMAP_NEAREST: | ||
664 | case GL_LINEAR_MIPMAP_LINEAR: | ||
665 | mipmaps = true; | ||
666 | filtering = LinearFiltering; | ||
667 | break; | ||
668 | case GL_NEAREST: | ||
669 | filtering = NearestFiltering; | ||
670 | break; | ||
671 | case GL_LINEAR: | ||
672 | filtering = LinearFiltering; | ||
673 | break; | ||
674 | default: | ||
675 | break; | ||
676 | } | ||
677 | } | ||
678 | |||
679 | // Currently only supporting loading textures from files. | ||
680 | assert(image->uri); | ||
681 | assert(directory); | ||
682 | mstring fullpath = | ||
683 | mstring_concat_path(mstring_make(directory), mstring_make(image->uri)); | ||
684 | |||
685 | load_texture_cmds[i] = (LoadTextureCmd){ | ||
686 | .origin = AssetFromFile, | ||
687 | .type = LoadTexture, | ||
688 | .colour_space = sRGB, | ||
689 | .filtering = filtering, | ||
690 | .wrap = wrap, | ||
691 | .mipmaps = mipmaps, | ||
692 | .data.texture.filepath = fullpath}; | ||
693 | } | ||
694 | } | ||
695 | |||
696 | /// Load a texture uniform. | ||
697 | /// | ||
698 | /// This determines a texture's colour space based on its intended use, loads | ||
699 | /// the texture, and then defines the sampler shader uniform. | ||
700 | static bool load_texture_and_uniform( | ||
701 | const cgltf_data* data, Gfx* gfx, const cgltf_texture_view* texture_view, | ||
702 | TextureType texture_type, const Texture** textures, | ||
703 | LoadTextureCmd* load_texture_cmds, int* next_uniform, MaterialDesc* desc) { | ||
704 | assert(data); | ||
705 | assert(gfx); | ||
706 | assert(texture_view); | ||
707 | assert(textures); | ||
708 | assert(next_uniform); | ||
709 | assert(desc); | ||
710 | assert(*next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
711 | |||
712 | const size_t texture_index = texture_view->texture - data->textures; | ||
713 | assert(texture_index < data->textures_count); | ||
714 | |||
715 | // Here we are assuming that if a texture is re-used, it is re-used with the | ||
716 | // same texture view. This should be fine because, e.g., a normal map would | ||
717 | // not be used as albedo and vice versa. | ||
718 | if (!textures[texture_index]) { | ||
719 | LoadTextureCmd* cmd = &load_texture_cmds[texture_index]; | ||
720 | // TODO: Check for colour textures and default to LinearColourSpace instead. | ||
721 | if (texture_type == NormalMap) { | ||
722 | cmd->colour_space = LinearColourSpace; | ||
723 | } | ||
724 | |||
725 | LOGD( | ||
726 | "Load texture: %s (mipmaps: %d, filtering: %d)", | ||
727 | mstring_cstr(&cmd->data.texture.filepath), cmd->mipmaps, | ||
728 | cmd->filtering); | ||
729 | |||
730 | textures[texture_index] = gfx_load_texture(gfx, cmd); | ||
731 | if (!textures[texture_index]) { | ||
732 | log_error( | ||
733 | "Failed to load texture: %s", | ||
734 | mstring_cstr(&cmd->data.texture.filepath)); | ||
735 | return false; | ||
736 | } | ||
737 | } | ||
738 | |||
739 | assert(*next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
740 | desc->uniforms[(*next_uniform)++] = (ShaderUniform){ | ||
741 | .name = sstring_make(get_texture_uniform_name(texture_type)), | ||
742 | .type = UniformTexture, | ||
743 | .value.texture = textures[texture_index]}; | ||
744 | |||
745 | return true; | ||
746 | } | ||
747 | |||
748 | /// Load all materials from the glTF scene. | ||
749 | /// | ||
750 | /// Return an array of Materials such that the index of each descriptor matches | ||
751 | /// the index of each glTF material in the scene. Also return the number of | ||
752 | /// materials and the textures used by them. | ||
753 | static bool load_materials( | ||
754 | const cgltf_data* data, Gfx* gfx, LoadTextureCmd* load_texture_cmds, | ||
755 | const Texture** textures, Material** materials) { | ||
756 | assert(data); | ||
757 | assert(gfx); | ||
758 | assert(materials); | ||
759 | if (data->textures_count > 0) { | ||
760 | assert(load_texture_cmds); | ||
761 | assert(textures); | ||
762 | } | ||
763 | |||
764 | for (cgltf_size i = 0; i < data->materials_count; ++i) { | ||
765 | const cgltf_material* mat = &data->materials[i]; | ||
766 | |||
767 | int next_uniform = 0; | ||
768 | MaterialDesc desc = {0}; | ||
769 | |||
770 | // TODO: specular/glossiness and other material parameters. | ||
771 | if (mat->has_pbr_metallic_roughness) { | ||
772 | const cgltf_pbr_metallic_roughness* pbr = &mat->pbr_metallic_roughness; | ||
773 | |||
774 | assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
775 | desc.uniforms[next_uniform++] = (ShaderUniform){ | ||
776 | .name = sstring_make(UNIFORM_BASE_COLOR_FACTOR), | ||
777 | .type = UniformVec4, | ||
778 | .value.vec4 = vec4_from_array(pbr->base_color_factor)}; | ||
779 | |||
780 | assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
781 | desc.uniforms[next_uniform++] = (ShaderUniform){ | ||
782 | .name = sstring_make(UNIFORM_METALLIC_FACTOR), | ||
783 | .type = UniformFloat, | ||
784 | .value.scalar = pbr->metallic_factor}; | ||
785 | |||
786 | assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
787 | desc.uniforms[next_uniform++] = (ShaderUniform){ | ||
788 | .name = sstring_make(UNIFORM_ROUGHNESS_FACTOR), | ||
789 | .type = UniformFloat, | ||
790 | .value.scalar = pbr->roughness_factor}; | ||
791 | |||
792 | assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
793 | desc.uniforms[next_uniform++] = (ShaderUniform){ | ||
794 | .name = sstring_make(UNIFORM_EMISSIVE_FACTOR), | ||
795 | .type = UniformVec3, | ||
796 | .value.vec3 = vec3_from_array(mat->emissive_factor)}; | ||
797 | |||
798 | if (pbr->base_color_texture.texture) { | ||
799 | if (!load_texture_and_uniform( | ||
800 | data, gfx, &pbr->base_color_texture, BaseColorTexture, textures, | ||
801 | load_texture_cmds, &next_uniform, &desc)) { | ||
802 | return false; | ||
803 | } | ||
804 | } | ||
805 | |||
806 | if (pbr->metallic_roughness_texture.texture) { | ||
807 | if (!load_texture_and_uniform( | ||
808 | data, gfx, &pbr->metallic_roughness_texture, | ||
809 | MetallicRoughnessTexture, textures, load_texture_cmds, | ||
810 | &next_uniform, &desc)) { | ||
811 | return false; | ||
812 | } | ||
813 | } | ||
814 | } | ||
815 | |||
816 | if (mat->emissive_texture.texture) { | ||
817 | if (!load_texture_and_uniform( | ||
818 | data, gfx, &mat->emissive_texture, EmissiveTexture, textures, | ||
819 | load_texture_cmds, &next_uniform, &desc)) { | ||
820 | return false; | ||
821 | } | ||
822 | } | ||
823 | |||
824 | if (mat->occlusion_texture.texture) { | ||
825 | if (!load_texture_and_uniform( | ||
826 | data, gfx, &mat->occlusion_texture, AmbientOcclusionTexture, | ||
827 | textures, load_texture_cmds, &next_uniform, &desc)) { | ||
828 | return false; | ||
829 | } | ||
830 | } | ||
831 | |||
832 | if (mat->normal_texture.texture) { | ||
833 | if (!load_texture_and_uniform( | ||
834 | data, gfx, &mat->normal_texture, NormalMap, textures, | ||
835 | load_texture_cmds, &next_uniform, &desc)) { | ||
836 | return false; | ||
837 | } | ||
838 | } | ||
839 | |||
840 | assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
841 | desc.num_uniforms = next_uniform; | ||
842 | |||
843 | materials[i] = gfx_make_material(&desc); | ||
844 | if (!materials[i]) { | ||
845 | return false; | ||
846 | } | ||
847 | } | ||
848 | |||
849 | return true; | ||
850 | } | ||
851 | |||
852 | /// Create a default material for meshes that do not have a material. | ||
853 | static Material* make_default_material() { | ||
854 | MaterialDesc desc = (MaterialDesc){0}; | ||
855 | |||
856 | assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
857 | desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ | ||
858 | .name = sstring_make(UNIFORM_BASE_COLOR_FACTOR), | ||
859 | .type = UniformVec4, | ||
860 | .value.vec4 = vec4_make(1, 1, 1, 1)}; | ||
861 | |||
862 | assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
863 | desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ | ||
864 | .name = sstring_make(UNIFORM_METALLIC_FACTOR), | ||
865 | .type = UniformFloat, | ||
866 | .value.scalar = 0}; | ||
867 | |||
868 | assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
869 | desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ | ||
870 | .name = sstring_make(UNIFORM_ROUGHNESS_FACTOR), | ||
871 | .type = UniformFloat, | ||
872 | .value.scalar = 1}; | ||
873 | |||
874 | assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
875 | desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ | ||
876 | .name = sstring_make(UNIFORM_EMISSIVE_FACTOR), | ||
877 | .type = UniformVec3, | ||
878 | .value.vec3 = vec3_make(0, 0, 0)}; | ||
879 | |||
880 | return gfx_make_material(&desc); | ||
881 | } | ||
882 | |||
883 | /// Compute the bounding box of the vertices pointed to by the accessor. | ||
884 | /// 'dim' is the dimension of the vertices (2D or 3D). | ||
885 | aabb3 compute_aabb(const cgltf_accessor* accessor) { | ||
886 | aabb3 box = {0}; | ||
887 | if (accessor->has_min && accessor->has_max) { | ||
888 | box = aabb3_make( | ||
889 | vec3_from_array(accessor->min), vec3_from_array(accessor->max)); | ||
890 | } else { | ||
891 | AccessorIter iter = make_accessor_iter(accessor); | ||
892 | AccessorData vertex = {0}; | ||
893 | cgltf_size i = 0; | ||
894 | |||
895 | while (accessor_iter_next(&iter, &vertex)) { | ||
896 | const vec3 p = vec3_make(vertex.x, vertex.y, vertex.z); | ||
897 | if (i == 0) { | ||
898 | box = aabb3_make(p, p); | ||
899 | } else { | ||
900 | box = aabb3_add(box, p); | ||
901 | } | ||
902 | ++i; | ||
903 | } | ||
904 | } | ||
905 | return box; | ||
906 | } | ||
907 | |||
908 | /// Load all meshes from the glTF scene. | ||
909 | static bool load_meshes( | ||
910 | const cgltf_data* data, GfxCore* gfxcore, Buffer** buffers, | ||
911 | Buffer** tangent_buffers, const cgltfTangentBuffer* cgltf_tangent_buffers, | ||
912 | cgltf_size num_tangent_buffers, Material** materials, | ||
913 | ShaderProgram* const shader, size_t primitive_count, Geometry** geometries, | ||
914 | Mesh** meshes, SceneObject** scene_objects) { | ||
915 | // Walk through the mesh primitives to create Meshes. A GLTF mesh primitive | ||
916 | // has a material (Mesh) and vertex data (Geometry). A GLTF mesh maps to | ||
917 | // a SceneObject. | ||
918 | // | ||
919 | // glTF gfx | ||
920 | // ---- --- | ||
921 | // Mesh SceneObject | ||
922 | // Mesh primitive Mesh / Geometry | ||
923 | // Accessor + buffer view BufferView | ||
924 | // Buffer Buffer | ||
925 | assert(data); | ||
926 | assert(gfxcore); | ||
927 | assert(buffers); | ||
928 | assert(materials); | ||
929 | assert(geometries); | ||
930 | assert(meshes); | ||
931 | assert(scene_objects); | ||
932 | if (num_tangent_buffers > 0) { | ||
933 | assert(tangent_buffers); | ||
934 | assert(cgltf_tangent_buffers); | ||
935 | } | ||
936 | |||
937 | // Points to the next available Mesh and also the next available Geometry. | ||
938 | // There is one (Mesh, Geometry) pair per glTF mesh primitive. | ||
939 | size_t next_mesh = 0; | ||
940 | |||
941 | for (cgltf_size m = 0; m < data->meshes_count; ++m) { | ||
942 | const cgltf_mesh* mesh = &data->meshes[m]; | ||
943 | |||
944 | ObjectDesc object_desc = {0}; | ||
945 | |||
946 | for (cgltf_size p = 0; p < mesh->primitives_count; ++p) { | ||
947 | assert(next_mesh < primitive_count); | ||
948 | const cgltf_primitive* prim = &mesh->primitives[p]; | ||
949 | const cgltf_material* mat = prim->material; | ||
950 | |||
951 | MeshPermutation perm = {0}; | ||
952 | if (mat) { | ||
953 | perm.has_normal_map = mat->normal_texture.texture != 0; | ||
954 | perm.has_occlusion_map = mat->occlusion_texture.texture != 0; | ||
955 | perm.has_emissive_map = mat->emissive_texture.texture != 0; | ||
956 | |||
957 | if (mat->has_pbr_metallic_roughness) { | ||
958 | const cgltf_pbr_metallic_roughness* pbr = | ||
959 | &mat->pbr_metallic_roughness; | ||
960 | perm.has_albedo_map = pbr->base_color_texture.texture != 0; | ||
961 | perm.has_metallic_roughness_map = | ||
962 | pbr->metallic_roughness_texture.texture != 0; | ||
963 | } else { | ||
964 | // TODO: specular/glossiness and other material parameters. | ||
965 | } | ||
966 | } | ||
967 | |||
968 | GeometryDesc geometry_desc = { | ||
969 | .type = from_gltf_primitive_type(prim->type), | ||
970 | .buffer_usage = BufferStatic}; | ||
971 | |||
972 | // Vertex indices. | ||
973 | if (prim->indices) { | ||
974 | const cgltf_accessor* accessor = prim->indices; | ||
975 | const cgltf_buffer_view* view = prim->indices->buffer_view; | ||
976 | const cgltf_size buffer_index = view->buffer - data->buffers; | ||
977 | |||
978 | assert(buffer_index < data->buffers_count); | ||
979 | Buffer* buffer = buffers[buffer_index]; | ||
980 | |||
981 | const cgltf_size component_size = | ||
982 | get_component_size(accessor->component_type); | ||
983 | switch (component_size) { | ||
984 | case 1: { | ||
985 | BufferViewIdx8* indices = &geometry_desc.indices8; | ||
986 | // TODO: discards const qualifier. | ||
987 | indices->buffer = buffer; | ||
988 | indices->offset_bytes = accessor->offset + view->offset; | ||
989 | indices->size_bytes = view->size; | ||
990 | indices->stride_bytes = view->stride; | ||
991 | geometry_desc.num_indices = prim->indices->count; | ||
992 | break; | ||
993 | } | ||
994 | case 2: { | ||
995 | BufferViewIdx16* indices = &geometry_desc.indices16; | ||
996 | indices->buffer = buffer; | ||
997 | indices->offset_bytes = accessor->offset + view->offset; | ||
998 | indices->size_bytes = view->size; | ||
999 | indices->stride_bytes = view->stride; | ||
1000 | geometry_desc.num_indices = prim->indices->count; | ||
1001 | break; | ||
1002 | } | ||
1003 | default: | ||
1004 | // TODO: Handle 32-bit indices. | ||
1005 | assert(false); | ||
1006 | break; | ||
1007 | } | ||
1008 | } | ||
1009 | |||
1010 | // Vertex attributes. | ||
1011 | for (cgltf_size a = 0; a < prim->attributes_count; ++a) { | ||
1012 | const cgltf_attribute* attrib = &prim->attributes[a]; | ||
1013 | const cgltf_accessor* accessor = attrib->data; | ||
1014 | const cgltf_buffer_view* view = accessor->buffer_view; | ||
1015 | const cgltf_size offset = accessor->offset + view->offset; | ||
1016 | const cgltf_size buffer_index = view->buffer - data->buffers; | ||
1017 | |||
1018 | assert(buffer_index < data->buffers_count); | ||
1019 | Buffer* buffer = buffers[buffer_index]; | ||
1020 | |||
1021 | BufferView2d* buffer_view_2d = 0; | ||
1022 | BufferView3d* buffer_view_3d = 0; | ||
1023 | BufferView4d* buffer_view_4d = 0; | ||
1024 | BufferViewFloat* buffer_view_float = 0; | ||
1025 | BufferViewU8* buffer_view_u8 = 0; | ||
1026 | BufferViewU16* buffer_view_u16 = 0; | ||
1027 | |||
1028 | switch (attrib->type) { | ||
1029 | case cgltf_attribute_type_position: { | ||
1030 | switch (accessor->type) { | ||
1031 | case cgltf_type_vec2: | ||
1032 | assert(geometry_desc.positions3d.buffer == 0); | ||
1033 | buffer_view_2d = &geometry_desc.positions2d; | ||
1034 | geometry_desc.aabb = compute_aabb(accessor); | ||
1035 | break; | ||
1036 | case cgltf_type_vec3: | ||
1037 | assert(geometry_desc.positions2d.buffer == 0); | ||
1038 | buffer_view_3d = &geometry_desc.positions3d; | ||
1039 | geometry_desc.aabb = compute_aabb(accessor); | ||
1040 | break; | ||
1041 | default: | ||
1042 | FAIL( | ||
1043 | "Unhandled accessor type %d in vertex positions", | ||
1044 | accessor->type); | ||
1045 | assert(false); | ||
1046 | return false; | ||
1047 | } | ||
1048 | // It is assumed that meshes have positions, so there is nothing to | ||
1049 | // do for the mesh permutation in this case. | ||
1050 | break; | ||
1051 | } | ||
1052 | case cgltf_attribute_type_normal: | ||
1053 | buffer_view_3d = &geometry_desc.normals; | ||
1054 | perm.has_normals = true; | ||
1055 | break; | ||
1056 | case cgltf_attribute_type_tangent: | ||
1057 | buffer_view_4d = &geometry_desc.tangents; | ||
1058 | perm.has_tangents = true; | ||
1059 | break; | ||
1060 | case cgltf_attribute_type_texcoord: | ||
1061 | buffer_view_2d = &geometry_desc.texcoords; | ||
1062 | perm.has_texcoords = true; | ||
1063 | break; | ||
1064 | case cgltf_attribute_type_color: | ||
1065 | // TODO: Add support for color. | ||
1066 | break; | ||
1067 | case cgltf_attribute_type_joints: | ||
1068 | // Joints can be either u8 or u16. | ||
1069 | switch (accessor->component_type) { | ||
1070 | case cgltf_component_type_r_8u: | ||
1071 | buffer_view_u8 = &geometry_desc.joints.u8; | ||
1072 | break; | ||
1073 | case cgltf_component_type_r_16u: | ||
1074 | buffer_view_u16 = &geometry_desc.joints.u16; | ||
1075 | break; | ||
1076 | default: | ||
1077 | assert(false); | ||
1078 | return false; | ||
1079 | } | ||
1080 | perm.has_joints = true; | ||
1081 | break; | ||
1082 | case cgltf_attribute_type_weights: | ||
1083 | // Weights can be either u8, u16, or float. | ||
1084 | switch (accessor->component_type) { | ||
1085 | case cgltf_component_type_r_8u: | ||
1086 | buffer_view_u8 = &geometry_desc.weights.u8; | ||
1087 | break; | ||
1088 | case cgltf_component_type_r_16u: | ||
1089 | buffer_view_u16 = &geometry_desc.weights.u16; | ||
1090 | break; | ||
1091 | case cgltf_component_type_r_32f: | ||
1092 | buffer_view_float = &geometry_desc.weights.floats; | ||
1093 | break; | ||
1094 | default: | ||
1095 | assert(false); | ||
1096 | return false; | ||
1097 | } | ||
1098 | perm.has_weights = true; | ||
1099 | break; | ||
1100 | case cgltf_attribute_type_invalid: | ||
1101 | assert(false); | ||
1102 | break; | ||
1103 | } | ||
1104 | |||
1105 | #define CONFIGURE_BUFFER(buf) \ | ||
1106 | if (buf) { \ | ||
1107 | buf->buffer = buffer; \ | ||
1108 | buf->offset_bytes = offset; \ | ||
1109 | buf->size_bytes = view->size; \ | ||
1110 | buf->stride_bytes = view->stride; \ | ||
1111 | } | ||
1112 | CONFIGURE_BUFFER(buffer_view_2d); | ||
1113 | CONFIGURE_BUFFER(buffer_view_3d); | ||
1114 | CONFIGURE_BUFFER(buffer_view_4d); | ||
1115 | CONFIGURE_BUFFER(buffer_view_u8); | ||
1116 | CONFIGURE_BUFFER(buffer_view_u16); | ||
1117 | CONFIGURE_BUFFER(buffer_view_float); | ||
1118 | } // Vertex attributes. | ||
1119 | |||
1120 | assert( | ||
1121 | (perm.has_joints && perm.has_weights) || | ||
1122 | (!perm.has_joints && !perm.has_weights)); | ||
1123 | |||
1124 | // If the mesh primitive has no tangents, see if they were computed | ||
1125 | // separately. | ||
1126 | if (!geometry_desc.tangents.buffer) { | ||
1127 | for (cgltf_size t = 0; t < num_tangent_buffers; ++t) { | ||
1128 | const cgltfTangentBuffer* cgltf_buffer = &cgltf_tangent_buffers[t]; | ||
1129 | |||
1130 | if (cgltf_buffer->primitive == prim) { | ||
1131 | BufferView4d* view = &geometry_desc.tangents; | ||
1132 | view->buffer = tangent_buffers[t]; | ||
1133 | view->offset_bytes = 0; | ||
1134 | view->size_bytes = cgltf_buffer->size_bytes; | ||
1135 | view->stride_bytes = 0; // Tightly packed. | ||
1136 | break; | ||
1137 | } | ||
1138 | } | ||
1139 | } | ||
1140 | |||
1141 | // Set the number of vertices in the geometry. Since a geometry can have | ||
1142 | // either 2d or 3d positions but not both, here we can perform addition | ||
1143 | // to compute the total number of vertices. | ||
1144 | geometry_desc.num_verts = | ||
1145 | (geometry_desc.positions2d.size_bytes / sizeof(vec2)) + | ||
1146 | (geometry_desc.positions3d.size_bytes / sizeof(vec3)); | ||
1147 | |||
1148 | #define CHECK_COUNT(buffer_view, type, num_components) \ | ||
1149 | if (geometry_desc.buffer_view.buffer) { \ | ||
1150 | assert( \ | ||
1151 | (geometry_desc.buffer_view.size_bytes / \ | ||
1152 | (num_components * sizeof(type))) == geometry_desc.num_verts); \ | ||
1153 | } | ||
1154 | |||
1155 | // Check that the number of vertices is consistent across all vertex | ||
1156 | // attributes. | ||
1157 | CHECK_COUNT(normals, vec3, 1); | ||
1158 | CHECK_COUNT(tangents, vec4, 1); | ||
1159 | CHECK_COUNT(texcoords, vec2, 1); | ||
1160 | CHECK_COUNT(joints.u8, uint8_t, 4); | ||
1161 | CHECK_COUNT(joints.u16, uint16_t, 4); | ||
1162 | CHECK_COUNT(weights.u8, uint8_t, 4); | ||
1163 | CHECK_COUNT(weights.u16, uint16_t, 4); | ||
1164 | CHECK_COUNT(weights.floats, float, 4); | ||
1165 | |||
1166 | Material* material = 0; | ||
1167 | if (mat) { | ||
1168 | const cgltf_size material_index = mat - data->materials; | ||
1169 | assert(material_index < data->materials_count); | ||
1170 | material = materials[material_index]; | ||
1171 | } else { | ||
1172 | // Create a default material for meshes that do not specify one. | ||
1173 | material = make_default_material(); | ||
1174 | } | ||
1175 | assert(material); | ||
1176 | |||
1177 | geometries[next_mesh] = gfx_make_geometry(gfxcore, &geometry_desc); | ||
1178 | if (!geometries[next_mesh]) { | ||
1179 | return false; | ||
1180 | } | ||
1181 | |||
1182 | // If the user specifies a custom shader, use that instead. Otherwise | ||
1183 | // compile a shader based on the mesh's permutation. | ||
1184 | // | ||
1185 | // Note that Gfx takes care of caching shaders and shader programs. | ||
1186 | // | ||
1187 | // Caching materials could be useful, but, provided they can share | ||
1188 | // shaders, the renderer can check later whether uniforms have the same | ||
1189 | // values. Also, changing uniforms is much faster than swapping shaders, | ||
1190 | // so shader caching is the most important thing here. | ||
1191 | ShaderProgram* mesh_shader = | ||
1192 | shader ? shader : make_shader_permutation(gfxcore, perm); | ||
1193 | assert(mesh_shader); | ||
1194 | |||
1195 | meshes[next_mesh] = gfx_make_mesh(&(MeshDesc){ | ||
1196 | .geometry = geometries[next_mesh], | ||
1197 | .material = material, | ||
1198 | .shader = mesh_shader}); | ||
1199 | |||
1200 | if (!meshes[next_mesh]) { | ||
1201 | return false; | ||
1202 | } | ||
1203 | |||
1204 | assert(object_desc.num_meshes < GFX_MAX_NUM_MESHES); | ||
1205 | object_desc.meshes[object_desc.num_meshes] = meshes[next_mesh]; | ||
1206 | object_desc.num_meshes++; | ||
1207 | |||
1208 | ++next_mesh; | ||
1209 | } // glTF mesh primitive / gfx Mesh. | ||
1210 | |||
1211 | scene_objects[m] = gfx_make_object(&object_desc); | ||
1212 | if (!scene_objects[m]) { | ||
1213 | return false; | ||
1214 | } | ||
1215 | } // glTF mesh / gfx SceneObject. | ||
1216 | |||
1217 | return true; | ||
1218 | } | ||
1219 | |||
1220 | /// Compute bounding boxes for the joints in the model. | ||
1221 | static void compute_joint_bounding_boxes( | ||
1222 | const cgltf_data* data, size_t num_joints, JointDesc* joint_descs) { | ||
1223 | assert(data); | ||
1224 | assert(joint_descs); | ||
1225 | assert(num_joints <= GFX_MAX_NUM_JOINTS); | ||
1226 | |||
1227 | // Initialize bounding boxes so that we can compute unions below. | ||
1228 | for (size_t i = 0; i < num_joints; ++i) { | ||
1229 | joint_descs[i].box = aabb3_make_empty(); | ||
1230 | } | ||
1231 | |||
1232 | // Iterate over the meshes -> primitives -> vertices -> joint indices, and add | ||
1233 | // the vertex to the joint's bounding box. | ||
1234 | for (cgltf_size n = 0; n < data->nodes_count; ++n) { | ||
1235 | const cgltf_node* node = &data->nodes[n]; | ||
1236 | |||
1237 | if (node->skin) { | ||
1238 | if (node->mesh) { | ||
1239 | const cgltf_mesh* mesh = node->mesh; | ||
1240 | |||
1241 | for (cgltf_size pr = 0; pr < mesh->primitives_count; ++pr) { | ||
1242 | const cgltf_primitive* prim = &mesh->primitives[pr]; | ||
1243 | |||
1244 | // Find the indices of the positions and joints arrays in the | ||
1245 | // primitive's attributes. | ||
1246 | int positions_index = -1; | ||
1247 | int joints_index = -1; | ||
1248 | for (int a = 0; a < (int)prim->attributes_count; ++a) { | ||
1249 | const cgltf_attribute* attrib = &prim->attributes[a]; | ||
1250 | |||
1251 | if (attrib->type == cgltf_attribute_type_position) { | ||
1252 | positions_index = a; | ||
1253 | } else if (attrib->type == cgltf_attribute_type_joints) { | ||
1254 | joints_index = a; | ||
1255 | } | ||
1256 | } | ||
1257 | |||
1258 | if ((positions_index != -1) && (joints_index != -1)) { | ||
1259 | const cgltf_accessor* positions = | ||
1260 | prim->attributes[positions_index].data; | ||
1261 | const cgltf_accessor* joints = prim->attributes[joints_index].data; | ||
1262 | |||
1263 | assert(positions->count == joints->count); | ||
1264 | |||
1265 | AccessorIter positions_iter = make_accessor_iter(positions); | ||
1266 | AccessorIter joints_iter = make_accessor_iter(joints); | ||
1267 | AccessorData position = {0}, joint = {0}; | ||
1268 | |||
1269 | while (accessor_iter_next(&positions_iter, &position)) { | ||
1270 | const bool advance = accessor_iter_next(&joints_iter, &joint); | ||
1271 | assert(advance); // Counts should match. | ||
1272 | |||
1273 | const vec3 p = vec3_make(position.x, position.y, position.z); | ||
1274 | const int64_t j[4] = {joint.xi, joint.yi, joint.wi, joint.zi}; | ||
1275 | |||
1276 | for (int i = 0; i < 4; ++i) { | ||
1277 | const size_t joint_index = j[i]; | ||
1278 | assert((size_t)joint_index < num_joints); | ||
1279 | |||
1280 | joint_descs[joint_index].box = | ||
1281 | aabb3_add(joint_descs[joint_index].box, p); | ||
1282 | } | ||
1283 | } | ||
1284 | } | ||
1285 | } | ||
1286 | } | ||
1287 | } | ||
1288 | } | ||
1289 | } | ||
1290 | |||
1291 | /// Find the joint node with the smallest index across all skeletons. | ||
1292 | /// | ||
1293 | /// The channels in glTF may target arbitrary nodes in the scene (those nodes | ||
1294 | /// are the joints). However, we want to map the "base joint" (the joint/node | ||
1295 | /// with the smallest index) to 0 in the AnimaDesc's joint array. We can do this | ||
1296 | /// by subtracting the "base node index" from every joint index or channel | ||
1297 | /// target. | ||
1298 | /// | ||
1299 | /// There is an assumption in the animation library that joints are contiguous | ||
1300 | /// anyway, so this "base joint index" works provided the joint nodes are also | ||
1301 | /// contiguous in the glTF. The glTF does not guarantee this, but I think it's | ||
1302 | /// a reasonable assumption that exporters write glTF files in such a way, and | ||
1303 | /// Blender does appear to do so. | ||
1304 | cgltf_size find_base_joint_index(const cgltf_data* data) { | ||
1305 | assert(data); | ||
1306 | |||
1307 | cgltf_size base_joint_index = (cgltf_size)-1; | ||
1308 | |||
1309 | for (cgltf_size s = 0; s < data->skins_count; ++s) { | ||
1310 | const cgltf_skin* skin = &data->skins[s]; | ||
1311 | for (cgltf_size j = 0; j < skin->joints_count; ++j) { | ||
1312 | // Joint is an index/pointer into the nodes array. | ||
1313 | const cgltf_size node_index = skin->joints[j] - data->nodes; | ||
1314 | assert(node_index < data->nodes_count); | ||
1315 | // Min. | ||
1316 | if (node_index < base_joint_index) { | ||
1317 | base_joint_index = node_index; | ||
1318 | } | ||
1319 | } | ||
1320 | } | ||
1321 | |||
1322 | return base_joint_index; | ||
1323 | } | ||
1324 | |||
1325 | /// Load all skins (Gfx skeletons) from the glTF scene. | ||
1326 | /// Return the total number of joints. | ||
1327 | static size_t load_skins( | ||
1328 | const cgltf_data* data, Buffer* const* buffers, cgltf_size base_joint_index, | ||
1329 | AnimaDesc* anima_desc) { | ||
1330 | assert(data); | ||
1331 | assert(buffers); | ||
1332 | assert(anima_desc); | ||
1333 | assert(base_joint_index < data->nodes_count); | ||
1334 | |||
1335 | // Determines whether the ith joint in the node hierarchy is a joint node. | ||
1336 | // This is then used to determine whether a joint is a root of the joint | ||
1337 | // hierarchy. | ||
1338 | bool is_joint_node[GFX_MAX_NUM_JOINTS] = {false}; | ||
1339 | |||
1340 | size_t num_joints = 0; | ||
1341 | |||
1342 | for (cgltf_size s = 0; s < data->skins_count; ++s) { | ||
1343 | const cgltf_skin* skin = &data->skins[s]; | ||
1344 | const cgltf_accessor* matrices_accessor = skin->inverse_bind_matrices; | ||
1345 | assert(matrices_accessor->count == skin->joints_count); | ||
1346 | |||
1347 | num_joints += skin->joints_count; | ||
1348 | assert(num_joints < GFX_MAX_NUM_JOINTS); | ||
1349 | |||
1350 | SkeletonDesc* skeleton_desc = &anima_desc->skeletons[s]; | ||
1351 | *skeleton_desc = (SkeletonDesc){.num_joints = skin->joints_count}; | ||
1352 | |||
1353 | // for (cgltf_size j = 0; j < skin->joints_count; ++j) { | ||
1354 | AccessorIter iter = make_accessor_iter(matrices_accessor); | ||
1355 | AccessorData matrix = {0}; | ||
1356 | for (cgltf_size i = 0; accessor_iter_next(&iter, &matrix); ++i) { | ||
1357 | const mat4 inv_bind_matrix = mat4_from_array(matrix.floats); | ||
1358 | |||
1359 | // Joint is an index/pointer into the nodes array. | ||
1360 | const cgltf_size node_index = skin->joints[i] - data->nodes; | ||
1361 | assert(node_index < data->nodes_count); | ||
1362 | |||
1363 | const cgltf_size parent_node_index = | ||
1364 | skin->joints[i]->parent - data->nodes; | ||
1365 | assert(parent_node_index < data->nodes_count); | ||
1366 | |||
1367 | // Subtract the base index to pack the joints as tightly as possible in | ||
1368 | // the AnimaDesc. | ||
1369 | assert(node_index >= base_joint_index); | ||
1370 | const cgltf_size joint_index = node_index - base_joint_index; | ||
1371 | |||
1372 | assert(parent_node_index >= base_joint_index); | ||
1373 | const cgltf_size parent_index = parent_node_index - base_joint_index; | ||
1374 | |||
1375 | skeleton_desc->joints[i] = joint_index; | ||
1376 | |||
1377 | JointDesc* joint_desc = &anima_desc->joints[joint_index]; | ||
1378 | joint_desc->parent = parent_index; | ||
1379 | joint_desc->inv_bind_matrix = inv_bind_matrix; | ||
1380 | |||
1381 | is_joint_node[joint_index] = true; | ||
1382 | }; | ||
1383 | |||
1384 | // glTF may specify a "skeleton", which is the root of the skin's | ||
1385 | // (skeleton's) node hierarchy. | ||
1386 | // if (skin->skeleton) { | ||
1387 | // // cgltf_size root_index = skin->skeleton - data->nodes; | ||
1388 | // // assert(root_index <= data->nodes_count); | ||
1389 | // // root_node = nodes[root_index]; | ||
1390 | // assert(false); | ||
1391 | //} | ||
1392 | } | ||
1393 | |||
1394 | // Animation library assumes that joints are contiguous. | ||
1395 | for (size_t i = 0; i < num_joints; ++i) { | ||
1396 | assert(is_joint_node[i]); | ||
1397 | } | ||
1398 | |||
1399 | // Insert the root joint. | ||
1400 | // This is the root of all skeletons. It is, specifically, the root of all | ||
1401 | // joints that do not have a parent; skins (skeletons) in glTF are not | ||
1402 | // guaranteed to have a common parent, but are generally a set of disjoint | ||
1403 | // trees. | ||
1404 | const size_t root_index = num_joints; | ||
1405 | assert(root_index < GFX_MAX_NUM_JOINTS); | ||
1406 | anima_desc->joints[root_index] = (JointDesc){.parent = INDEX_NONE}; | ||
1407 | num_joints++; | ||
1408 | |||
1409 | // Make root joints point to the root joint at index N. | ||
1410 | // The root joints are the ones that have a non-joint node in the glTF as a | ||
1411 | // parent. | ||
1412 | for (size_t i = 0; i < root_index; ++i) { | ||
1413 | JointDesc* joint = &anima_desc->joints[i]; | ||
1414 | if ((joint->parent >= root_index) || !is_joint_node[joint->parent]) { | ||
1415 | joint->parent = root_index; | ||
1416 | } | ||
1417 | } | ||
1418 | |||
1419 | return num_joints; | ||
1420 | } | ||
1421 | |||
1422 | /// Load all animations from the glTF scene. | ||
1423 | static void load_animations( | ||
1424 | const cgltf_data* data, cgltf_size base_joint_index, | ||
1425 | AnimaDesc* anima_desc) { | ||
1426 | assert(data); | ||
1427 | assert(anima_desc); | ||
1428 | assert(base_joint_index < data->nodes_count); | ||
1429 | assert(data->animations_count <= GFX_MAX_NUM_ANIMATIONS); | ||
1430 | |||
1431 | for (cgltf_size a = 0; a < data->animations_count; ++a) { | ||
1432 | const cgltf_animation* animation = &data->animations[a]; | ||
1433 | AnimationDesc* animation_desc = &anima_desc->animations[a]; | ||
1434 | |||
1435 | *animation_desc = (AnimationDesc){ | ||
1436 | .name = sstring_make(animation->name), | ||
1437 | .num_channels = animation->channels_count}; | ||
1438 | |||
1439 | assert(animation->channels_count <= GFX_MAX_NUM_CHANNELS); | ||
1440 | for (cgltf_size c = 0; c < animation->channels_count; ++c) { | ||
1441 | const cgltf_animation_channel* channel = &animation->channels[c]; | ||
1442 | ChannelDesc* channel_desc = &animation_desc->channels[c]; | ||
1443 | const cgltf_animation_sampler* sampler = channel->sampler; | ||
1444 | |||
1445 | const size_t target_index = channel->target_node - data->nodes; | ||
1446 | assert(target_index < data->nodes_count); | ||
1447 | |||
1448 | assert(target_index >= base_joint_index); | ||
1449 | const size_t tight_target_index = target_index - base_joint_index; | ||
1450 | assert(tight_target_index < anima_desc->num_joints); | ||
1451 | |||
1452 | *channel_desc = (ChannelDesc){ | ||
1453 | .target = tight_target_index, | ||
1454 | .type = from_gltf_animation_path_type(channel->target_path), | ||
1455 | .interpolation = from_gltf_interpolation_type(sampler->interpolation), | ||
1456 | .num_keyframes = 0}; | ||
1457 | |||
1458 | // Read time inputs. | ||
1459 | AccessorIter iter = make_accessor_iter(sampler->input); | ||
1460 | AccessorData input = {0}; | ||
1461 | for (cgltf_size i = 0; accessor_iter_next(&iter, &input); ++i) { | ||
1462 | channel_desc->keyframes[i].time = input.x; | ||
1463 | channel_desc->num_keyframes++; | ||
1464 | } | ||
1465 | |||
1466 | // Read transform outputs. | ||
1467 | AccessorData output = {0}; | ||
1468 | switch (channel->target_path) { | ||
1469 | case cgltf_animation_path_type_translation: { | ||
1470 | iter = make_accessor_iter(sampler->output); | ||
1471 | for (cgltf_size i = 0; accessor_iter_next(&iter, &output); ++i) { | ||
1472 | channel_desc->keyframes[i].translation = | ||
1473 | vec3_make(output.x, output.y, output.z); | ||
1474 | } | ||
1475 | break; | ||
1476 | } | ||
1477 | case cgltf_animation_path_type_rotation: { | ||
1478 | iter = make_accessor_iter(sampler->output); | ||
1479 | for (cgltf_size i = 0; accessor_iter_next(&iter, &output); ++i) { | ||
1480 | channel_desc->keyframes[i].rotation = | ||
1481 | qmake(output.x, output.y, output.z, output.w); | ||
1482 | } | ||
1483 | break; | ||
1484 | } | ||
1485 | default: | ||
1486 | // TODO: Handle other channel transformations. | ||
1487 | break; | ||
1488 | } | ||
1489 | } | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | /// Load all nodes from the glTF scene. | ||
1494 | /// | ||
1495 | /// This function ignores the many scenes and default scene of the glTF spec | ||
1496 | /// and instead just loads all nodes into a single gfx Scene. | ||
1497 | static void load_nodes( | ||
1498 | const cgltf_data* data, SceneNode* root_node, SceneObject** objects, | ||
1499 | SceneCamera** cameras, const Anima* anima, SceneNode** nodes) { | ||
1500 | // Note that with glTF 2.0, nodes do not form a DAG / scene graph but a | ||
1501 | // disjount union of strict trees: | ||
1502 | // | ||
1503 | // "For Version 2.0 conformance, the glTF node hierarchy is not a directed | ||
1504 | // acyclic graph (DAG) or scene graph, but a disjoint union of strict trees. | ||
1505 | // That is, no node may be a direct descendant of more than one node. This | ||
1506 | // restriction is meant to simplify implementation and facilitate | ||
1507 | // conformance." | ||
1508 | // | ||
1509 | // This matches the gfx library implementation, where every node can have at | ||
1510 | // most one parent. | ||
1511 | assert(data); | ||
1512 | assert(root_node); | ||
1513 | assert(objects); | ||
1514 | assert(cameras); | ||
1515 | assert(nodes); | ||
1516 | |||
1517 | cgltf_size next_camera = 0; | ||
1518 | |||
1519 | for (cgltf_size n = 0; n < data->nodes_count; ++n) { | ||
1520 | const cgltf_node* node = &data->nodes[n]; | ||
1521 | |||
1522 | // Add SceneObject, SceneCamera or Lights. | ||
1523 | // TODO: Handle lights once they are implemented in the gfx library. | ||
1524 | if (node->mesh) { | ||
1525 | const cgltf_size mesh_index = node->mesh - data->meshes; | ||
1526 | assert(mesh_index < data->meshes_count); | ||
1527 | SceneObject* object = objects[mesh_index]; | ||
1528 | gfx_construct_object_node(nodes[n], object); | ||
1529 | |||
1530 | if (node->skin) { | ||
1531 | assert(anima); | ||
1532 | |||
1533 | const cgltf_size skin_index = node->skin - data->skins; | ||
1534 | assert(skin_index < data->skins_count); | ||
1535 | const Skeleton* skeleton = gfx_get_anima_skeleton(anima, skin_index); | ||
1536 | gfx_set_object_skeleton(object, skeleton); | ||
1537 | } | ||
1538 | } else if (node->camera) { | ||
1539 | assert(next_camera < data->cameras_count); | ||
1540 | |||
1541 | Camera camera; | ||
1542 | const cgltf_camera* cam = node->camera; | ||
1543 | |||
1544 | // TODO: We could define a function load_cameras() the same way we load | ||
1545 | // every mesh and then remove this ad-hoc loading of cameras here, as well | ||
1546 | // as remove 'next_camera'. | ||
1547 | switch (cam->type) { | ||
1548 | case cgltf_camera_type_orthographic: | ||
1549 | camera = camera_orthographic( | ||
1550 | 0, cam->data.orthographic.xmag, 0, cam->data.orthographic.ymag, | ||
1551 | cam->data.orthographic.znear, cam->data.orthographic.zfar); | ||
1552 | break; | ||
1553 | case cgltf_camera_type_perspective: | ||
1554 | camera = camera_perspective( | ||
1555 | cam->data.perspective.yfov, cam->data.perspective.aspect_ratio, | ||
1556 | cam->data.perspective.znear, cam->data.perspective.zfar); | ||
1557 | break; | ||
1558 | case cgltf_camera_type_invalid: | ||
1559 | break; | ||
1560 | } | ||
1561 | |||
1562 | gfx_set_camera_camera(cameras[next_camera], &camera); | ||
1563 | gfx_construct_camera_node(nodes[n], cameras[next_camera]); | ||
1564 | ++next_camera; | ||
1565 | } else { | ||
1566 | // TODO: implementation for missing node types. | ||
1567 | // These nodes currently default to logical nodes. | ||
1568 | } | ||
1569 | assert(nodes[n]); | ||
1570 | |||
1571 | // Set transform. | ||
1572 | mat4 transform; | ||
1573 | if (node->has_matrix) { | ||
1574 | transform = mat4_from_array(node->matrix); | ||
1575 | } else { | ||
1576 | transform = mat4_id(); | ||
1577 | if (node->has_scale) { | ||
1578 | const mat4 scale = mat4_scale(vec3_from_array(node->scale)); | ||
1579 | transform = mat4_mul(transform, scale); | ||
1580 | } | ||
1581 | if (node->has_rotation) { | ||
1582 | const quat q = quat_from_array(node->rotation); | ||
1583 | const mat4 rotate = mat4_from_quat(q); | ||
1584 | transform = mat4_mul(transform, rotate); | ||
1585 | } | ||
1586 | if (node->has_translation) { | ||
1587 | const mat4 translate = | ||
1588 | mat4_translate(vec3_from_array(node->translation)); | ||
1589 | transform = mat4_mul(translate, transform); | ||
1590 | } | ||
1591 | } | ||
1592 | gfx_set_node_transform(nodes[n], &transform); | ||
1593 | |||
1594 | // If this is a top-level node in the glTF scene, set its parent to the | ||
1595 | // given root node. | ||
1596 | if (!node->parent) { | ||
1597 | gfx_set_node_parent(nodes[n], root_node); | ||
1598 | } else { | ||
1599 | const cgltf_size parent_index = node->parent - data->nodes; | ||
1600 | assert(parent_index < data->nodes_count); | ||
1601 | SceneNode* parent = nodes[parent_index]; | ||
1602 | assert(parent); | ||
1603 | gfx_set_node_parent(nodes[n], parent); | ||
1604 | } | ||
1605 | } // SceneNode. | ||
1606 | } | ||
1607 | |||
1608 | /// Remove joint nodes from the Gfx Scene. | ||
1609 | /// | ||
1610 | /// Joint nodes are not needed because joints are packed into the Anima. | ||
1611 | static void remove_joint_nodes( | ||
1612 | const cgltf_data* data, SceneNode** scene_nodes) { | ||
1613 | assert(data); | ||
1614 | assert(scene_nodes); | ||
1615 | |||
1616 | // This works assuming the joint nodes are contiguous. Contiguity is checked | ||
1617 | // when loading skins. See load_skins(). | ||
1618 | size_t min_joint_index = (size_t)-1; | ||
1619 | size_t max_joint_index = 0; | ||
1620 | |||
1621 | // First get the minimum and maximum indices of all joint nodes. | ||
1622 | for (cgltf_size s = 0; s < data->skins_count; ++s) { | ||
1623 | const cgltf_skin* skin = &data->skins[s]; | ||
1624 | |||
1625 | for (cgltf_size j = 0; j < skin->joints_count; ++j) { | ||
1626 | // Joint is an index/pointer into the nodes array. | ||
1627 | const cgltf_size joint_index = skin->joints[j] - data->nodes; | ||
1628 | assert(joint_index < data->nodes_count); | ||
1629 | |||
1630 | if (joint_index < min_joint_index) { | ||
1631 | min_joint_index = joint_index; | ||
1632 | } | ||
1633 | if (joint_index > max_joint_index) { | ||
1634 | max_joint_index = joint_index; | ||
1635 | } | ||
1636 | } | ||
1637 | } | ||
1638 | |||
1639 | assert(min_joint_index < data->nodes_count); | ||
1640 | assert(max_joint_index < data->nodes_count); | ||
1641 | |||
1642 | // Now walk over the joint nodes. If a joint's parent is itself not a joint | ||
1643 | // node, then that joint is a root of a joint hierarchy (skins in glTF may | ||
1644 | // have multiple roots). In such case, delete the root joint recursively. | ||
1645 | for (cgltf_size s = 0; s < data->skins_count; ++s) { | ||
1646 | const cgltf_skin* skin = &data->skins[s]; | ||
1647 | |||
1648 | for (cgltf_size j = 0; j < skin->joints_count; ++j) { | ||
1649 | // Joint is an index/pointer into the nodes array. | ||
1650 | const cgltf_size joint_index = skin->joints[j] - data->nodes; | ||
1651 | assert(joint_index < data->nodes_count); | ||
1652 | |||
1653 | const cgltf_node* joint = &data->nodes[joint_index]; | ||
1654 | |||
1655 | // Parent node index. | ||
1656 | const cgltf_size parent_index = joint->parent - data->nodes; | ||
1657 | assert(parent_index < data->nodes_count); | ||
1658 | |||
1659 | // If the parent is not a joint node, recursively delete this joint node. | ||
1660 | if ((parent_index < min_joint_index) || | ||
1661 | (parent_index > max_joint_index)) { | ||
1662 | gfx_destroy_node(&scene_nodes[joint_index]); | ||
1663 | } | ||
1664 | } | ||
1665 | } | ||
1666 | } | ||
1667 | |||
1668 | /// Load all scenes from the glTF file. | ||
1669 | /// | ||
1670 | /// If the scene is loaded from memory, set filepath = null. | ||
1671 | /// | ||
1672 | /// This function ignores the many scenes and default scene of the glTF spec | ||
1673 | /// and instead just loads all scenes into a single Gfx Scene. | ||
1674 | static Model* load_scene( | ||
1675 | cgltf_data* data, Gfx* gfx, const mstring* filepath, ShaderProgram* shader, | ||
1676 | const cgltfTangentBuffer* cgltf_tangent_buffers, | ||
1677 | cgltf_size num_tangent_buffers) { | ||
1678 | // In a GLTF scene, buffers can be shared among meshes, meshes among nodes, | ||
1679 | // etc. Each object is referenced by its index in the relevant array. Here we | ||
1680 | // do a button-up construction, first allocating our own graphics objects in | ||
1681 | // the same quantities and then re-using the GLTF indices to index these | ||
1682 | // arrays. | ||
1683 | // | ||
1684 | // For simplicity, this function also handles all of the cleanup. Arrays are | ||
1685 | // allocated up front, and the helper functions construct their elements. If | ||
1686 | // an error is encountered, the helper functions can simply return and this | ||
1687 | // function cleans up any intermediate objects that had been created up until | ||
1688 | // the point of failure. | ||
1689 | // | ||
1690 | // Loading animation data: | ||
1691 | // - Buffers with animation sampler data need to stay on the CPU, not | ||
1692 | // uploaded to the GPU. We could try to implement GPU animation at a later | ||
1693 | // stage. | ||
1694 | assert(data); | ||
1695 | assert(gfx); | ||
1696 | assert(filepath); | ||
1697 | assert((num_tangent_buffers == 0) || (cgltf_tangent_buffers != 0)); | ||
1698 | |||
1699 | bool success = false; | ||
1700 | |||
1701 | GfxCore* gfxcore = gfx_get_core(gfx); | ||
1702 | const size_t primitive_count = get_total_primitives(data); | ||
1703 | |||
1704 | const mstring directory = mstring_dirname(*filepath); | ||
1705 | LOGD("Filepath: %s", mstring_cstr(filepath)); | ||
1706 | LOGD("Directory: %s", mstring_cstr(&directory)); | ||
1707 | |||
1708 | Buffer** tangent_buffers = 0; | ||
1709 | Buffer** buffers = 0; | ||
1710 | LoadTextureCmd* load_texture_cmds = 0; | ||
1711 | const Texture** textures = 0; // Textures are owned by asset cache. | ||
1712 | Material** materials = 0; | ||
1713 | Geometry** geometries = 0; | ||
1714 | Mesh** meshes = 0; | ||
1715 | AnimaDesc* anima_desc = 0; | ||
1716 | SceneObject** scene_objects = 0; | ||
1717 | SceneCamera** scene_cameras = 0; | ||
1718 | SceneNode** scene_nodes = 0; | ||
1719 | Anima* anima = 0; | ||
1720 | SceneNode* root_node = 0; | ||
1721 | Model* model = 0; | ||
1722 | |||
1723 | tangent_buffers = calloc(num_tangent_buffers, sizeof(Buffer*)); | ||
1724 | buffers = calloc(data->buffers_count, sizeof(Buffer*)); | ||
1725 | textures = calloc(data->textures_count, sizeof(Texture*)); | ||
1726 | materials = calloc(data->materials_count, sizeof(Material*)); | ||
1727 | geometries = calloc(primitive_count, sizeof(Geometry*)); | ||
1728 | meshes = calloc(primitive_count, sizeof(Mesh*)); | ||
1729 | scene_objects = calloc(data->meshes_count, sizeof(SceneObject*)); | ||
1730 | scene_cameras = calloc(data->cameras_count, sizeof(SceneCamera**)); | ||
1731 | scene_nodes = calloc(data->nodes_count, sizeof(SceneNode**)); | ||
1732 | // A glTF scene does not necessarily have textures. Materials can be given | ||
1733 | // as constants, for example. | ||
1734 | if (data->textures_count > 0) { | ||
1735 | load_texture_cmds = calloc(data->textures_count, sizeof(LoadTextureCmd)); | ||
1736 | } | ||
1737 | |||
1738 | if (!buffers || !tangent_buffers || | ||
1739 | ((data->textures_count > 0) && !load_texture_cmds) || !textures || | ||
1740 | !materials || !geometries || !meshes || !scene_objects || | ||
1741 | !scene_cameras || !scene_nodes) { | ||
1742 | goto cleanup; | ||
1743 | } | ||
1744 | |||
1745 | if ((num_tangent_buffers > 0) && | ||
1746 | !load_tangent_buffers( | ||
1747 | cgltf_tangent_buffers, num_tangent_buffers, gfxcore, | ||
1748 | tangent_buffers)) { | ||
1749 | goto cleanup; | ||
1750 | } | ||
1751 | |||
1752 | if (!load_buffers(data, gfxcore, buffers)) { | ||
1753 | goto cleanup; | ||
1754 | } | ||
1755 | |||
1756 | if (data->textures_count > 0) { | ||
1757 | load_textures_lazy( | ||
1758 | data, gfxcore, mstring_cstr(&directory), load_texture_cmds); | ||
1759 | } | ||
1760 | |||
1761 | if (!load_materials(data, gfx, load_texture_cmds, textures, materials)) { | ||
1762 | goto cleanup; | ||
1763 | } | ||
1764 | |||
1765 | if (!load_meshes( | ||
1766 | data, gfxcore, buffers, tangent_buffers, cgltf_tangent_buffers, | ||
1767 | num_tangent_buffers, materials, shader, primitive_count, geometries, | ||
1768 | meshes, scene_objects)) { | ||
1769 | goto cleanup; | ||
1770 | } | ||
1771 | |||
1772 | // Skins refer to nodes, and nodes may refer to skins. To break this circular | ||
1773 | // dependency, glTF defines skins in terms of node indices. We could do the | ||
1774 | // same if Gfx allowed allocating nodes contiguously in memory. For now, | ||
1775 | // create the nodes up front and use the indices of the array to map to the | ||
1776 | // node_idx. | ||
1777 | for (cgltf_size i = 0; i < data->nodes_count; ++i) { | ||
1778 | scene_nodes[i] = gfx_make_node(); | ||
1779 | } | ||
1780 | |||
1781 | // Create the scene's root node. | ||
1782 | // This is an anima node if the scene has skins; otherwise it is a logical | ||
1783 | // node. | ||
1784 | root_node = gfx_make_node(); | ||
1785 | if (data->skins_count > 0) { | ||
1786 | anima_desc = calloc(1, sizeof(AnimaDesc)); | ||
1787 | if (!anima_desc) { | ||
1788 | goto cleanup; | ||
1789 | } | ||
1790 | |||
1791 | const cgltf_size base = find_base_joint_index(data); | ||
1792 | |||
1793 | anima_desc->num_skeletons = data->skins_count; | ||
1794 | anima_desc->num_animations = data->animations_count; | ||
1795 | anima_desc->num_joints = load_skins(data, buffers, base, anima_desc); | ||
1796 | load_animations(data, base, anima_desc); | ||
1797 | |||
1798 | compute_joint_bounding_boxes( | ||
1799 | data, anima_desc->num_joints, anima_desc->joints); | ||
1800 | |||
1801 | anima = gfx_make_anima(anima_desc); | ||
1802 | gfx_construct_anima_node(root_node, anima); | ||
1803 | } | ||
1804 | |||
1805 | // The root node becomes the root of all scene nodes. | ||
1806 | load_nodes(data, root_node, scene_objects, scene_cameras, anima, scene_nodes); | ||
1807 | |||
1808 | // Clean up scene nodes that correspond to joints in the glTF. These are | ||
1809 | // not needed anymore. | ||
1810 | if (data->skins_count > 0) { | ||
1811 | remove_joint_nodes(data, scene_nodes); | ||
1812 | } | ||
1813 | |||
1814 | model = gfx_make_model(root_node); | ||
1815 | |||
1816 | success = true; | ||
1817 | |||
1818 | cleanup: | ||
1819 | // The arrays of resources are no longer needed. The resources themselves are | ||
1820 | // destroyed only if this function fails. | ||
1821 | if (tangent_buffers) { | ||
1822 | if (!success) { | ||
1823 | for (cgltf_size i = 0; i < num_tangent_buffers; ++i) { | ||
1824 | if (tangent_buffers[i]) { | ||
1825 | gfx_destroy_buffer(gfxcore, &tangent_buffers[i]); | ||
1826 | } | ||
1827 | } | ||
1828 | } | ||
1829 | free(tangent_buffers); | ||
1830 | } | ||
1831 | if (buffers) { | ||
1832 | if (!success) { | ||
1833 | for (cgltf_size i = 0; i < data->buffers_count; ++i) { | ||
1834 | if (buffers[i]) { | ||
1835 | gfx_destroy_buffer(gfxcore, &buffers[i]); | ||
1836 | } | ||
1837 | } | ||
1838 | } | ||
1839 | free(buffers); | ||
1840 | } | ||
1841 | if (load_texture_cmds) { | ||
1842 | free(load_texture_cmds); | ||
1843 | } | ||
1844 | if (textures) { | ||
1845 | free(textures); | ||
1846 | } | ||
1847 | if (materials) { | ||
1848 | if (!success) { | ||
1849 | for (cgltf_size i = 0; i < data->materials_count; ++i) { | ||
1850 | if (materials[i]) { | ||
1851 | gfx_destroy_material(&materials[i]); | ||
1852 | } | ||
1853 | } | ||
1854 | } | ||
1855 | free(materials); | ||
1856 | } | ||
1857 | if (geometries) { | ||
1858 | if (!success) { | ||
1859 | for (size_t i = 0; i < primitive_count; ++i) { | ||
1860 | if (geometries[i]) { | ||
1861 | gfx_destroy_geometry(gfxcore, &geometries[i]); | ||
1862 | } | ||
1863 | } | ||
1864 | } | ||
1865 | free(geometries); | ||
1866 | } | ||
1867 | if (meshes) { | ||
1868 | if (!success) { | ||
1869 | for (size_t i = 0; i < primitive_count; ++i) { | ||
1870 | if (meshes[i]) { | ||
1871 | gfx_destroy_mesh(&meshes[i]); | ||
1872 | } | ||
1873 | } | ||
1874 | } | ||
1875 | free(meshes); | ||
1876 | } | ||
1877 | if (anima_desc) { | ||
1878 | free(anima_desc); | ||
1879 | } | ||
1880 | if (scene_objects) { | ||
1881 | if (!success) { | ||
1882 | for (cgltf_size i = 0; i < data->meshes_count; ++i) { | ||
1883 | if (scene_objects[i]) { | ||
1884 | gfx_destroy_object(&scene_objects[i]); | ||
1885 | } | ||
1886 | } | ||
1887 | } | ||
1888 | free(scene_objects); | ||
1889 | } | ||
1890 | if (scene_cameras) { | ||
1891 | if (!success) { | ||
1892 | for (cgltf_size i = 0; i < data->cameras_count; ++i) { | ||
1893 | if (scene_cameras[i]) { | ||
1894 | gfx_destroy_camera(&scene_cameras[i]); | ||
1895 | } | ||
1896 | } | ||
1897 | } | ||
1898 | free(scene_cameras); | ||
1899 | } | ||
1900 | if (scene_nodes) { | ||
1901 | if (!success) { | ||
1902 | for (cgltf_size i = 0; i < data->nodes_count; ++i) { | ||
1903 | if (scene_nodes[i]) { | ||
1904 | gfx_destroy_node(&scene_nodes[i]); | ||
1905 | } | ||
1906 | } | ||
1907 | } | ||
1908 | free(scene_nodes); | ||
1909 | } | ||
1910 | if (!success) { | ||
1911 | if (root_node) { | ||
1912 | gfx_destroy_node(&root_node); // Node owns the anima. | ||
1913 | } else if (anima) { | ||
1914 | gfx_destroy_anima(&anima); | ||
1915 | } | ||
1916 | } | ||
1917 | return model; | ||
1918 | } | ||
1919 | |||
1920 | Model* gfx_model_load(Gfx* gfx, const LoadModelCmd* cmd) { | ||
1921 | assert(gfx); | ||
1922 | assert(cmd); | ||
1923 | |||
1924 | Model* model = 0; | ||
1925 | |||
1926 | cgltf_options options = {0}; | ||
1927 | cgltf_data* data = NULL; | ||
1928 | cgltfTangentBuffer* tangent_buffers = 0; | ||
1929 | |||
1930 | cgltf_result result; | ||
1931 | switch (cmd->origin) { | ||
1932 | case AssetFromFile: | ||
1933 | result = cgltf_parse_file(&options, mstring_cstr(&cmd->filepath), &data); | ||
1934 | break; | ||
1935 | case AssetFromMemory: | ||
1936 | result = cgltf_parse(&options, cmd->data, cmd->size_bytes, &data); | ||
1937 | break; | ||
1938 | } | ||
1939 | if (result != cgltf_result_success) { | ||
1940 | goto cleanup; | ||
1941 | } | ||
1942 | |||
1943 | if (cmd->origin == AssetFromFile) { | ||
1944 | // Must call cgltf_load_buffers() to load buffer data. | ||
1945 | result = cgltf_load_buffers(&options, data, mstring_cstr(&cmd->filepath)); | ||
1946 | if (result != cgltf_result_success) { | ||
1947 | goto cleanup; | ||
1948 | } | ||
1949 | } | ||
1950 | |||
1951 | // Compute tangents for normal-mapped models that are missing them. | ||
1952 | cgltf_size num_tangent_buffers = 0; | ||
1953 | cgltf_compute_tangents( | ||
1954 | &options, data, &tangent_buffers, &num_tangent_buffers); | ||
1955 | |||
1956 | model = load_scene( | ||
1957 | data, gfx, &cmd->filepath, cmd->shader, tangent_buffers, | ||
1958 | num_tangent_buffers); | ||
1959 | |||
1960 | cleanup: | ||
1961 | if (data) { | ||
1962 | cgltf_free(data); | ||
1963 | } | ||
1964 | if (tangent_buffers) { | ||
1965 | free(tangent_buffers); | ||
1966 | } | ||
1967 | return model; | ||
1968 | } | ||