GCC Code Coverage Report


Directory: ./
File: submodules/raylib/src/external/cgltf.h
Date: 2023-09-29 04:53:15
Exec Total Coverage
Lines: 0 2591 0.0%
Branches: 0 2428 0.0%

Line Branch Exec Source
1 /**
2 * cgltf - a single-file glTF 2.0 parser written in C99.
3 *
4 * Version: 1.13
5 *
6 * Website: https://github.com/jkuhlmann/cgltf
7 *
8 * Distributed under the MIT License, see notice at the end of this file.
9 *
10 * Building:
11 * Include this file where you need the struct and function
12 * declarations. Have exactly one source file where you define
13 * `CGLTF_IMPLEMENTATION` before including this file to get the
14 * function definitions.
15 *
16 * Reference:
17 * `cgltf_result cgltf_parse(const cgltf_options*, const void*,
18 * cgltf_size, cgltf_data**)` parses both glTF and GLB data. If
19 * this function returns `cgltf_result_success`, you have to call
20 * `cgltf_free()` on the created `cgltf_data*` variable.
21 * Note that contents of external files for buffers and images are not
22 * automatically loaded. You'll need to read these files yourself using
23 * URIs in the `cgltf_data` structure.
24 *
25 * `cgltf_options` is the struct passed to `cgltf_parse()` to control
26 * parts of the parsing process. You can use it to force the file type
27 * and provide memory allocation as well as file operation callbacks.
28 * Should be zero-initialized to trigger default behavior.
29 *
30 * `cgltf_data` is the struct allocated and filled by `cgltf_parse()`.
31 * It generally mirrors the glTF format as described by the spec (see
32 * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0).
33 *
34 * `void cgltf_free(cgltf_data*)` frees the allocated `cgltf_data`
35 * variable.
36 *
37 * `cgltf_result cgltf_load_buffers(const cgltf_options*, cgltf_data*,
38 * const char* gltf_path)` can be optionally called to open and read buffer
39 * files using the `FILE*` APIs. The `gltf_path` argument is the path to
40 * the original glTF file, which allows the parser to resolve the path to
41 * buffer files.
42 *
43 * `cgltf_result cgltf_load_buffer_base64(const cgltf_options* options,
44 * cgltf_size size, const char* base64, void** out_data)` decodes
45 * base64-encoded data content. Used internally by `cgltf_load_buffers()`.
46 * This is useful when decoding data URIs in images.
47 *
48 * `cgltf_result cgltf_parse_file(const cgltf_options* options, const
49 * char* path, cgltf_data** out_data)` can be used to open the given
50 * file using `FILE*` APIs and parse the data using `cgltf_parse()`.
51 *
52 * `cgltf_result cgltf_validate(cgltf_data*)` can be used to do additional
53 * checks to make sure the parsed glTF data is valid.
54 *
55 * `cgltf_node_transform_local` converts the translation / rotation / scale properties of a node
56 * into a mat4.
57 *
58 * `cgltf_node_transform_world` calls `cgltf_node_transform_local` on every ancestor in order
59 * to compute the root-to-node transformation.
60 *
61 * `cgltf_accessor_unpack_floats` reads in the data from an accessor, applies sparse data (if any),
62 * and converts them to floating point. Assumes that `cgltf_load_buffers` has already been called.
63 * By passing null for the output pointer, users can find out how many floats are required in the
64 * output buffer.
65 *
66 * `cgltf_num_components` is a tiny utility that tells you the dimensionality of
67 * a certain accessor type. This can be used before `cgltf_accessor_unpack_floats` to help allocate
68 * the necessary amount of memory. `cgltf_component_size` and `cgltf_calc_size` exist for
69 * similar purposes.
70 *
71 * `cgltf_accessor_read_float` reads a certain element from a non-sparse accessor and converts it to
72 * floating point, assuming that `cgltf_load_buffers` has already been called. The passed-in element
73 * size is the number of floats in the output buffer, which should be in the range [1, 16]. Returns
74 * false if the passed-in element_size is too small, or if the accessor is sparse.
75 *
76 * `cgltf_accessor_read_uint` is similar to its floating-point counterpart, but limited to reading
77 * vector types and does not support matrix types. The passed-in element size is the number of uints
78 * in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in
79 * element_size is too small, or if the accessor is sparse.
80 *
81 * `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t
82 * and only works with single-component data types.
83 *
84 * `cgltf_copy_extras_json` allows users to retrieve the "extras" data that can be attached to many
85 * glTF objects (which can be arbitrary JSON data). This is a legacy function, consider using
86 * cgltf_extras::data directly instead. You can parse this data using your own JSON parser
87 * or, if you've included the cgltf implementation using the integrated JSMN JSON parser.
88 */
89 #ifndef CGLTF_H_INCLUDED__
90 #define CGLTF_H_INCLUDED__
91
92 #include <stddef.h>
93 #include <stdint.h> /* For uint8_t, uint32_t */
94
95 #ifdef __cplusplus
96 extern "C" {
97 #endif
98
99 typedef size_t cgltf_size;
100 typedef long long int cgltf_ssize;
101 typedef float cgltf_float;
102 typedef int cgltf_int;
103 typedef unsigned int cgltf_uint;
104 typedef int cgltf_bool;
105
106 typedef enum cgltf_file_type
107 {
108 cgltf_file_type_invalid,
109 cgltf_file_type_gltf,
110 cgltf_file_type_glb,
111 cgltf_file_type_max_enum
112 } cgltf_file_type;
113
114 typedef enum cgltf_result
115 {
116 cgltf_result_success,
117 cgltf_result_data_too_short,
118 cgltf_result_unknown_format,
119 cgltf_result_invalid_json,
120 cgltf_result_invalid_gltf,
121 cgltf_result_invalid_options,
122 cgltf_result_file_not_found,
123 cgltf_result_io_error,
124 cgltf_result_out_of_memory,
125 cgltf_result_legacy_gltf,
126 cgltf_result_max_enum
127 } cgltf_result;
128
129 typedef struct cgltf_memory_options
130 {
131 void* (*alloc_func)(void* user, cgltf_size size);
132 void (*free_func) (void* user, void* ptr);
133 void* user_data;
134 } cgltf_memory_options;
135
136 typedef struct cgltf_file_options
137 {
138 cgltf_result(*read)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, const char* path, cgltf_size* size, void** data);
139 void (*release)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data);
140 void* user_data;
141 } cgltf_file_options;
142
143 typedef struct cgltf_options
144 {
145 cgltf_file_type type; /* invalid == auto detect */
146 cgltf_size json_token_count; /* 0 == auto */
147 cgltf_memory_options memory;
148 cgltf_file_options file;
149 } cgltf_options;
150
151 typedef enum cgltf_buffer_view_type
152 {
153 cgltf_buffer_view_type_invalid,
154 cgltf_buffer_view_type_indices,
155 cgltf_buffer_view_type_vertices,
156 cgltf_buffer_view_type_max_enum
157 } cgltf_buffer_view_type;
158
159 typedef enum cgltf_attribute_type
160 {
161 cgltf_attribute_type_invalid,
162 cgltf_attribute_type_position,
163 cgltf_attribute_type_normal,
164 cgltf_attribute_type_tangent,
165 cgltf_attribute_type_texcoord,
166 cgltf_attribute_type_color,
167 cgltf_attribute_type_joints,
168 cgltf_attribute_type_weights,
169 cgltf_attribute_type_custom,
170 cgltf_attribute_type_max_enum
171 } cgltf_attribute_type;
172
173 typedef enum cgltf_component_type
174 {
175 cgltf_component_type_invalid,
176 cgltf_component_type_r_8, /* BYTE */
177 cgltf_component_type_r_8u, /* UNSIGNED_BYTE */
178 cgltf_component_type_r_16, /* SHORT */
179 cgltf_component_type_r_16u, /* UNSIGNED_SHORT */
180 cgltf_component_type_r_32u, /* UNSIGNED_INT */
181 cgltf_component_type_r_32f, /* FLOAT */
182 cgltf_component_type_max_enum
183 } cgltf_component_type;
184
185 typedef enum cgltf_type
186 {
187 cgltf_type_invalid,
188 cgltf_type_scalar,
189 cgltf_type_vec2,
190 cgltf_type_vec3,
191 cgltf_type_vec4,
192 cgltf_type_mat2,
193 cgltf_type_mat3,
194 cgltf_type_mat4,
195 cgltf_type_max_enum
196 } cgltf_type;
197
198 typedef enum cgltf_primitive_type
199 {
200 cgltf_primitive_type_points,
201 cgltf_primitive_type_lines,
202 cgltf_primitive_type_line_loop,
203 cgltf_primitive_type_line_strip,
204 cgltf_primitive_type_triangles,
205 cgltf_primitive_type_triangle_strip,
206 cgltf_primitive_type_triangle_fan,
207 cgltf_primitive_type_max_enum
208 } cgltf_primitive_type;
209
210 typedef enum cgltf_alpha_mode
211 {
212 cgltf_alpha_mode_opaque,
213 cgltf_alpha_mode_mask,
214 cgltf_alpha_mode_blend,
215 cgltf_alpha_mode_max_enum
216 } cgltf_alpha_mode;
217
218 typedef enum cgltf_animation_path_type {
219 cgltf_animation_path_type_invalid,
220 cgltf_animation_path_type_translation,
221 cgltf_animation_path_type_rotation,
222 cgltf_animation_path_type_scale,
223 cgltf_animation_path_type_weights,
224 cgltf_animation_path_type_max_enum
225 } cgltf_animation_path_type;
226
227 typedef enum cgltf_interpolation_type {
228 cgltf_interpolation_type_linear,
229 cgltf_interpolation_type_step,
230 cgltf_interpolation_type_cubic_spline,
231 cgltf_interpolation_type_max_enum
232 } cgltf_interpolation_type;
233
234 typedef enum cgltf_camera_type {
235 cgltf_camera_type_invalid,
236 cgltf_camera_type_perspective,
237 cgltf_camera_type_orthographic,
238 cgltf_camera_type_max_enum
239 } cgltf_camera_type;
240
241 typedef enum cgltf_light_type {
242 cgltf_light_type_invalid,
243 cgltf_light_type_directional,
244 cgltf_light_type_point,
245 cgltf_light_type_spot,
246 cgltf_light_type_max_enum
247 } cgltf_light_type;
248
249 typedef enum cgltf_data_free_method {
250 cgltf_data_free_method_none,
251 cgltf_data_free_method_file_release,
252 cgltf_data_free_method_memory_free,
253 cgltf_data_free_method_max_enum
254 } cgltf_data_free_method;
255
256 typedef struct cgltf_extras {
257 cgltf_size start_offset; /* this field is deprecated and will be removed in the future; use data instead */
258 cgltf_size end_offset; /* this field is deprecated and will be removed in the future; use data instead */
259
260 char* data;
261 } cgltf_extras;
262
263 typedef struct cgltf_extension {
264 char* name;
265 char* data;
266 } cgltf_extension;
267
268 typedef struct cgltf_buffer
269 {
270 char* name;
271 cgltf_size size;
272 char* uri;
273 void* data; /* loaded by cgltf_load_buffers */
274 cgltf_data_free_method data_free_method;
275 cgltf_extras extras;
276 cgltf_size extensions_count;
277 cgltf_extension* extensions;
278 } cgltf_buffer;
279
280 typedef enum cgltf_meshopt_compression_mode {
281 cgltf_meshopt_compression_mode_invalid,
282 cgltf_meshopt_compression_mode_attributes,
283 cgltf_meshopt_compression_mode_triangles,
284 cgltf_meshopt_compression_mode_indices,
285 cgltf_meshopt_compression_mode_max_enum
286 } cgltf_meshopt_compression_mode;
287
288 typedef enum cgltf_meshopt_compression_filter {
289 cgltf_meshopt_compression_filter_none,
290 cgltf_meshopt_compression_filter_octahedral,
291 cgltf_meshopt_compression_filter_quaternion,
292 cgltf_meshopt_compression_filter_exponential,
293 cgltf_meshopt_compression_filter_max_enum
294 } cgltf_meshopt_compression_filter;
295
296 typedef struct cgltf_meshopt_compression
297 {
298 cgltf_buffer* buffer;
299 cgltf_size offset;
300 cgltf_size size;
301 cgltf_size stride;
302 cgltf_size count;
303 cgltf_meshopt_compression_mode mode;
304 cgltf_meshopt_compression_filter filter;
305 } cgltf_meshopt_compression;
306
307 typedef struct cgltf_buffer_view
308 {
309 char *name;
310 cgltf_buffer* buffer;
311 cgltf_size offset;
312 cgltf_size size;
313 cgltf_size stride; /* 0 == automatically determined by accessor */
314 cgltf_buffer_view_type type;
315 void* data; /* overrides buffer->data if present, filled by extensions */
316 cgltf_bool has_meshopt_compression;
317 cgltf_meshopt_compression meshopt_compression;
318 cgltf_extras extras;
319 cgltf_size extensions_count;
320 cgltf_extension* extensions;
321 } cgltf_buffer_view;
322
323 typedef struct cgltf_accessor_sparse
324 {
325 cgltf_size count;
326 cgltf_buffer_view* indices_buffer_view;
327 cgltf_size indices_byte_offset;
328 cgltf_component_type indices_component_type;
329 cgltf_buffer_view* values_buffer_view;
330 cgltf_size values_byte_offset;
331 cgltf_extras extras;
332 cgltf_extras indices_extras;
333 cgltf_extras values_extras;
334 cgltf_size extensions_count;
335 cgltf_extension* extensions;
336 cgltf_size indices_extensions_count;
337 cgltf_extension* indices_extensions;
338 cgltf_size values_extensions_count;
339 cgltf_extension* values_extensions;
340 } cgltf_accessor_sparse;
341
342 typedef struct cgltf_accessor
343 {
344 char* name;
345 cgltf_component_type component_type;
346 cgltf_bool normalized;
347 cgltf_type type;
348 cgltf_size offset;
349 cgltf_size count;
350 cgltf_size stride;
351 cgltf_buffer_view* buffer_view;
352 cgltf_bool has_min;
353 cgltf_float min[16];
354 cgltf_bool has_max;
355 cgltf_float max[16];
356 cgltf_bool is_sparse;
357 cgltf_accessor_sparse sparse;
358 cgltf_extras extras;
359 cgltf_size extensions_count;
360 cgltf_extension* extensions;
361 } cgltf_accessor;
362
363 typedef struct cgltf_attribute
364 {
365 char* name;
366 cgltf_attribute_type type;
367 cgltf_int index;
368 cgltf_accessor* data;
369 } cgltf_attribute;
370
371 typedef struct cgltf_image
372 {
373 char* name;
374 char* uri;
375 cgltf_buffer_view* buffer_view;
376 char* mime_type;
377 cgltf_extras extras;
378 cgltf_size extensions_count;
379 cgltf_extension* extensions;
380 } cgltf_image;
381
382 typedef struct cgltf_sampler
383 {
384 char* name;
385 cgltf_int mag_filter;
386 cgltf_int min_filter;
387 cgltf_int wrap_s;
388 cgltf_int wrap_t;
389 cgltf_extras extras;
390 cgltf_size extensions_count;
391 cgltf_extension* extensions;
392 } cgltf_sampler;
393
394 typedef struct cgltf_texture
395 {
396 char* name;
397 cgltf_image* image;
398 cgltf_sampler* sampler;
399 cgltf_bool has_basisu;
400 cgltf_image* basisu_image;
401 cgltf_extras extras;
402 cgltf_size extensions_count;
403 cgltf_extension* extensions;
404 } cgltf_texture;
405
406 typedef struct cgltf_texture_transform
407 {
408 cgltf_float offset[2];
409 cgltf_float rotation;
410 cgltf_float scale[2];
411 cgltf_bool has_texcoord;
412 cgltf_int texcoord;
413 } cgltf_texture_transform;
414
415 typedef struct cgltf_texture_view
416 {
417 cgltf_texture* texture;
418 cgltf_int texcoord;
419 cgltf_float scale; /* equivalent to strength for occlusion_texture */
420 cgltf_bool has_transform;
421 cgltf_texture_transform transform;
422 cgltf_extras extras;
423 cgltf_size extensions_count;
424 cgltf_extension* extensions;
425 } cgltf_texture_view;
426
427 typedef struct cgltf_pbr_metallic_roughness
428 {
429 cgltf_texture_view base_color_texture;
430 cgltf_texture_view metallic_roughness_texture;
431
432 cgltf_float base_color_factor[4];
433 cgltf_float metallic_factor;
434 cgltf_float roughness_factor;
435 } cgltf_pbr_metallic_roughness;
436
437 typedef struct cgltf_pbr_specular_glossiness
438 {
439 cgltf_texture_view diffuse_texture;
440 cgltf_texture_view specular_glossiness_texture;
441
442 cgltf_float diffuse_factor[4];
443 cgltf_float specular_factor[3];
444 cgltf_float glossiness_factor;
445 } cgltf_pbr_specular_glossiness;
446
447 typedef struct cgltf_clearcoat
448 {
449 cgltf_texture_view clearcoat_texture;
450 cgltf_texture_view clearcoat_roughness_texture;
451 cgltf_texture_view clearcoat_normal_texture;
452
453 cgltf_float clearcoat_factor;
454 cgltf_float clearcoat_roughness_factor;
455 } cgltf_clearcoat;
456
457 typedef struct cgltf_transmission
458 {
459 cgltf_texture_view transmission_texture;
460 cgltf_float transmission_factor;
461 } cgltf_transmission;
462
463 typedef struct cgltf_ior
464 {
465 cgltf_float ior;
466 } cgltf_ior;
467
468 typedef struct cgltf_specular
469 {
470 cgltf_texture_view specular_texture;
471 cgltf_texture_view specular_color_texture;
472 cgltf_float specular_color_factor[3];
473 cgltf_float specular_factor;
474 } cgltf_specular;
475
476 typedef struct cgltf_volume
477 {
478 cgltf_texture_view thickness_texture;
479 cgltf_float thickness_factor;
480 cgltf_float attenuation_color[3];
481 cgltf_float attenuation_distance;
482 } cgltf_volume;
483
484 typedef struct cgltf_sheen
485 {
486 cgltf_texture_view sheen_color_texture;
487 cgltf_float sheen_color_factor[3];
488 cgltf_texture_view sheen_roughness_texture;
489 cgltf_float sheen_roughness_factor;
490 } cgltf_sheen;
491
492 typedef struct cgltf_emissive_strength
493 {
494 cgltf_float emissive_strength;
495 } cgltf_emissive_strength;
496
497 typedef struct cgltf_iridescence
498 {
499 cgltf_float iridescence_factor;
500 cgltf_texture_view iridescence_texture;
501 cgltf_float iridescence_ior;
502 cgltf_float iridescence_thickness_min;
503 cgltf_float iridescence_thickness_max;
504 cgltf_texture_view iridescence_thickness_texture;
505 } cgltf_iridescence;
506
507 typedef struct cgltf_material
508 {
509 char* name;
510 cgltf_bool has_pbr_metallic_roughness;
511 cgltf_bool has_pbr_specular_glossiness;
512 cgltf_bool has_clearcoat;
513 cgltf_bool has_transmission;
514 cgltf_bool has_volume;
515 cgltf_bool has_ior;
516 cgltf_bool has_specular;
517 cgltf_bool has_sheen;
518 cgltf_bool has_emissive_strength;
519 cgltf_bool has_iridescence;
520 cgltf_pbr_metallic_roughness pbr_metallic_roughness;
521 cgltf_pbr_specular_glossiness pbr_specular_glossiness;
522 cgltf_clearcoat clearcoat;
523 cgltf_ior ior;
524 cgltf_specular specular;
525 cgltf_sheen sheen;
526 cgltf_transmission transmission;
527 cgltf_volume volume;
528 cgltf_emissive_strength emissive_strength;
529 cgltf_iridescence iridescence;
530 cgltf_texture_view normal_texture;
531 cgltf_texture_view occlusion_texture;
532 cgltf_texture_view emissive_texture;
533 cgltf_float emissive_factor[3];
534 cgltf_alpha_mode alpha_mode;
535 cgltf_float alpha_cutoff;
536 cgltf_bool double_sided;
537 cgltf_bool unlit;
538 cgltf_extras extras;
539 cgltf_size extensions_count;
540 cgltf_extension* extensions;
541 } cgltf_material;
542
543 typedef struct cgltf_material_mapping
544 {
545 cgltf_size variant;
546 cgltf_material* material;
547 cgltf_extras extras;
548 } cgltf_material_mapping;
549
550 typedef struct cgltf_morph_target {
551 cgltf_attribute* attributes;
552 cgltf_size attributes_count;
553 } cgltf_morph_target;
554
555 typedef struct cgltf_draco_mesh_compression {
556 cgltf_buffer_view* buffer_view;
557 cgltf_attribute* attributes;
558 cgltf_size attributes_count;
559 } cgltf_draco_mesh_compression;
560
561 typedef struct cgltf_mesh_gpu_instancing {
562 cgltf_buffer_view* buffer_view;
563 cgltf_attribute* attributes;
564 cgltf_size attributes_count;
565 } cgltf_mesh_gpu_instancing;
566
567 typedef struct cgltf_primitive {
568 cgltf_primitive_type type;
569 cgltf_accessor* indices;
570 cgltf_material* material;
571 cgltf_attribute* attributes;
572 cgltf_size attributes_count;
573 cgltf_morph_target* targets;
574 cgltf_size targets_count;
575 cgltf_extras extras;
576 cgltf_bool has_draco_mesh_compression;
577 cgltf_draco_mesh_compression draco_mesh_compression;
578 cgltf_material_mapping* mappings;
579 cgltf_size mappings_count;
580 cgltf_size extensions_count;
581 cgltf_extension* extensions;
582 } cgltf_primitive;
583
584 typedef struct cgltf_mesh {
585 char* name;
586 cgltf_primitive* primitives;
587 cgltf_size primitives_count;
588 cgltf_float* weights;
589 cgltf_size weights_count;
590 char** target_names;
591 cgltf_size target_names_count;
592 cgltf_extras extras;
593 cgltf_size extensions_count;
594 cgltf_extension* extensions;
595 } cgltf_mesh;
596
597 typedef struct cgltf_node cgltf_node;
598
599 typedef struct cgltf_skin {
600 char* name;
601 cgltf_node** joints;
602 cgltf_size joints_count;
603 cgltf_node* skeleton;
604 cgltf_accessor* inverse_bind_matrices;
605 cgltf_extras extras;
606 cgltf_size extensions_count;
607 cgltf_extension* extensions;
608 } cgltf_skin;
609
610 typedef struct cgltf_camera_perspective {
611 cgltf_bool has_aspect_ratio;
612 cgltf_float aspect_ratio;
613 cgltf_float yfov;
614 cgltf_bool has_zfar;
615 cgltf_float zfar;
616 cgltf_float znear;
617 cgltf_extras extras;
618 } cgltf_camera_perspective;
619
620 typedef struct cgltf_camera_orthographic {
621 cgltf_float xmag;
622 cgltf_float ymag;
623 cgltf_float zfar;
624 cgltf_float znear;
625 cgltf_extras extras;
626 } cgltf_camera_orthographic;
627
628 typedef struct cgltf_camera {
629 char* name;
630 cgltf_camera_type type;
631 union {
632 cgltf_camera_perspective perspective;
633 cgltf_camera_orthographic orthographic;
634 } data;
635 cgltf_extras extras;
636 cgltf_size extensions_count;
637 cgltf_extension* extensions;
638 } cgltf_camera;
639
640 typedef struct cgltf_light {
641 char* name;
642 cgltf_float color[3];
643 cgltf_float intensity;
644 cgltf_light_type type;
645 cgltf_float range;
646 cgltf_float spot_inner_cone_angle;
647 cgltf_float spot_outer_cone_angle;
648 cgltf_extras extras;
649 } cgltf_light;
650
651 struct cgltf_node {
652 char* name;
653 cgltf_node* parent;
654 cgltf_node** children;
655 cgltf_size children_count;
656 cgltf_skin* skin;
657 cgltf_mesh* mesh;
658 cgltf_camera* camera;
659 cgltf_light* light;
660 cgltf_float* weights;
661 cgltf_size weights_count;
662 cgltf_bool has_translation;
663 cgltf_bool has_rotation;
664 cgltf_bool has_scale;
665 cgltf_bool has_matrix;
666 cgltf_float translation[3];
667 cgltf_float rotation[4];
668 cgltf_float scale[3];
669 cgltf_float matrix[16];
670 cgltf_extras extras;
671 cgltf_bool has_mesh_gpu_instancing;
672 cgltf_mesh_gpu_instancing mesh_gpu_instancing;
673 cgltf_size extensions_count;
674 cgltf_extension* extensions;
675 };
676
677 typedef struct cgltf_scene {
678 char* name;
679 cgltf_node** nodes;
680 cgltf_size nodes_count;
681 cgltf_extras extras;
682 cgltf_size extensions_count;
683 cgltf_extension* extensions;
684 } cgltf_scene;
685
686 typedef struct cgltf_animation_sampler {
687 cgltf_accessor* input;
688 cgltf_accessor* output;
689 cgltf_interpolation_type interpolation;
690 cgltf_extras extras;
691 cgltf_size extensions_count;
692 cgltf_extension* extensions;
693 } cgltf_animation_sampler;
694
695 typedef struct cgltf_animation_channel {
696 cgltf_animation_sampler* sampler;
697 cgltf_node* target_node;
698 cgltf_animation_path_type target_path;
699 cgltf_extras extras;
700 cgltf_size extensions_count;
701 cgltf_extension* extensions;
702 } cgltf_animation_channel;
703
704 typedef struct cgltf_animation {
705 char* name;
706 cgltf_animation_sampler* samplers;
707 cgltf_size samplers_count;
708 cgltf_animation_channel* channels;
709 cgltf_size channels_count;
710 cgltf_extras extras;
711 cgltf_size extensions_count;
712 cgltf_extension* extensions;
713 } cgltf_animation;
714
715 typedef struct cgltf_material_variant
716 {
717 char* name;
718 cgltf_extras extras;
719 } cgltf_material_variant;
720
721 typedef struct cgltf_asset {
722 char* copyright;
723 char* generator;
724 char* version;
725 char* min_version;
726 cgltf_extras extras;
727 cgltf_size extensions_count;
728 cgltf_extension* extensions;
729 } cgltf_asset;
730
731 typedef struct cgltf_data
732 {
733 cgltf_file_type file_type;
734 void* file_data;
735
736 cgltf_asset asset;
737
738 cgltf_mesh* meshes;
739 cgltf_size meshes_count;
740
741 cgltf_material* materials;
742 cgltf_size materials_count;
743
744 cgltf_accessor* accessors;
745 cgltf_size accessors_count;
746
747 cgltf_buffer_view* buffer_views;
748 cgltf_size buffer_views_count;
749
750 cgltf_buffer* buffers;
751 cgltf_size buffers_count;
752
753 cgltf_image* images;
754 cgltf_size images_count;
755
756 cgltf_texture* textures;
757 cgltf_size textures_count;
758
759 cgltf_sampler* samplers;
760 cgltf_size samplers_count;
761
762 cgltf_skin* skins;
763 cgltf_size skins_count;
764
765 cgltf_camera* cameras;
766 cgltf_size cameras_count;
767
768 cgltf_light* lights;
769 cgltf_size lights_count;
770
771 cgltf_node* nodes;
772 cgltf_size nodes_count;
773
774 cgltf_scene* scenes;
775 cgltf_size scenes_count;
776
777 cgltf_scene* scene;
778
779 cgltf_animation* animations;
780 cgltf_size animations_count;
781
782 cgltf_material_variant* variants;
783 cgltf_size variants_count;
784
785 cgltf_extras extras;
786
787 cgltf_size data_extensions_count;
788 cgltf_extension* data_extensions;
789
790 char** extensions_used;
791 cgltf_size extensions_used_count;
792
793 char** extensions_required;
794 cgltf_size extensions_required_count;
795
796 const char* json;
797 cgltf_size json_size;
798
799 const void* bin;
800 cgltf_size bin_size;
801
802 cgltf_memory_options memory;
803 cgltf_file_options file;
804 } cgltf_data;
805
806 cgltf_result cgltf_parse(
807 const cgltf_options* options,
808 const void* data,
809 cgltf_size size,
810 cgltf_data** out_data);
811
812 cgltf_result cgltf_parse_file(
813 const cgltf_options* options,
814 const char* path,
815 cgltf_data** out_data);
816
817 cgltf_result cgltf_load_buffers(
818 const cgltf_options* options,
819 cgltf_data* data,
820 const char* gltf_path);
821
822 cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data);
823
824 cgltf_size cgltf_decode_string(char* string);
825 cgltf_size cgltf_decode_uri(char* uri);
826
827 cgltf_result cgltf_validate(cgltf_data* data);
828
829 void cgltf_free(cgltf_data* data);
830
831 void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix);
832 void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix);
833
834 const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view);
835
836 cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size);
837 cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size);
838 cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index);
839
840 cgltf_size cgltf_num_components(cgltf_type type);
841 cgltf_size cgltf_component_size(cgltf_component_type component_type);
842 cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type);
843
844 cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count);
845
846 /* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */
847 cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size);
848
849 #ifdef __cplusplus
850 }
851 #endif
852
853 #endif /* #ifndef CGLTF_H_INCLUDED__ */
854
855 /*
856 *
857 * Stop now, if you are only interested in the API.
858 * Below, you find the implementation.
859 *
860 */
861
862 #if defined(__INTELLISENSE__) || defined(__JETBRAINS_IDE__)
863 /* This makes MSVC/CLion intellisense work. */
864 #define CGLTF_IMPLEMENTATION
865 #endif
866
867 #ifdef CGLTF_IMPLEMENTATION
868
869 #include <string.h> /* For strncpy */
870 #include <stdio.h> /* For fopen */
871 #include <limits.h> /* For UINT_MAX etc */
872 #include <float.h> /* For FLT_MAX */
873
874 #if !defined(CGLTF_MALLOC) || !defined(CGLTF_FREE) || !defined(CGLTF_ATOI) || !defined(CGLTF_ATOF) || !defined(CGLTF_ATOLL)
875 #include <stdlib.h> /* For malloc, free, atoi, atof */
876 #endif
877
878 #if CGLTF_VALIDATE_ENABLE_ASSERTS
879 #include <assert.h>
880 #endif
881
882 /* JSMN_PARENT_LINKS is necessary to make parsing large structures linear in input size */
883 #define JSMN_PARENT_LINKS
884
885 /* JSMN_STRICT is necessary to reject invalid JSON documents */
886 #define JSMN_STRICT
887
888 /*
889 * -- jsmn.h start --
890 * Source: https://github.com/zserge/jsmn
891 * License: MIT
892 */
893 typedef enum {
894 JSMN_UNDEFINED = 0,
895 JSMN_OBJECT = 1,
896 JSMN_ARRAY = 2,
897 JSMN_STRING = 3,
898 JSMN_PRIMITIVE = 4
899 } jsmntype_t;
900 enum jsmnerr {
901 /* Not enough tokens were provided */
902 JSMN_ERROR_NOMEM = -1,
903 /* Invalid character inside JSON string */
904 JSMN_ERROR_INVAL = -2,
905 /* The string is not a full JSON packet, more bytes expected */
906 JSMN_ERROR_PART = -3
907 };
908 typedef struct {
909 jsmntype_t type;
910 ptrdiff_t start;
911 ptrdiff_t end;
912 int size;
913 #ifdef JSMN_PARENT_LINKS
914 int parent;
915 #endif
916 } jsmntok_t;
917 typedef struct {
918 size_t pos; /* offset in the JSON string */
919 unsigned int toknext; /* next token to allocate */
920 int toksuper; /* superior token node, e.g parent object or array */
921 } jsmn_parser;
922 static void jsmn_init(jsmn_parser *parser);
923 static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens);
924 /*
925 * -- jsmn.h end --
926 */
927
928
929 #ifndef CGLTF_CONSTS
930 static const cgltf_size GlbHeaderSize = 12;
931 static const cgltf_size GlbChunkHeaderSize = 8;
932 static const uint32_t GlbVersion = 2;
933 static const uint32_t GlbMagic = 0x46546C67;
934 static const uint32_t GlbMagicJsonChunk = 0x4E4F534A;
935 static const uint32_t GlbMagicBinChunk = 0x004E4942;
936 #define CGLTF_CONSTS
937 #endif
938
939 #ifndef CGLTF_MALLOC
940 #define CGLTF_MALLOC(size) malloc(size)
941 #endif
942 #ifndef CGLTF_FREE
943 #define CGLTF_FREE(ptr) free(ptr)
944 #endif
945 #ifndef CGLTF_ATOI
946 #define CGLTF_ATOI(str) atoi(str)
947 #endif
948 #ifndef CGLTF_ATOF
949 #define CGLTF_ATOF(str) atof(str)
950 #endif
951 #ifndef CGLTF_ATOLL
952 #define CGLTF_ATOLL(str) atoll(str)
953 #endif
954 #ifndef CGLTF_VALIDATE_ENABLE_ASSERTS
955 #define CGLTF_VALIDATE_ENABLE_ASSERTS 0
956 #endif
957
958 static void* cgltf_default_alloc(void* user, cgltf_size size)
959 {
960 (void)user;
961 return CGLTF_MALLOC(size);
962 }
963
964 static void cgltf_default_free(void* user, void* ptr)
965 {
966 (void)user;
967 CGLTF_FREE(ptr);
968 }
969
970 static void* cgltf_calloc(cgltf_options* options, size_t element_size, cgltf_size count)
971 {
972 if (SIZE_MAX / element_size < count)
973 {
974 return NULL;
975 }
976 void* result = options->memory.alloc_func(options->memory.user_data, element_size * count);
977 if (!result)
978 {
979 return NULL;
980 }
981 memset(result, 0, element_size * count);
982 return result;
983 }
984
985 static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, const char* path, cgltf_size* size, void** data)
986 {
987 (void)file_options;
988 void* (*memory_alloc)(void*, cgltf_size) = memory_options->alloc_func ? memory_options->alloc_func : &cgltf_default_alloc;
989 void (*memory_free)(void*, void*) = memory_options->free_func ? memory_options->free_func : &cgltf_default_free;
990
991 FILE* file = fopen(path, "rb");
992 if (!file)
993 {
994 return cgltf_result_file_not_found;
995 }
996
997 cgltf_size file_size = size ? *size : 0;
998
999 if (file_size == 0)
1000 {
1001 fseek(file, 0, SEEK_END);
1002
1003 #ifdef _WIN32
1004 __int64 length = _ftelli64(file);
1005 #else
1006 long length = ftell(file);
1007 #endif
1008
1009 if (length < 0)
1010 {
1011 fclose(file);
1012 return cgltf_result_io_error;
1013 }
1014
1015 fseek(file, 0, SEEK_SET);
1016 file_size = (cgltf_size)length;
1017 }
1018
1019 char* file_data = (char*)memory_alloc(memory_options->user_data, file_size);
1020 if (!file_data)
1021 {
1022 fclose(file);
1023 return cgltf_result_out_of_memory;
1024 }
1025
1026 cgltf_size read_size = fread(file_data, 1, file_size, file);
1027
1028 fclose(file);
1029
1030 if (read_size != file_size)
1031 {
1032 memory_free(memory_options->user_data, file_data);
1033 return cgltf_result_io_error;
1034 }
1035
1036 if (size)
1037 {
1038 *size = file_size;
1039 }
1040 if (data)
1041 {
1042 *data = file_data;
1043 }
1044
1045 return cgltf_result_success;
1046 }
1047
1048 static void cgltf_default_file_release(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data)
1049 {
1050 (void)file_options;
1051 void (*memfree)(void*, void*) = memory_options->free_func ? memory_options->free_func : &cgltf_default_free;
1052 memfree(memory_options->user_data, data);
1053 }
1054
1055 static cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, cgltf_size size, cgltf_data** out_data);
1056
1057 cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_size size, cgltf_data** out_data)
1058 {
1059 if (size < GlbHeaderSize)
1060 {
1061 return cgltf_result_data_too_short;
1062 }
1063
1064 if (options == NULL)
1065 {
1066 return cgltf_result_invalid_options;
1067 }
1068
1069 cgltf_options fixed_options = *options;
1070 if (fixed_options.memory.alloc_func == NULL)
1071 {
1072 fixed_options.memory.alloc_func = &cgltf_default_alloc;
1073 }
1074 if (fixed_options.memory.free_func == NULL)
1075 {
1076 fixed_options.memory.free_func = &cgltf_default_free;
1077 }
1078
1079 uint32_t tmp;
1080 // Magic
1081 memcpy(&tmp, data, 4);
1082 if (tmp != GlbMagic)
1083 {
1084 if (fixed_options.type == cgltf_file_type_invalid)
1085 {
1086 fixed_options.type = cgltf_file_type_gltf;
1087 }
1088 else if (fixed_options.type == cgltf_file_type_glb)
1089 {
1090 return cgltf_result_unknown_format;
1091 }
1092 }
1093
1094 if (fixed_options.type == cgltf_file_type_gltf)
1095 {
1096 cgltf_result json_result = cgltf_parse_json(&fixed_options, (const uint8_t*)data, size, out_data);
1097 if (json_result != cgltf_result_success)
1098 {
1099 return json_result;
1100 }
1101
1102 (*out_data)->file_type = cgltf_file_type_gltf;
1103
1104 return cgltf_result_success;
1105 }
1106
1107 const uint8_t* ptr = (const uint8_t*)data;
1108 // Version
1109 memcpy(&tmp, ptr + 4, 4);
1110 uint32_t version = tmp;
1111 if (version != GlbVersion)
1112 {
1113 return version < GlbVersion ? cgltf_result_legacy_gltf : cgltf_result_unknown_format;
1114 }
1115
1116 // Total length
1117 memcpy(&tmp, ptr + 8, 4);
1118 if (tmp > size)
1119 {
1120 return cgltf_result_data_too_short;
1121 }
1122
1123 const uint8_t* json_chunk = ptr + GlbHeaderSize;
1124
1125 if (GlbHeaderSize + GlbChunkHeaderSize > size)
1126 {
1127 return cgltf_result_data_too_short;
1128 }
1129
1130 // JSON chunk: length
1131 uint32_t json_length;
1132 memcpy(&json_length, json_chunk, 4);
1133 if (GlbHeaderSize + GlbChunkHeaderSize + json_length > size)
1134 {
1135 return cgltf_result_data_too_short;
1136 }
1137
1138 // JSON chunk: magic
1139 memcpy(&tmp, json_chunk + 4, 4);
1140 if (tmp != GlbMagicJsonChunk)
1141 {
1142 return cgltf_result_unknown_format;
1143 }
1144
1145 json_chunk += GlbChunkHeaderSize;
1146
1147 const void* bin = 0;
1148 cgltf_size bin_size = 0;
1149
1150 if (GlbHeaderSize + GlbChunkHeaderSize + json_length + GlbChunkHeaderSize <= size)
1151 {
1152 // We can read another chunk
1153 const uint8_t* bin_chunk = json_chunk + json_length;
1154
1155 // Bin chunk: length
1156 uint32_t bin_length;
1157 memcpy(&bin_length, bin_chunk, 4);
1158 if (GlbHeaderSize + GlbChunkHeaderSize + json_length + GlbChunkHeaderSize + bin_length > size)
1159 {
1160 return cgltf_result_data_too_short;
1161 }
1162
1163 // Bin chunk: magic
1164 memcpy(&tmp, bin_chunk + 4, 4);
1165 if (tmp != GlbMagicBinChunk)
1166 {
1167 return cgltf_result_unknown_format;
1168 }
1169
1170 bin_chunk += GlbChunkHeaderSize;
1171
1172 bin = bin_chunk;
1173 bin_size = bin_length;
1174 }
1175
1176 cgltf_result json_result = cgltf_parse_json(&fixed_options, json_chunk, json_length, out_data);
1177 if (json_result != cgltf_result_success)
1178 {
1179 return json_result;
1180 }
1181
1182 (*out_data)->file_type = cgltf_file_type_glb;
1183 (*out_data)->bin = bin;
1184 (*out_data)->bin_size = bin_size;
1185
1186 return cgltf_result_success;
1187 }
1188
1189 cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cgltf_data** out_data)
1190 {
1191 if (options == NULL)
1192 {
1193 return cgltf_result_invalid_options;
1194 }
1195
1196 cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read;
1197 void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = options->file.release ? options->file.release : cgltf_default_file_release;
1198
1199 void* file_data = NULL;
1200 cgltf_size file_size = 0;
1201 cgltf_result result = file_read(&options->memory, &options->file, path, &file_size, &file_data);
1202 if (result != cgltf_result_success)
1203 {
1204 return result;
1205 }
1206
1207 result = cgltf_parse(options, file_data, file_size, out_data);
1208
1209 if (result != cgltf_result_success)
1210 {
1211 file_release(&options->memory, &options->file, file_data);
1212 return result;
1213 }
1214
1215 (*out_data)->file_data = file_data;
1216
1217 return cgltf_result_success;
1218 }
1219
1220 static void cgltf_combine_paths(char* path, const char* base, const char* uri)
1221 {
1222 const char* s0 = strrchr(base, '/');
1223 const char* s1 = strrchr(base, '\\');
1224 const char* slash = s0 ? (s1 && s1 > s0 ? s1 : s0) : s1;
1225
1226 if (slash)
1227 {
1228 size_t prefix = slash - base + 1;
1229
1230 strncpy(path, base, prefix);
1231 strcpy(path + prefix, uri);
1232 }
1233 else
1234 {
1235 strcpy(path, uri);
1236 }
1237 }
1238
1239 static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_size size, const char* uri, const char* gltf_path, void** out_data)
1240 {
1241 void* (*memory_alloc)(void*, cgltf_size) = options->memory.alloc_func ? options->memory.alloc_func : &cgltf_default_alloc;
1242 void (*memory_free)(void*, void*) = options->memory.free_func ? options->memory.free_func : &cgltf_default_free;
1243 cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read;
1244
1245 char* path = (char*)memory_alloc(options->memory.user_data, strlen(uri) + strlen(gltf_path) + 1);
1246 if (!path)
1247 {
1248 return cgltf_result_out_of_memory;
1249 }
1250
1251 cgltf_combine_paths(path, gltf_path, uri);
1252
1253 // after combining, the tail of the resulting path is a uri; decode_uri converts it into path
1254 cgltf_decode_uri(path + strlen(path) - strlen(uri));
1255
1256 void* file_data = NULL;
1257 cgltf_result result = file_read(&options->memory, &options->file, path, &size, &file_data);
1258
1259 memory_free(options->memory.user_data, path);
1260
1261 *out_data = (result == cgltf_result_success) ? file_data : NULL;
1262
1263 return result;
1264 }
1265
1266 cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data)
1267 {
1268 void* (*memory_alloc)(void*, cgltf_size) = options->memory.alloc_func ? options->memory.alloc_func : &cgltf_default_alloc;
1269 void (*memory_free)(void*, void*) = options->memory.free_func ? options->memory.free_func : &cgltf_default_free;
1270
1271 unsigned char* data = (unsigned char*)memory_alloc(options->memory.user_data, size);
1272 if (!data)
1273 {
1274 return cgltf_result_out_of_memory;
1275 }
1276
1277 unsigned int buffer = 0;
1278 unsigned int buffer_bits = 0;
1279
1280 for (cgltf_size i = 0; i < size; ++i)
1281 {
1282 while (buffer_bits < 8)
1283 {
1284 char ch = *base64++;
1285
1286 int index =
1287 (unsigned)(ch - 'A') < 26 ? (ch - 'A') :
1288 (unsigned)(ch - 'a') < 26 ? (ch - 'a') + 26 :
1289 (unsigned)(ch - '0') < 10 ? (ch - '0') + 52 :
1290 ch == '+' ? 62 :
1291 ch == '/' ? 63 :
1292 -1;
1293
1294 if (index < 0)
1295 {
1296 memory_free(options->memory.user_data, data);
1297 return cgltf_result_io_error;
1298 }
1299
1300 buffer = (buffer << 6) | index;
1301 buffer_bits += 6;
1302 }
1303
1304 data[i] = (unsigned char)(buffer >> (buffer_bits - 8));
1305 buffer_bits -= 8;
1306 }
1307
1308 *out_data = data;
1309
1310 return cgltf_result_success;
1311 }
1312
1313 static int cgltf_unhex(char ch)
1314 {
1315 return
1316 (unsigned)(ch - '0') < 10 ? (ch - '0') :
1317 (unsigned)(ch - 'A') < 6 ? (ch - 'A') + 10 :
1318 (unsigned)(ch - 'a') < 6 ? (ch - 'a') + 10 :
1319 -1;
1320 }
1321
1322 cgltf_size cgltf_decode_string(char* string)
1323 {
1324 char* read = string + strcspn(string, "\\");
1325 if (*read == 0)
1326 {
1327 return read - string;
1328 }
1329 char* write = string;
1330 char* last = string;
1331
1332 for (;;)
1333 {
1334 // Copy characters since last escaped sequence
1335 cgltf_size written = read - last;
1336 memmove(write, last, written);
1337 write += written;
1338
1339 if (*read++ == 0)
1340 {
1341 break;
1342 }
1343
1344 // jsmn already checked that all escape sequences are valid
1345 switch (*read++)
1346 {
1347 case '\"': *write++ = '\"'; break;
1348 case '/': *write++ = '/'; break;
1349 case '\\': *write++ = '\\'; break;
1350 case 'b': *write++ = '\b'; break;
1351 case 'f': *write++ = '\f'; break;
1352 case 'r': *write++ = '\r'; break;
1353 case 'n': *write++ = '\n'; break;
1354 case 't': *write++ = '\t'; break;
1355 case 'u':
1356 {
1357 // UCS-2 codepoint \uXXXX to UTF-8
1358 int character = 0;
1359 for (cgltf_size i = 0; i < 4; ++i)
1360 {
1361 character = (character << 4) + cgltf_unhex(*read++);
1362 }
1363
1364 if (character <= 0x7F)
1365 {
1366 *write++ = character & 0xFF;
1367 }
1368 else if (character <= 0x7FF)
1369 {
1370 *write++ = 0xC0 | ((character >> 6) & 0xFF);
1371 *write++ = 0x80 | (character & 0x3F);
1372 }
1373 else
1374 {
1375 *write++ = 0xE0 | ((character >> 12) & 0xFF);
1376 *write++ = 0x80 | ((character >> 6) & 0x3F);
1377 *write++ = 0x80 | (character & 0x3F);
1378 }
1379 break;
1380 }
1381 default:
1382 break;
1383 }
1384
1385 last = read;
1386 read += strcspn(read, "\\");
1387 }
1388
1389 *write = 0;
1390 return write - string;
1391 }
1392
1393 cgltf_size cgltf_decode_uri(char* uri)
1394 {
1395 char* write = uri;
1396 char* i = uri;
1397
1398 while (*i)
1399 {
1400 if (*i == '%')
1401 {
1402 int ch1 = cgltf_unhex(i[1]);
1403
1404 if (ch1 >= 0)
1405 {
1406 int ch2 = cgltf_unhex(i[2]);
1407
1408 if (ch2 >= 0)
1409 {
1410 *write++ = (char)(ch1 * 16 + ch2);
1411 i += 3;
1412 continue;
1413 }
1414 }
1415 }
1416
1417 *write++ = *i++;
1418 }
1419
1420 *write = 0;
1421 return write - uri;
1422 }
1423
1424 cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, const char* gltf_path)
1425 {
1426 if (options == NULL)
1427 {
1428 return cgltf_result_invalid_options;
1429 }
1430
1431 if (data->buffers_count && data->buffers[0].data == NULL && data->buffers[0].uri == NULL && data->bin)
1432 {
1433 if (data->bin_size < data->buffers[0].size)
1434 {
1435 return cgltf_result_data_too_short;
1436 }
1437
1438 data->buffers[0].data = (void*)data->bin;
1439 data->buffers[0].data_free_method = cgltf_data_free_method_none;
1440 }
1441
1442 for (cgltf_size i = 0; i < data->buffers_count; ++i)
1443 {
1444 if (data->buffers[i].data)
1445 {
1446 continue;
1447 }
1448
1449 const char* uri = data->buffers[i].uri;
1450
1451 if (uri == NULL)
1452 {
1453 continue;
1454 }
1455
1456 if (strncmp(uri, "data:", 5) == 0)
1457 {
1458 const char* comma = strchr(uri, ',');
1459
1460 if (comma && comma - uri >= 7 && strncmp(comma - 7, ";base64", 7) == 0)
1461 {
1462 cgltf_result res = cgltf_load_buffer_base64(options, data->buffers[i].size, comma + 1, &data->buffers[i].data);
1463 data->buffers[i].data_free_method = cgltf_data_free_method_memory_free;
1464
1465 if (res != cgltf_result_success)
1466 {
1467 return res;
1468 }
1469 }
1470 else
1471 {
1472 return cgltf_result_unknown_format;
1473 }
1474 }
1475 else if (strstr(uri, "://") == NULL && gltf_path)
1476 {
1477 cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data);
1478 data->buffers[i].data_free_method = cgltf_data_free_method_file_release;
1479
1480 if (res != cgltf_result_success)
1481 {
1482 return res;
1483 }
1484 }
1485 else
1486 {
1487 return cgltf_result_unknown_format;
1488 }
1489 }
1490
1491 return cgltf_result_success;
1492 }
1493
1494 static cgltf_size cgltf_calc_index_bound(cgltf_buffer_view* buffer_view, cgltf_size offset, cgltf_component_type component_type, cgltf_size count)
1495 {
1496 char* data = (char*)buffer_view->buffer->data + offset + buffer_view->offset;
1497 cgltf_size bound = 0;
1498
1499 switch (component_type)
1500 {
1501 case cgltf_component_type_r_8u:
1502 for (size_t i = 0; i < count; ++i)
1503 {
1504 cgltf_size v = ((unsigned char*)data)[i];
1505 bound = bound > v ? bound : v;
1506 }
1507 break;
1508
1509 case cgltf_component_type_r_16u:
1510 for (size_t i = 0; i < count; ++i)
1511 {
1512 cgltf_size v = ((unsigned short*)data)[i];
1513 bound = bound > v ? bound : v;
1514 }
1515 break;
1516
1517 case cgltf_component_type_r_32u:
1518 for (size_t i = 0; i < count; ++i)
1519 {
1520 cgltf_size v = ((unsigned int*)data)[i];
1521 bound = bound > v ? bound : v;
1522 }
1523 break;
1524
1525 default:
1526 ;
1527 }
1528
1529 return bound;
1530 }
1531
1532 #if CGLTF_VALIDATE_ENABLE_ASSERTS
1533 #define CGLTF_ASSERT_IF(cond, result) assert(!(cond)); if (cond) return result;
1534 #else
1535 #define CGLTF_ASSERT_IF(cond, result) if (cond) return result;
1536 #endif
1537
1538 cgltf_result cgltf_validate(cgltf_data* data)
1539 {
1540 for (cgltf_size i = 0; i < data->accessors_count; ++i)
1541 {
1542 cgltf_accessor* accessor = &data->accessors[i];
1543
1544 cgltf_size element_size = cgltf_calc_size(accessor->type, accessor->component_type);
1545
1546 if (accessor->buffer_view)
1547 {
1548 cgltf_size req_size = accessor->offset + accessor->stride * (accessor->count - 1) + element_size;
1549
1550 CGLTF_ASSERT_IF(accessor->buffer_view->size < req_size, cgltf_result_data_too_short);
1551 }
1552
1553 if (accessor->is_sparse)
1554 {
1555 cgltf_accessor_sparse* sparse = &accessor->sparse;
1556
1557 cgltf_size indices_component_size = cgltf_calc_size(cgltf_type_scalar, sparse->indices_component_type);
1558 cgltf_size indices_req_size = sparse->indices_byte_offset + indices_component_size * sparse->count;
1559 cgltf_size values_req_size = sparse->values_byte_offset + element_size * sparse->count;
1560
1561 CGLTF_ASSERT_IF(sparse->indices_buffer_view->size < indices_req_size ||
1562 sparse->values_buffer_view->size < values_req_size, cgltf_result_data_too_short);
1563
1564 CGLTF_ASSERT_IF(sparse->indices_component_type != cgltf_component_type_r_8u &&
1565 sparse->indices_component_type != cgltf_component_type_r_16u &&
1566 sparse->indices_component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf);
1567
1568 if (sparse->indices_buffer_view->buffer->data)
1569 {
1570 cgltf_size index_bound = cgltf_calc_index_bound(sparse->indices_buffer_view, sparse->indices_byte_offset, sparse->indices_component_type, sparse->count);
1571
1572 CGLTF_ASSERT_IF(index_bound >= accessor->count, cgltf_result_data_too_short);
1573 }
1574 }
1575 }
1576
1577 for (cgltf_size i = 0; i < data->buffer_views_count; ++i)
1578 {
1579 cgltf_size req_size = data->buffer_views[i].offset + data->buffer_views[i].size;
1580
1581 CGLTF_ASSERT_IF(data->buffer_views[i].buffer && data->buffer_views[i].buffer->size < req_size, cgltf_result_data_too_short);
1582
1583 if (data->buffer_views[i].has_meshopt_compression)
1584 {
1585 cgltf_meshopt_compression* mc = &data->buffer_views[i].meshopt_compression;
1586
1587 CGLTF_ASSERT_IF(mc->buffer == NULL || mc->buffer->size < mc->offset + mc->size, cgltf_result_data_too_short);
1588
1589 CGLTF_ASSERT_IF(data->buffer_views[i].stride && mc->stride != data->buffer_views[i].stride, cgltf_result_invalid_gltf);
1590
1591 CGLTF_ASSERT_IF(data->buffer_views[i].size != mc->stride * mc->count, cgltf_result_invalid_gltf);
1592
1593 CGLTF_ASSERT_IF(mc->mode == cgltf_meshopt_compression_mode_invalid, cgltf_result_invalid_gltf);
1594
1595 CGLTF_ASSERT_IF(mc->mode == cgltf_meshopt_compression_mode_attributes && !(mc->stride % 4 == 0 && mc->stride <= 256), cgltf_result_invalid_gltf);
1596
1597 CGLTF_ASSERT_IF(mc->mode == cgltf_meshopt_compression_mode_triangles && mc->count % 3 != 0, cgltf_result_invalid_gltf);
1598
1599 CGLTF_ASSERT_IF((mc->mode == cgltf_meshopt_compression_mode_triangles || mc->mode == cgltf_meshopt_compression_mode_indices) && mc->stride != 2 && mc->stride != 4, cgltf_result_invalid_gltf);
1600
1601 CGLTF_ASSERT_IF((mc->mode == cgltf_meshopt_compression_mode_triangles || mc->mode == cgltf_meshopt_compression_mode_indices) && mc->filter != cgltf_meshopt_compression_filter_none, cgltf_result_invalid_gltf);
1602
1603 CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_octahedral && mc->stride != 4 && mc->stride != 8, cgltf_result_invalid_gltf);
1604
1605 CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_quaternion && mc->stride != 8, cgltf_result_invalid_gltf);
1606 }
1607 }
1608
1609 for (cgltf_size i = 0; i < data->meshes_count; ++i)
1610 {
1611 if (data->meshes[i].weights)
1612 {
1613 CGLTF_ASSERT_IF(data->meshes[i].primitives_count && data->meshes[i].primitives[0].targets_count != data->meshes[i].weights_count, cgltf_result_invalid_gltf);
1614 }
1615
1616 if (data->meshes[i].target_names)
1617 {
1618 CGLTF_ASSERT_IF(data->meshes[i].primitives_count && data->meshes[i].primitives[0].targets_count != data->meshes[i].target_names_count, cgltf_result_invalid_gltf);
1619 }
1620
1621 for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j)
1622 {
1623 CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets_count != data->meshes[i].primitives[0].targets_count, cgltf_result_invalid_gltf);
1624
1625 if (data->meshes[i].primitives[j].attributes_count)
1626 {
1627 cgltf_accessor* first = data->meshes[i].primitives[j].attributes[0].data;
1628
1629 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k)
1630 {
1631 CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes[k].data->count != first->count, cgltf_result_invalid_gltf);
1632 }
1633
1634 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k)
1635 {
1636 for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m)
1637 {
1638 CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets[k].attributes[m].data->count != first->count, cgltf_result_invalid_gltf);
1639 }
1640 }
1641
1642 cgltf_accessor* indices = data->meshes[i].primitives[j].indices;
1643
1644 CGLTF_ASSERT_IF(indices &&
1645 indices->component_type != cgltf_component_type_r_8u &&
1646 indices->component_type != cgltf_component_type_r_16u &&
1647 indices->component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf);
1648
1649 if (indices && indices->buffer_view && indices->buffer_view->buffer->data)
1650 {
1651 cgltf_size index_bound = cgltf_calc_index_bound(indices->buffer_view, indices->offset, indices->component_type, indices->count);
1652
1653 CGLTF_ASSERT_IF(index_bound >= first->count, cgltf_result_data_too_short);
1654 }
1655
1656 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k)
1657 {
1658 CGLTF_ASSERT_IF(data->meshes[i].primitives[j].mappings[k].variant >= data->variants_count, cgltf_result_invalid_gltf);
1659 }
1660 }
1661 }
1662 }
1663
1664 for (cgltf_size i = 0; i < data->nodes_count; ++i)
1665 {
1666 if (data->nodes[i].weights && data->nodes[i].mesh)
1667 {
1668 CGLTF_ASSERT_IF (data->nodes[i].mesh->primitives_count && data->nodes[i].mesh->primitives[0].targets_count != data->nodes[i].weights_count, cgltf_result_invalid_gltf);
1669 }
1670 }
1671
1672 for (cgltf_size i = 0; i < data->nodes_count; ++i)
1673 {
1674 cgltf_node* p1 = data->nodes[i].parent;
1675 cgltf_node* p2 = p1 ? p1->parent : NULL;
1676
1677 while (p1 && p2)
1678 {
1679 CGLTF_ASSERT_IF(p1 == p2, cgltf_result_invalid_gltf);
1680
1681 p1 = p1->parent;
1682 p2 = p2->parent ? p2->parent->parent : NULL;
1683 }
1684 }
1685
1686 for (cgltf_size i = 0; i < data->scenes_count; ++i)
1687 {
1688 for (cgltf_size j = 0; j < data->scenes[i].nodes_count; ++j)
1689 {
1690 CGLTF_ASSERT_IF(data->scenes[i].nodes[j]->parent, cgltf_result_invalid_gltf);
1691 }
1692 }
1693
1694 for (cgltf_size i = 0; i < data->animations_count; ++i)
1695 {
1696 for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j)
1697 {
1698 cgltf_animation_channel* channel = &data->animations[i].channels[j];
1699
1700 if (!channel->target_node)
1701 {
1702 continue;
1703 }
1704
1705 cgltf_size components = 1;
1706
1707 if (channel->target_path == cgltf_animation_path_type_weights)
1708 {
1709 CGLTF_ASSERT_IF(!channel->target_node->mesh || !channel->target_node->mesh->primitives_count, cgltf_result_invalid_gltf);
1710
1711 components = channel->target_node->mesh->primitives[0].targets_count;
1712 }
1713
1714 cgltf_size values = channel->sampler->interpolation == cgltf_interpolation_type_cubic_spline ? 3 : 1;
1715
1716 CGLTF_ASSERT_IF(channel->sampler->input->count * components * values != channel->sampler->output->count, cgltf_result_data_too_short);
1717 }
1718 }
1719
1720 return cgltf_result_success;
1721 }
1722
1723 cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size)
1724 {
1725 cgltf_size json_size = extras->end_offset - extras->start_offset;
1726
1727 if (!dest)
1728 {
1729 if (dest_size)
1730 {
1731 *dest_size = json_size + 1;
1732 return cgltf_result_success;
1733 }
1734 return cgltf_result_invalid_options;
1735 }
1736
1737 if (*dest_size + 1 < json_size)
1738 {
1739 strncpy(dest, data->json + extras->start_offset, *dest_size - 1);
1740 dest[*dest_size - 1] = 0;
1741 }
1742 else
1743 {
1744 strncpy(dest, data->json + extras->start_offset, json_size);
1745 dest[json_size] = 0;
1746 }
1747
1748 return cgltf_result_success;
1749 }
1750
1751 static void cgltf_free_extras(cgltf_data* data, cgltf_extras* extras)
1752 {
1753 data->memory.free_func(data->memory.user_data, extras->data);
1754 }
1755
1756 static void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, cgltf_size extensions_count)
1757 {
1758 for (cgltf_size i = 0; i < extensions_count; ++i)
1759 {
1760 data->memory.free_func(data->memory.user_data, extensions[i].name);
1761 data->memory.free_func(data->memory.user_data, extensions[i].data);
1762 }
1763 data->memory.free_func(data->memory.user_data, extensions);
1764 }
1765
1766 static void cgltf_free_texture_view(cgltf_data* data, cgltf_texture_view* view)
1767 {
1768 cgltf_free_extensions(data, view->extensions, view->extensions_count);
1769 cgltf_free_extras(data, &view->extras);
1770 }
1771
1772 void cgltf_free(cgltf_data* data)
1773 {
1774 if (!data)
1775 {
1776 return;
1777 }
1778
1779 void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = data->file.release ? data->file.release : cgltf_default_file_release;
1780
1781 data->memory.free_func(data->memory.user_data, data->asset.copyright);
1782 data->memory.free_func(data->memory.user_data, data->asset.generator);
1783 data->memory.free_func(data->memory.user_data, data->asset.version);
1784 data->memory.free_func(data->memory.user_data, data->asset.min_version);
1785
1786 cgltf_free_extensions(data, data->asset.extensions, data->asset.extensions_count);
1787 cgltf_free_extras(data, &data->asset.extras);
1788
1789 for (cgltf_size i = 0; i < data->accessors_count; ++i)
1790 {
1791 data->memory.free_func(data->memory.user_data, data->accessors[i].name);
1792
1793 if(data->accessors[i].is_sparse)
1794 {
1795 cgltf_free_extensions(data, data->accessors[i].sparse.extensions, data->accessors[i].sparse.extensions_count);
1796 cgltf_free_extensions(data, data->accessors[i].sparse.indices_extensions, data->accessors[i].sparse.indices_extensions_count);
1797 cgltf_free_extensions(data, data->accessors[i].sparse.values_extensions, data->accessors[i].sparse.values_extensions_count);
1798 cgltf_free_extras(data, &data->accessors[i].sparse.extras);
1799 cgltf_free_extras(data, &data->accessors[i].sparse.indices_extras);
1800 cgltf_free_extras(data, &data->accessors[i].sparse.values_extras);
1801 }
1802 cgltf_free_extensions(data, data->accessors[i].extensions, data->accessors[i].extensions_count);
1803 cgltf_free_extras(data, &data->accessors[i].extras);
1804 }
1805 data->memory.free_func(data->memory.user_data, data->accessors);
1806
1807 for (cgltf_size i = 0; i < data->buffer_views_count; ++i)
1808 {
1809 data->memory.free_func(data->memory.user_data, data->buffer_views[i].name);
1810 data->memory.free_func(data->memory.user_data, data->buffer_views[i].data);
1811
1812 cgltf_free_extensions(data, data->buffer_views[i].extensions, data->buffer_views[i].extensions_count);
1813 cgltf_free_extras(data, &data->buffer_views[i].extras);
1814 }
1815 data->memory.free_func(data->memory.user_data, data->buffer_views);
1816
1817 for (cgltf_size i = 0; i < data->buffers_count; ++i)
1818 {
1819 data->memory.free_func(data->memory.user_data, data->buffers[i].name);
1820
1821 if (data->buffers[i].data_free_method == cgltf_data_free_method_file_release)
1822 {
1823 file_release(&data->memory, &data->file, data->buffers[i].data);
1824 }
1825 else if (data->buffers[i].data_free_method == cgltf_data_free_method_memory_free)
1826 {
1827 data->memory.free_func(data->memory.user_data, data->buffers[i].data);
1828 }
1829
1830 data->memory.free_func(data->memory.user_data, data->buffers[i].uri);
1831
1832 cgltf_free_extensions(data, data->buffers[i].extensions, data->buffers[i].extensions_count);
1833 cgltf_free_extras(data, &data->buffers[i].extras);
1834 }
1835 data->memory.free_func(data->memory.user_data, data->buffers);
1836
1837 for (cgltf_size i = 0; i < data->meshes_count; ++i)
1838 {
1839 data->memory.free_func(data->memory.user_data, data->meshes[i].name);
1840
1841 for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j)
1842 {
1843 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k)
1844 {
1845 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].attributes[k].name);
1846 }
1847
1848 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].attributes);
1849
1850 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k)
1851 {
1852 for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m)
1853 {
1854 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].targets[k].attributes[m].name);
1855 }
1856
1857 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].targets[k].attributes);
1858 }
1859
1860 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].targets);
1861
1862 if (data->meshes[i].primitives[j].has_draco_mesh_compression)
1863 {
1864 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].draco_mesh_compression.attributes_count; ++k)
1865 {
1866 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].draco_mesh_compression.attributes[k].name);
1867 }
1868
1869 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].draco_mesh_compression.attributes);
1870 }
1871
1872 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k)
1873 {
1874 cgltf_free_extras(data, &data->meshes[i].primitives[j].mappings[k].extras);
1875 }
1876
1877 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].mappings);
1878
1879 cgltf_free_extensions(data, data->meshes[i].primitives[j].extensions, data->meshes[i].primitives[j].extensions_count);
1880 cgltf_free_extras(data, &data->meshes[i].primitives[j].extras);
1881 }
1882
1883 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives);
1884 data->memory.free_func(data->memory.user_data, data->meshes[i].weights);
1885
1886 for (cgltf_size j = 0; j < data->meshes[i].target_names_count; ++j)
1887 {
1888 data->memory.free_func(data->memory.user_data, data->meshes[i].target_names[j]);
1889 }
1890
1891 cgltf_free_extensions(data, data->meshes[i].extensions, data->meshes[i].extensions_count);
1892 cgltf_free_extras(data, &data->meshes[i].extras);
1893
1894 data->memory.free_func(data->memory.user_data, data->meshes[i].target_names);
1895 }
1896
1897 data->memory.free_func(data->memory.user_data, data->meshes);
1898
1899 for (cgltf_size i = 0; i < data->materials_count; ++i)
1900 {
1901 data->memory.free_func(data->memory.user_data, data->materials[i].name);
1902
1903 if(data->materials[i].has_pbr_metallic_roughness)
1904 {
1905 cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.metallic_roughness_texture);
1906 cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.base_color_texture);
1907 }
1908 if(data->materials[i].has_pbr_specular_glossiness)
1909 {
1910 cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.diffuse_texture);
1911 cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.specular_glossiness_texture);
1912 }
1913 if(data->materials[i].has_clearcoat)
1914 {
1915 cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_texture);
1916 cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_roughness_texture);
1917 cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_normal_texture);
1918 }
1919 if(data->materials[i].has_specular)
1920 {
1921 cgltf_free_texture_view(data, &data->materials[i].specular.specular_texture);
1922 cgltf_free_texture_view(data, &data->materials[i].specular.specular_color_texture);
1923 }
1924 if(data->materials[i].has_transmission)
1925 {
1926 cgltf_free_texture_view(data, &data->materials[i].transmission.transmission_texture);
1927 }
1928 if (data->materials[i].has_volume)
1929 {
1930 cgltf_free_texture_view(data, &data->materials[i].volume.thickness_texture);
1931 }
1932 if(data->materials[i].has_sheen)
1933 {
1934 cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_color_texture);
1935 cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_roughness_texture);
1936 }
1937 if(data->materials[i].has_iridescence)
1938 {
1939 cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_texture);
1940 cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_thickness_texture);
1941 }
1942
1943 cgltf_free_texture_view(data, &data->materials[i].normal_texture);
1944 cgltf_free_texture_view(data, &data->materials[i].occlusion_texture);
1945 cgltf_free_texture_view(data, &data->materials[i].emissive_texture);
1946
1947 cgltf_free_extensions(data, data->materials[i].extensions, data->materials[i].extensions_count);
1948 cgltf_free_extras(data, &data->materials[i].extras);
1949 }
1950
1951 data->memory.free_func(data->memory.user_data, data->materials);
1952
1953 for (cgltf_size i = 0; i < data->images_count; ++i)
1954 {
1955 data->memory.free_func(data->memory.user_data, data->images[i].name);
1956 data->memory.free_func(data->memory.user_data, data->images[i].uri);
1957 data->memory.free_func(data->memory.user_data, data->images[i].mime_type);
1958
1959 cgltf_free_extensions(data, data->images[i].extensions, data->images[i].extensions_count);
1960 cgltf_free_extras(data, &data->images[i].extras);
1961 }
1962
1963 data->memory.free_func(data->memory.user_data, data->images);
1964
1965 for (cgltf_size i = 0; i < data->textures_count; ++i)
1966 {
1967 data->memory.free_func(data->memory.user_data, data->textures[i].name);
1968
1969 cgltf_free_extensions(data, data->textures[i].extensions, data->textures[i].extensions_count);
1970 cgltf_free_extras(data, &data->textures[i].extras);
1971 }
1972
1973 data->memory.free_func(data->memory.user_data, data->textures);
1974
1975 for (cgltf_size i = 0; i < data->samplers_count; ++i)
1976 {
1977 data->memory.free_func(data->memory.user_data, data->samplers[i].name);
1978
1979 cgltf_free_extensions(data, data->samplers[i].extensions, data->samplers[i].extensions_count);
1980 cgltf_free_extras(data, &data->samplers[i].extras);
1981 }
1982
1983 data->memory.free_func(data->memory.user_data, data->samplers);
1984
1985 for (cgltf_size i = 0; i < data->skins_count; ++i)
1986 {
1987 data->memory.free_func(data->memory.user_data, data->skins[i].name);
1988 data->memory.free_func(data->memory.user_data, data->skins[i].joints);
1989
1990 cgltf_free_extensions(data, data->skins[i].extensions, data->skins[i].extensions_count);
1991 cgltf_free_extras(data, &data->skins[i].extras);
1992 }
1993
1994 data->memory.free_func(data->memory.user_data, data->skins);
1995
1996 for (cgltf_size i = 0; i < data->cameras_count; ++i)
1997 {
1998 data->memory.free_func(data->memory.user_data, data->cameras[i].name);
1999
2000 if (data->cameras[i].type == cgltf_camera_type_perspective)
2001 {
2002 cgltf_free_extras(data, &data->cameras[i].data.perspective.extras);
2003 }
2004 else if (data->cameras[i].type == cgltf_camera_type_orthographic)
2005 {
2006 cgltf_free_extras(data, &data->cameras[i].data.orthographic.extras);
2007 }
2008
2009 cgltf_free_extensions(data, data->cameras[i].extensions, data->cameras[i].extensions_count);
2010 cgltf_free_extras(data, &data->cameras[i].extras);
2011 }
2012
2013 data->memory.free_func(data->memory.user_data, data->cameras);
2014
2015 for (cgltf_size i = 0; i < data->lights_count; ++i)
2016 {
2017 data->memory.free_func(data->memory.user_data, data->lights[i].name);
2018
2019 cgltf_free_extras(data, &data->lights[i].extras);
2020 }
2021
2022 data->memory.free_func(data->memory.user_data, data->lights);
2023
2024 for (cgltf_size i = 0; i < data->nodes_count; ++i)
2025 {
2026 data->memory.free_func(data->memory.user_data, data->nodes[i].name);
2027 data->memory.free_func(data->memory.user_data, data->nodes[i].children);
2028 data->memory.free_func(data->memory.user_data, data->nodes[i].weights);
2029
2030 if (data->nodes[i].has_mesh_gpu_instancing)
2031 {
2032 for (cgltf_size j = 0; j < data->nodes[i].mesh_gpu_instancing.attributes_count; ++j)
2033 {
2034 data->memory.free_func(data->memory.user_data, data->nodes[i].mesh_gpu_instancing.attributes[j].name);
2035 }
2036
2037 data->memory.free_func(data->memory.user_data, data->nodes[i].mesh_gpu_instancing.attributes);
2038 }
2039
2040 cgltf_free_extensions(data, data->nodes[i].extensions, data->nodes[i].extensions_count);
2041 cgltf_free_extras(data, &data->nodes[i].extras);
2042 }
2043
2044 data->memory.free_func(data->memory.user_data, data->nodes);
2045
2046 for (cgltf_size i = 0; i < data->scenes_count; ++i)
2047 {
2048 data->memory.free_func(data->memory.user_data, data->scenes[i].name);
2049 data->memory.free_func(data->memory.user_data, data->scenes[i].nodes);
2050
2051 cgltf_free_extensions(data, data->scenes[i].extensions, data->scenes[i].extensions_count);
2052 cgltf_free_extras(data, &data->scenes[i].extras);
2053 }
2054
2055 data->memory.free_func(data->memory.user_data, data->scenes);
2056
2057 for (cgltf_size i = 0; i < data->animations_count; ++i)
2058 {
2059 data->memory.free_func(data->memory.user_data, data->animations[i].name);
2060 for (cgltf_size j = 0; j < data->animations[i].samplers_count; ++j)
2061 {
2062 cgltf_free_extensions(data, data->animations[i].samplers[j].extensions, data->animations[i].samplers[j].extensions_count);
2063 cgltf_free_extras(data, &data->animations[i].samplers[j].extras);
2064 }
2065 data->memory.free_func(data->memory.user_data, data->animations[i].samplers);
2066
2067 for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j)
2068 {
2069 cgltf_free_extensions(data, data->animations[i].channels[j].extensions, data->animations[i].channels[j].extensions_count);
2070 cgltf_free_extras(data, &data->animations[i].channels[j].extras);
2071 }
2072 data->memory.free_func(data->memory.user_data, data->animations[i].channels);
2073
2074 cgltf_free_extensions(data, data->animations[i].extensions, data->animations[i].extensions_count);
2075 cgltf_free_extras(data, &data->animations[i].extras);
2076 }
2077
2078 data->memory.free_func(data->memory.user_data, data->animations);
2079
2080 for (cgltf_size i = 0; i < data->variants_count; ++i)
2081 {
2082 data->memory.free_func(data->memory.user_data, data->variants[i].name);
2083
2084 cgltf_free_extras(data, &data->variants[i].extras);
2085 }
2086
2087 data->memory.free_func(data->memory.user_data, data->variants);
2088
2089 cgltf_free_extensions(data, data->data_extensions, data->data_extensions_count);
2090 cgltf_free_extras(data, &data->extras);
2091
2092 for (cgltf_size i = 0; i < data->extensions_used_count; ++i)
2093 {
2094 data->memory.free_func(data->memory.user_data, data->extensions_used[i]);
2095 }
2096
2097 data->memory.free_func(data->memory.user_data, data->extensions_used);
2098
2099 for (cgltf_size i = 0; i < data->extensions_required_count; ++i)
2100 {
2101 data->memory.free_func(data->memory.user_data, data->extensions_required[i]);
2102 }
2103
2104 data->memory.free_func(data->memory.user_data, data->extensions_required);
2105
2106 file_release(&data->memory, &data->file, data->file_data);
2107
2108 data->memory.free_func(data->memory.user_data, data);
2109 }
2110
2111 void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix)
2112 {
2113 cgltf_float* lm = out_matrix;
2114
2115 if (node->has_matrix)
2116 {
2117 memcpy(lm, node->matrix, sizeof(float) * 16);
2118 }
2119 else
2120 {
2121 float tx = node->translation[0];
2122 float ty = node->translation[1];
2123 float tz = node->translation[2];
2124
2125 float qx = node->rotation[0];
2126 float qy = node->rotation[1];
2127 float qz = node->rotation[2];
2128 float qw = node->rotation[3];
2129
2130 float sx = node->scale[0];
2131 float sy = node->scale[1];
2132 float sz = node->scale[2];
2133
2134 lm[0] = (1 - 2 * qy*qy - 2 * qz*qz) * sx;
2135 lm[1] = (2 * qx*qy + 2 * qz*qw) * sx;
2136 lm[2] = (2 * qx*qz - 2 * qy*qw) * sx;
2137 lm[3] = 0.f;
2138
2139 lm[4] = (2 * qx*qy - 2 * qz*qw) * sy;
2140 lm[5] = (1 - 2 * qx*qx - 2 * qz*qz) * sy;
2141 lm[6] = (2 * qy*qz + 2 * qx*qw) * sy;
2142 lm[7] = 0.f;
2143
2144 lm[8] = (2 * qx*qz + 2 * qy*qw) * sz;
2145 lm[9] = (2 * qy*qz - 2 * qx*qw) * sz;
2146 lm[10] = (1 - 2 * qx*qx - 2 * qy*qy) * sz;
2147 lm[11] = 0.f;
2148
2149 lm[12] = tx;
2150 lm[13] = ty;
2151 lm[14] = tz;
2152 lm[15] = 1.f;
2153 }
2154 }
2155
2156 void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix)
2157 {
2158 cgltf_float* lm = out_matrix;
2159 cgltf_node_transform_local(node, lm);
2160
2161 const cgltf_node* parent = node->parent;
2162
2163 while (parent)
2164 {
2165 float pm[16];
2166 cgltf_node_transform_local(parent, pm);
2167
2168 for (int i = 0; i < 4; ++i)
2169 {
2170 float l0 = lm[i * 4 + 0];
2171 float l1 = lm[i * 4 + 1];
2172 float l2 = lm[i * 4 + 2];
2173
2174 float r0 = l0 * pm[0] + l1 * pm[4] + l2 * pm[8];
2175 float r1 = l0 * pm[1] + l1 * pm[5] + l2 * pm[9];
2176 float r2 = l0 * pm[2] + l1 * pm[6] + l2 * pm[10];
2177
2178 lm[i * 4 + 0] = r0;
2179 lm[i * 4 + 1] = r1;
2180 lm[i * 4 + 2] = r2;
2181 }
2182
2183 lm[12] += pm[12];
2184 lm[13] += pm[13];
2185 lm[14] += pm[14];
2186
2187 parent = parent->parent;
2188 }
2189 }
2190
2191 static cgltf_ssize cgltf_component_read_integer(const void* in, cgltf_component_type component_type)
2192 {
2193 switch (component_type)
2194 {
2195 case cgltf_component_type_r_16:
2196 return *((const int16_t*) in);
2197 case cgltf_component_type_r_16u:
2198 return *((const uint16_t*) in);
2199 case cgltf_component_type_r_32u:
2200 return *((const uint32_t*) in);
2201 case cgltf_component_type_r_32f:
2202 return (cgltf_ssize)*((const float*) in);
2203 case cgltf_component_type_r_8:
2204 return *((const int8_t*) in);
2205 case cgltf_component_type_r_8u:
2206 return *((const uint8_t*) in);
2207 default:
2208 return 0;
2209 }
2210 }
2211
2212 static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_type component_type)
2213 {
2214 switch (component_type)
2215 {
2216 case cgltf_component_type_r_16u:
2217 return *((const uint16_t*) in);
2218 case cgltf_component_type_r_32u:
2219 return *((const uint32_t*) in);
2220 case cgltf_component_type_r_32f:
2221 return (cgltf_size)((cgltf_ssize)*((const float*) in));
2222 case cgltf_component_type_r_8u:
2223 return *((const uint8_t*) in);
2224 default:
2225 return 0;
2226 }
2227 }
2228
2229 static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_type component_type, cgltf_bool normalized)
2230 {
2231 if (component_type == cgltf_component_type_r_32f)
2232 {
2233 return *((const float*) in);
2234 }
2235
2236 if (normalized)
2237 {
2238 switch (component_type)
2239 {
2240 // note: glTF spec doesn't currently define normalized conversions for 32-bit integers
2241 case cgltf_component_type_r_16:
2242 return *((const int16_t*) in) / (cgltf_float)32767;
2243 case cgltf_component_type_r_16u:
2244 return *((const uint16_t*) in) / (cgltf_float)65535;
2245 case cgltf_component_type_r_8:
2246 return *((const int8_t*) in) / (cgltf_float)127;
2247 case cgltf_component_type_r_8u:
2248 return *((const uint8_t*) in) / (cgltf_float)255;
2249 default:
2250 return 0;
2251 }
2252 }
2253
2254 return (cgltf_float)cgltf_component_read_integer(in, component_type);
2255 }
2256
2257 static cgltf_bool cgltf_element_read_float(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_bool normalized, cgltf_float* out, cgltf_size element_size)
2258 {
2259 cgltf_size num_components = cgltf_num_components(type);
2260
2261 if (element_size < num_components) {
2262 return 0;
2263 }
2264
2265 // There are three special cases for component extraction, see #data-alignment in the 2.0 spec.
2266
2267 cgltf_size component_size = cgltf_component_size(component_type);
2268
2269 if (type == cgltf_type_mat2 && component_size == 1)
2270 {
2271 out[0] = cgltf_component_read_float(element, component_type, normalized);
2272 out[1] = cgltf_component_read_float(element + 1, component_type, normalized);
2273 out[2] = cgltf_component_read_float(element + 4, component_type, normalized);
2274 out[3] = cgltf_component_read_float(element + 5, component_type, normalized);
2275 return 1;
2276 }
2277
2278 if (type == cgltf_type_mat3 && component_size == 1)
2279 {
2280 out[0] = cgltf_component_read_float(element, component_type, normalized);
2281 out[1] = cgltf_component_read_float(element + 1, component_type, normalized);
2282 out[2] = cgltf_component_read_float(element + 2, component_type, normalized);
2283 out[3] = cgltf_component_read_float(element + 4, component_type, normalized);
2284 out[4] = cgltf_component_read_float(element + 5, component_type, normalized);
2285 out[5] = cgltf_component_read_float(element + 6, component_type, normalized);
2286 out[6] = cgltf_component_read_float(element + 8, component_type, normalized);
2287 out[7] = cgltf_component_read_float(element + 9, component_type, normalized);
2288 out[8] = cgltf_component_read_float(element + 10, component_type, normalized);
2289 return 1;
2290 }
2291
2292 if (type == cgltf_type_mat3 && component_size == 2)
2293 {
2294 out[0] = cgltf_component_read_float(element, component_type, normalized);
2295 out[1] = cgltf_component_read_float(element + 2, component_type, normalized);
2296 out[2] = cgltf_component_read_float(element + 4, component_type, normalized);
2297 out[3] = cgltf_component_read_float(element + 8, component_type, normalized);
2298 out[4] = cgltf_component_read_float(element + 10, component_type, normalized);
2299 out[5] = cgltf_component_read_float(element + 12, component_type, normalized);
2300 out[6] = cgltf_component_read_float(element + 16, component_type, normalized);
2301 out[7] = cgltf_component_read_float(element + 18, component_type, normalized);
2302 out[8] = cgltf_component_read_float(element + 20, component_type, normalized);
2303 return 1;
2304 }
2305
2306 for (cgltf_size i = 0; i < num_components; ++i)
2307 {
2308 out[i] = cgltf_component_read_float(element + component_size * i, component_type, normalized);
2309 }
2310 return 1;
2311 }
2312
2313 const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view)
2314 {
2315 if (view->data)
2316 return (const uint8_t*)view->data;
2317
2318 if (!view->buffer->data)
2319 return NULL;
2320
2321 const uint8_t* result = (const uint8_t*)view->buffer->data;
2322 result += view->offset;
2323 return result;
2324 }
2325
2326 cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size)
2327 {
2328 if (accessor->is_sparse)
2329 {
2330 return 0;
2331 }
2332 if (accessor->buffer_view == NULL)
2333 {
2334 memset(out, 0, element_size * sizeof(cgltf_float));
2335 return 1;
2336 }
2337 const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
2338 if (element == NULL)
2339 {
2340 return 0;
2341 }
2342 element += accessor->offset + accessor->stride * index;
2343 return cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, out, element_size);
2344 }
2345
2346 cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count)
2347 {
2348 cgltf_size floats_per_element = cgltf_num_components(accessor->type);
2349 cgltf_size available_floats = accessor->count * floats_per_element;
2350 if (out == NULL)
2351 {
2352 return available_floats;
2353 }
2354
2355 float_count = available_floats < float_count ? available_floats : float_count;
2356 cgltf_size element_count = float_count / floats_per_element;
2357
2358 // First pass: convert each element in the base accessor.
2359 cgltf_float* dest = out;
2360 cgltf_accessor dense = *accessor;
2361 dense.is_sparse = 0;
2362 for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element)
2363 {
2364 if (!cgltf_accessor_read_float(&dense, index, dest, floats_per_element))
2365 {
2366 return 0;
2367 }
2368 }
2369
2370 // Second pass: write out each element in the sparse accessor.
2371 if (accessor->is_sparse)
2372 {
2373 const cgltf_accessor_sparse* sparse = &dense.sparse;
2374
2375 const uint8_t* index_data = cgltf_buffer_view_data(sparse->indices_buffer_view);
2376 const uint8_t* reader_head = cgltf_buffer_view_data(sparse->values_buffer_view);
2377
2378 if (index_data == NULL || reader_head == NULL)
2379 {
2380 return 0;
2381 }
2382
2383 index_data += sparse->indices_byte_offset;
2384 reader_head += sparse->values_byte_offset;
2385
2386 cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type);
2387 for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride)
2388 {
2389 size_t writer_index = cgltf_component_read_index(index_data, sparse->indices_component_type);
2390 float* writer_head = out + writer_index * floats_per_element;
2391
2392 if (!cgltf_element_read_float(reader_head, dense.type, dense.component_type, dense.normalized, writer_head, floats_per_element))
2393 {
2394 return 0;
2395 }
2396
2397 reader_head += dense.stride;
2398 }
2399 }
2400
2401 return element_count * floats_per_element;
2402 }
2403
2404 static cgltf_uint cgltf_component_read_uint(const void* in, cgltf_component_type component_type)
2405 {
2406 switch (component_type)
2407 {
2408 case cgltf_component_type_r_8:
2409 return *((const int8_t*) in);
2410
2411 case cgltf_component_type_r_8u:
2412 return *((const uint8_t*) in);
2413
2414 case cgltf_component_type_r_16:
2415 return *((const int16_t*) in);
2416
2417 case cgltf_component_type_r_16u:
2418 return *((const uint16_t*) in);
2419
2420 case cgltf_component_type_r_32u:
2421 return *((const uint32_t*) in);
2422
2423 default:
2424 return 0;
2425 }
2426 }
2427
2428 static cgltf_bool cgltf_element_read_uint(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_uint* out, cgltf_size element_size)
2429 {
2430 cgltf_size num_components = cgltf_num_components(type);
2431
2432 if (element_size < num_components)
2433 {
2434 return 0;
2435 }
2436
2437 // Reading integer matrices is not a valid use case
2438 if (type == cgltf_type_mat2 || type == cgltf_type_mat3 || type == cgltf_type_mat4)
2439 {
2440 return 0;
2441 }
2442
2443 cgltf_size component_size = cgltf_component_size(component_type);
2444
2445 for (cgltf_size i = 0; i < num_components; ++i)
2446 {
2447 out[i] = cgltf_component_read_uint(element + component_size * i, component_type);
2448 }
2449 return 1;
2450 }
2451
2452 cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size)
2453 {
2454 if (accessor->is_sparse)
2455 {
2456 return 0;
2457 }
2458 if (accessor->buffer_view == NULL)
2459 {
2460 memset(out, 0, element_size * sizeof( cgltf_uint ));
2461 return 1;
2462 }
2463 const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
2464 if (element == NULL)
2465 {
2466 return 0;
2467 }
2468 element += accessor->offset + accessor->stride * index;
2469 return cgltf_element_read_uint(element, accessor->type, accessor->component_type, out, element_size);
2470 }
2471
2472 cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index)
2473 {
2474 if (accessor->is_sparse)
2475 {
2476 return 0; // This is an error case, but we can't communicate the error with existing interface.
2477 }
2478 if (accessor->buffer_view == NULL)
2479 {
2480 return 0;
2481 }
2482 const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
2483 if (element == NULL)
2484 {
2485 return 0; // This is an error case, but we can't communicate the error with existing interface.
2486 }
2487 element += accessor->offset + accessor->stride * index;
2488 return cgltf_component_read_index(element, accessor->component_type);
2489 }
2490
2491 #define CGLTF_ERROR_JSON -1
2492 #define CGLTF_ERROR_NOMEM -2
2493 #define CGLTF_ERROR_LEGACY -3
2494
2495 #define CGLTF_CHECK_TOKTYPE(tok_, type_) if ((tok_).type != (type_)) { return CGLTF_ERROR_JSON; }
2496 #define CGLTF_CHECK_TOKTYPE_RETTYPE(tok_, type_, ret_) if ((tok_).type != (type_)) { return (ret_)CGLTF_ERROR_JSON; }
2497 #define CGLTF_CHECK_KEY(tok_) if ((tok_).type != JSMN_STRING || (tok_).size == 0) { return CGLTF_ERROR_JSON; } /* checking size for 0 verifies that a value follows the key */
2498
2499 #define CGLTF_PTRINDEX(type, idx) (type*)((cgltf_size)idx + 1)
2500 #define CGLTF_PTRFIXUP(var, data, size) if (var) { if ((cgltf_size)var > size) { return CGLTF_ERROR_JSON; } var = &data[(cgltf_size)var-1]; }
2501 #define CGLTF_PTRFIXUP_REQ(var, data, size) if (!var || (cgltf_size)var > size) { return CGLTF_ERROR_JSON; } var = &data[(cgltf_size)var-1];
2502
2503 static int cgltf_json_strcmp(jsmntok_t const* tok, const uint8_t* json_chunk, const char* str)
2504 {
2505 CGLTF_CHECK_TOKTYPE(*tok, JSMN_STRING);
2506 size_t const str_len = strlen(str);
2507 size_t const name_length = (size_t)(tok->end - tok->start);
2508 return (str_len == name_length) ? strncmp((const char*)json_chunk + tok->start, str, str_len) : 128;
2509 }
2510
2511 static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk)
2512 {
2513 CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE);
2514 char tmp[128];
2515 int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1);
2516 strncpy(tmp, (const char*)json_chunk + tok->start, size);
2517 tmp[size] = 0;
2518 return CGLTF_ATOI(tmp);
2519 }
2520
2521 static cgltf_size cgltf_json_to_size(jsmntok_t const* tok, const uint8_t* json_chunk)
2522 {
2523 CGLTF_CHECK_TOKTYPE_RETTYPE(*tok, JSMN_PRIMITIVE, cgltf_size);
2524 char tmp[128];
2525 int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1);
2526 strncpy(tmp, (const char*)json_chunk + tok->start, size);
2527 tmp[size] = 0;
2528 return (cgltf_size)CGLTF_ATOLL(tmp);
2529 }
2530
2531 static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json_chunk)
2532 {
2533 CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE);
2534 char tmp[128];
2535 int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1);
2536 strncpy(tmp, (const char*)json_chunk + tok->start, size);
2537 tmp[size] = 0;
2538 return (cgltf_float)CGLTF_ATOF(tmp);
2539 }
2540
2541 static cgltf_bool cgltf_json_to_bool(jsmntok_t const* tok, const uint8_t* json_chunk)
2542 {
2543 int size = (int)(tok->end - tok->start);
2544 return size == 4 && memcmp(json_chunk + tok->start, "true", 4) == 0;
2545 }
2546
2547 static int cgltf_skip_json(jsmntok_t const* tokens, int i)
2548 {
2549 int end = i + 1;
2550
2551 while (i < end)
2552 {
2553 switch (tokens[i].type)
2554 {
2555 case JSMN_OBJECT:
2556 end += tokens[i].size * 2;
2557 break;
2558
2559 case JSMN_ARRAY:
2560 end += tokens[i].size;
2561 break;
2562
2563 case JSMN_PRIMITIVE:
2564 case JSMN_STRING:
2565 break;
2566
2567 default:
2568 return -1;
2569 }
2570
2571 i++;
2572 }
2573
2574 return i;
2575 }
2576
2577 static void cgltf_fill_float_array(float* out_array, int size, float value)
2578 {
2579 for (int j = 0; j < size; ++j)
2580 {
2581 out_array[j] = value;
2582 }
2583 }
2584
2585 static int cgltf_parse_json_float_array(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, float* out_array, int size)
2586 {
2587 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY);
2588 if (tokens[i].size != size)
2589 {
2590 return CGLTF_ERROR_JSON;
2591 }
2592 ++i;
2593 for (int j = 0; j < size; ++j)
2594 {
2595 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
2596 out_array[j] = cgltf_json_to_float(tokens + i, json_chunk);
2597 ++i;
2598 }
2599 return i;
2600 }
2601
2602 static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, char** out_string)
2603 {
2604 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_STRING);
2605 if (*out_string)
2606 {
2607 return CGLTF_ERROR_JSON;
2608 }
2609 int size = (int)(tokens[i].end - tokens[i].start);
2610 char* result = (char*)options->memory.alloc_func(options->memory.user_data, size + 1);
2611 if (!result)
2612 {
2613 return CGLTF_ERROR_NOMEM;
2614 }
2615 strncpy(result, (const char*)json_chunk + tokens[i].start, size);
2616 result[size] = 0;
2617 *out_string = result;
2618 return i + 1;
2619 }
2620
2621 static int cgltf_parse_json_array(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, size_t element_size, void** out_array, cgltf_size* out_size)
2622 {
2623 (void)json_chunk;
2624 if (tokens[i].type != JSMN_ARRAY)
2625 {
2626 return tokens[i].type == JSMN_OBJECT ? CGLTF_ERROR_LEGACY : CGLTF_ERROR_JSON;
2627 }
2628 if (*out_array)
2629 {
2630 return CGLTF_ERROR_JSON;
2631 }
2632 int size = tokens[i].size;
2633 void* result = cgltf_calloc(options, element_size, size);
2634 if (!result)
2635 {
2636 return CGLTF_ERROR_NOMEM;
2637 }
2638 *out_array = result;
2639 *out_size = size;
2640 return i + 1;
2641 }
2642
2643 static int cgltf_parse_json_string_array(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, char*** out_array, cgltf_size* out_size)
2644 {
2645 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY);
2646 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(char*), (void**)out_array, out_size);
2647 if (i < 0)
2648 {
2649 return i;
2650 }
2651
2652 for (cgltf_size j = 0; j < *out_size; ++j)
2653 {
2654 i = cgltf_parse_json_string(options, tokens, i, json_chunk, j + (*out_array));
2655 if (i < 0)
2656 {
2657 return i;
2658 }
2659 }
2660 return i;
2661 }
2662
2663 static void cgltf_parse_attribute_type(const char* name, cgltf_attribute_type* out_type, int* out_index)
2664 {
2665 if (*name == '_')
2666 {
2667 *out_type = cgltf_attribute_type_custom;
2668 return;
2669 }
2670
2671 const char* us = strchr(name, '_');
2672 size_t len = us ? (size_t)(us - name) : strlen(name);
2673
2674 if (len == 8 && strncmp(name, "POSITION", 8) == 0)
2675 {
2676 *out_type = cgltf_attribute_type_position;
2677 }
2678 else if (len == 6 && strncmp(name, "NORMAL", 6) == 0)
2679 {
2680 *out_type = cgltf_attribute_type_normal;
2681 }
2682 else if (len == 7 && strncmp(name, "TANGENT", 7) == 0)
2683 {
2684 *out_type = cgltf_attribute_type_tangent;
2685 }
2686 else if (len == 8 && strncmp(name, "TEXCOORD", 8) == 0)
2687 {
2688 *out_type = cgltf_attribute_type_texcoord;
2689 }
2690 else if (len == 5 && strncmp(name, "COLOR", 5) == 0)
2691 {
2692 *out_type = cgltf_attribute_type_color;
2693 }
2694 else if (len == 6 && strncmp(name, "JOINTS", 6) == 0)
2695 {
2696 *out_type = cgltf_attribute_type_joints;
2697 }
2698 else if (len == 7 && strncmp(name, "WEIGHTS", 7) == 0)
2699 {
2700 *out_type = cgltf_attribute_type_weights;
2701 }
2702 else
2703 {
2704 *out_type = cgltf_attribute_type_invalid;
2705 }
2706
2707 if (us && *out_type != cgltf_attribute_type_invalid)
2708 {
2709 *out_index = CGLTF_ATOI(us + 1);
2710 }
2711 }
2712
2713 static int cgltf_parse_json_attribute_list(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_attribute** out_attributes, cgltf_size* out_attributes_count)
2714 {
2715 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
2716
2717 if (*out_attributes)
2718 {
2719 return CGLTF_ERROR_JSON;
2720 }
2721
2722 *out_attributes_count = tokens[i].size;
2723 *out_attributes = (cgltf_attribute*)cgltf_calloc(options, sizeof(cgltf_attribute), *out_attributes_count);
2724 ++i;
2725
2726 if (!*out_attributes)
2727 {
2728 return CGLTF_ERROR_NOMEM;
2729 }
2730
2731 for (cgltf_size j = 0; j < *out_attributes_count; ++j)
2732 {
2733 CGLTF_CHECK_KEY(tokens[i]);
2734
2735 i = cgltf_parse_json_string(options, tokens, i, json_chunk, &(*out_attributes)[j].name);
2736 if (i < 0)
2737 {
2738 return CGLTF_ERROR_JSON;
2739 }
2740
2741 cgltf_parse_attribute_type((*out_attributes)[j].name, &(*out_attributes)[j].type, &(*out_attributes)[j].index);
2742
2743 (*out_attributes)[j].data = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk));
2744 ++i;
2745 }
2746
2747 return i;
2748 }
2749
2750 static int cgltf_parse_json_extras(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extras* out_extras)
2751 {
2752 if (out_extras->data)
2753 {
2754 return CGLTF_ERROR_JSON;
2755 }
2756
2757 /* fill deprecated fields for now, this will be removed in the future */
2758 out_extras->start_offset = tokens[i].start;
2759 out_extras->end_offset = tokens[i].end;
2760
2761 size_t start = tokens[i].start;
2762 size_t size = tokens[i].end - start;
2763 out_extras->data = (char*)options->memory.alloc_func(options->memory.user_data, size + 1);
2764 if (!out_extras->data)
2765 {
2766 return CGLTF_ERROR_NOMEM;
2767 }
2768 strncpy(out_extras->data, (const char*)json_chunk + start, size);
2769 out_extras->data[size] = '\0';
2770
2771 i = cgltf_skip_json(tokens, i);
2772 return i;
2773 }
2774
2775 static int cgltf_parse_json_unprocessed_extension(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extension* out_extension)
2776 {
2777 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_STRING);
2778 CGLTF_CHECK_TOKTYPE(tokens[i+1], JSMN_OBJECT);
2779 if (out_extension->name)
2780 {
2781 return CGLTF_ERROR_JSON;
2782 }
2783
2784 cgltf_size name_length = tokens[i].end - tokens[i].start;
2785 out_extension->name = (char*)options->memory.alloc_func(options->memory.user_data, name_length + 1);
2786 if (!out_extension->name)
2787 {
2788 return CGLTF_ERROR_NOMEM;
2789 }
2790 strncpy(out_extension->name, (const char*)json_chunk + tokens[i].start, name_length);
2791 out_extension->name[name_length] = 0;
2792 i++;
2793
2794 size_t start = tokens[i].start;
2795 size_t size = tokens[i].end - start;
2796 out_extension->data = (char*)options->memory.alloc_func(options->memory.user_data, size + 1);
2797 if (!out_extension->data)
2798 {
2799 return CGLTF_ERROR_NOMEM;
2800 }
2801 strncpy(out_extension->data, (const char*)json_chunk + start, size);
2802 out_extension->data[size] = '\0';
2803
2804 i = cgltf_skip_json(tokens, i);
2805
2806 return i;
2807 }
2808
2809 static int cgltf_parse_json_unprocessed_extensions(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_size* out_extensions_count, cgltf_extension** out_extensions)
2810 {
2811 ++i;
2812
2813 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
2814 if(*out_extensions)
2815 {
2816 return CGLTF_ERROR_JSON;
2817 }
2818
2819 int extensions_size = tokens[i].size;
2820 *out_extensions_count = 0;
2821 *out_extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
2822
2823 if (!*out_extensions)
2824 {
2825 return CGLTF_ERROR_NOMEM;
2826 }
2827
2828 ++i;
2829
2830 for (int j = 0; j < extensions_size; ++j)
2831 {
2832 CGLTF_CHECK_KEY(tokens[i]);
2833
2834 cgltf_size extension_index = (*out_extensions_count)++;
2835 cgltf_extension* extension = &((*out_extensions)[extension_index]);
2836 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, extension);
2837
2838 if (i < 0)
2839 {
2840 return i;
2841 }
2842 }
2843 return i;
2844 }
2845
2846 static int cgltf_parse_json_draco_mesh_compression(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_draco_mesh_compression* out_draco_mesh_compression)
2847 {
2848 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
2849
2850 int size = tokens[i].size;
2851 ++i;
2852
2853 for (int j = 0; j < size; ++j)
2854 {
2855 CGLTF_CHECK_KEY(tokens[i]);
2856
2857 if (cgltf_json_strcmp(tokens + i, json_chunk, "attributes") == 0)
2858 {
2859 i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_draco_mesh_compression->attributes, &out_draco_mesh_compression->attributes_count);
2860 }
2861 else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferView") == 0)
2862 {
2863 ++i;
2864 out_draco_mesh_compression->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
2865 ++i;
2866 }
2867
2868 if (i < 0)
2869 {
2870 return i;
2871 }
2872 }
2873
2874 return i;
2875 }
2876
2877 static int cgltf_parse_json_mesh_gpu_instancing(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_mesh_gpu_instancing* out_mesh_gpu_instancing)
2878 {
2879 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
2880
2881 int size = tokens[i].size;
2882 ++i;
2883
2884 for (int j = 0; j < size; ++j)
2885 {
2886 CGLTF_CHECK_KEY(tokens[i]);
2887
2888 if (cgltf_json_strcmp(tokens + i, json_chunk, "attributes") == 0)
2889 {
2890 i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_mesh_gpu_instancing->attributes, &out_mesh_gpu_instancing->attributes_count);
2891 }
2892 else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferView") == 0)
2893 {
2894 ++i;
2895 out_mesh_gpu_instancing->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
2896 ++i;
2897 }
2898
2899 if (i < 0)
2900 {
2901 return i;
2902 }
2903 }
2904
2905 return i;
2906 }
2907
2908 static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_material_mapping* out_mappings, cgltf_size* offset)
2909 {
2910 (void)options;
2911 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY);
2912
2913 int size = tokens[i].size;
2914 ++i;
2915
2916 for (int j = 0; j < size; ++j)
2917 {
2918 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
2919
2920 int obj_size = tokens[i].size;
2921 ++i;
2922
2923 int material = -1;
2924 int variants_tok = -1;
2925 int extras_tok = -1;
2926
2927 for (int k = 0; k < obj_size; ++k)
2928 {
2929 CGLTF_CHECK_KEY(tokens[i]);
2930
2931 if (cgltf_json_strcmp(tokens + i, json_chunk, "material") == 0)
2932 {
2933 ++i;
2934 material = cgltf_json_to_int(tokens + i, json_chunk);
2935 ++i;
2936 }
2937 else if (cgltf_json_strcmp(tokens + i, json_chunk, "variants") == 0)
2938 {
2939 variants_tok = i+1;
2940 CGLTF_CHECK_TOKTYPE(tokens[variants_tok], JSMN_ARRAY);
2941
2942 i = cgltf_skip_json(tokens, i+1);
2943 }
2944 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
2945 {
2946 extras_tok = i + 1;
2947 i = cgltf_skip_json(tokens, extras_tok);
2948 }
2949 else
2950 {
2951 i = cgltf_skip_json(tokens, i+1);
2952 }
2953
2954 if (i < 0)
2955 {
2956 return i;
2957 }
2958 }
2959
2960 if (material < 0 || variants_tok < 0)
2961 {
2962 return CGLTF_ERROR_JSON;
2963 }
2964
2965 if (out_mappings)
2966 {
2967 for (int k = 0; k < tokens[variants_tok].size; ++k)
2968 {
2969 int variant = cgltf_json_to_int(&tokens[variants_tok + 1 + k], json_chunk);
2970 if (variant < 0)
2971 return variant;
2972
2973 out_mappings[*offset].material = CGLTF_PTRINDEX(cgltf_material, material);
2974 out_mappings[*offset].variant = variant;
2975
2976 if (extras_tok >= 0)
2977 {
2978 int e = cgltf_parse_json_extras(options, tokens, extras_tok, json_chunk, &out_mappings[*offset].extras);
2979 if (e < 0)
2980 return e;
2981 }
2982
2983 (*offset)++;
2984 }
2985 }
2986 else
2987 {
2988 (*offset) += tokens[variants_tok].size;
2989 }
2990 }
2991
2992 return i;
2993 }
2994
2995 static int cgltf_parse_json_material_mappings(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_primitive* out_prim)
2996 {
2997 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
2998
2999 int size = tokens[i].size;
3000 ++i;
3001
3002 for (int j = 0; j < size; ++j)
3003 {
3004 CGLTF_CHECK_KEY(tokens[i]);
3005
3006 if (cgltf_json_strcmp(tokens + i, json_chunk, "mappings") == 0)
3007 {
3008 if (out_prim->mappings)
3009 {
3010 return CGLTF_ERROR_JSON;
3011 }
3012
3013 cgltf_size mappings_offset = 0;
3014 int k = cgltf_parse_json_material_mapping_data(options, tokens, i + 1, json_chunk, NULL, &mappings_offset);
3015 if (k < 0)
3016 {
3017 return k;
3018 }
3019
3020 out_prim->mappings_count = mappings_offset;
3021 out_prim->mappings = (cgltf_material_mapping*)cgltf_calloc(options, sizeof(cgltf_material_mapping), out_prim->mappings_count);
3022
3023 mappings_offset = 0;
3024 i = cgltf_parse_json_material_mapping_data(options, tokens, i + 1, json_chunk, out_prim->mappings, &mappings_offset);
3025 }
3026 else
3027 {
3028 i = cgltf_skip_json(tokens, i+1);
3029 }
3030
3031 if (i < 0)
3032 {
3033 return i;
3034 }
3035 }
3036
3037 return i;
3038 }
3039
3040 static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_primitive* out_prim)
3041 {
3042 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3043
3044 out_prim->type = cgltf_primitive_type_triangles;
3045
3046 int size = tokens[i].size;
3047 ++i;
3048
3049 for (int j = 0; j < size; ++j)
3050 {
3051 CGLTF_CHECK_KEY(tokens[i]);
3052
3053 if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0)
3054 {
3055 ++i;
3056 out_prim->type
3057 = (cgltf_primitive_type)
3058 cgltf_json_to_int(tokens+i, json_chunk);
3059 ++i;
3060 }
3061 else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0)
3062 {
3063 ++i;
3064 out_prim->indices = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk));
3065 ++i;
3066 }
3067 else if (cgltf_json_strcmp(tokens+i, json_chunk, "material") == 0)
3068 {
3069 ++i;
3070 out_prim->material = CGLTF_PTRINDEX(cgltf_material, cgltf_json_to_int(tokens + i, json_chunk));
3071 ++i;
3072 }
3073 else if (cgltf_json_strcmp(tokens+i, json_chunk, "attributes") == 0)
3074 {
3075 i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_prim->attributes, &out_prim->attributes_count);
3076 }
3077 else if (cgltf_json_strcmp(tokens+i, json_chunk, "targets") == 0)
3078 {
3079 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_morph_target), (void**)&out_prim->targets, &out_prim->targets_count);
3080 if (i < 0)
3081 {
3082 return i;
3083 }
3084
3085 for (cgltf_size k = 0; k < out_prim->targets_count; ++k)
3086 {
3087 i = cgltf_parse_json_attribute_list(options, tokens, i, json_chunk, &out_prim->targets[k].attributes, &out_prim->targets[k].attributes_count);
3088 if (i < 0)
3089 {
3090 return i;
3091 }
3092 }
3093 }
3094 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
3095 {
3096 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_prim->extras);
3097 }
3098 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
3099 {
3100 ++i;
3101
3102 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3103 if(out_prim->extensions)
3104 {
3105 return CGLTF_ERROR_JSON;
3106 }
3107
3108 int extensions_size = tokens[i].size;
3109 out_prim->extensions_count = 0;
3110 out_prim->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
3111
3112 if (!out_prim->extensions)
3113 {
3114 return CGLTF_ERROR_NOMEM;
3115 }
3116
3117 ++i;
3118 for (int k = 0; k < extensions_size; ++k)
3119 {
3120 CGLTF_CHECK_KEY(tokens[i]);
3121
3122 if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_draco_mesh_compression") == 0)
3123 {
3124 out_prim->has_draco_mesh_compression = 1;
3125 i = cgltf_parse_json_draco_mesh_compression(options, tokens, i + 1, json_chunk, &out_prim->draco_mesh_compression);
3126 }
3127 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_variants") == 0)
3128 {
3129 i = cgltf_parse_json_material_mappings(options, tokens, i + 1, json_chunk, out_prim);
3130 }
3131 else
3132 {
3133 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_prim->extensions[out_prim->extensions_count++]));
3134 }
3135
3136 if (i < 0)
3137 {
3138 return i;
3139 }
3140 }
3141 }
3142 else
3143 {
3144 i = cgltf_skip_json(tokens, i+1);
3145 }
3146
3147 if (i < 0)
3148 {
3149 return i;
3150 }
3151 }
3152
3153 return i;
3154 }
3155
3156 static int cgltf_parse_json_mesh(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_mesh* out_mesh)
3157 {
3158 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3159
3160 int size = tokens[i].size;
3161 ++i;
3162
3163 for (int j = 0; j < size; ++j)
3164 {
3165 CGLTF_CHECK_KEY(tokens[i]);
3166
3167 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
3168 {
3169 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_mesh->name);
3170 }
3171 else if (cgltf_json_strcmp(tokens+i, json_chunk, "primitives") == 0)
3172 {
3173 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_primitive), (void**)&out_mesh->primitives, &out_mesh->primitives_count);
3174 if (i < 0)
3175 {
3176 return i;
3177 }
3178
3179 for (cgltf_size prim_index = 0; prim_index < out_mesh->primitives_count; ++prim_index)
3180 {
3181 i = cgltf_parse_json_primitive(options, tokens, i, json_chunk, &out_mesh->primitives[prim_index]);
3182 if (i < 0)
3183 {
3184 return i;
3185 }
3186 }
3187 }
3188 else if (cgltf_json_strcmp(tokens + i, json_chunk, "weights") == 0)
3189 {
3190 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_float), (void**)&out_mesh->weights, &out_mesh->weights_count);
3191 if (i < 0)
3192 {
3193 return i;
3194 }
3195
3196 i = cgltf_parse_json_float_array(tokens, i - 1, json_chunk, out_mesh->weights, (int)out_mesh->weights_count);
3197 }
3198 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
3199 {
3200 ++i;
3201
3202 out_mesh->extras.start_offset = tokens[i].start;
3203 out_mesh->extras.end_offset = tokens[i].end;
3204
3205 if (tokens[i].type == JSMN_OBJECT)
3206 {
3207 int extras_size = tokens[i].size;
3208 ++i;
3209
3210 for (int k = 0; k < extras_size; ++k)
3211 {
3212 CGLTF_CHECK_KEY(tokens[i]);
3213
3214 if (cgltf_json_strcmp(tokens+i, json_chunk, "targetNames") == 0 && tokens[i+1].type == JSMN_ARRAY)
3215 {
3216 i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_mesh->target_names, &out_mesh->target_names_count);
3217 }
3218 else
3219 {
3220 i = cgltf_skip_json(tokens, i+1);
3221 }
3222
3223 if (i < 0)
3224 {
3225 return i;
3226 }
3227 }
3228 }
3229 else
3230 {
3231 i = cgltf_skip_json(tokens, i);
3232 }
3233 }
3234 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
3235 {
3236 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_mesh->extensions_count, &out_mesh->extensions);
3237 }
3238 else
3239 {
3240 i = cgltf_skip_json(tokens, i+1);
3241 }
3242
3243 if (i < 0)
3244 {
3245 return i;
3246 }
3247 }
3248
3249 return i;
3250 }
3251
3252 static int cgltf_parse_json_meshes(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
3253 {
3254 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_mesh), (void**)&out_data->meshes, &out_data->meshes_count);
3255 if (i < 0)
3256 {
3257 return i;
3258 }
3259
3260 for (cgltf_size j = 0; j < out_data->meshes_count; ++j)
3261 {
3262 i = cgltf_parse_json_mesh(options, tokens, i, json_chunk, &out_data->meshes[j]);
3263 if (i < 0)
3264 {
3265 return i;
3266 }
3267 }
3268 return i;
3269 }
3270
3271 static cgltf_component_type cgltf_json_to_component_type(jsmntok_t const* tok, const uint8_t* json_chunk)
3272 {
3273 int type = cgltf_json_to_int(tok, json_chunk);
3274
3275 switch (type)
3276 {
3277 case 5120:
3278 return cgltf_component_type_r_8;
3279 case 5121:
3280 return cgltf_component_type_r_8u;
3281 case 5122:
3282 return cgltf_component_type_r_16;
3283 case 5123:
3284 return cgltf_component_type_r_16u;
3285 case 5125:
3286 return cgltf_component_type_r_32u;
3287 case 5126:
3288 return cgltf_component_type_r_32f;
3289 default:
3290 return cgltf_component_type_invalid;
3291 }
3292 }
3293
3294 static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor_sparse* out_sparse)
3295 {
3296 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3297
3298 int size = tokens[i].size;
3299 ++i;
3300
3301 for (int j = 0; j < size; ++j)
3302 {
3303 CGLTF_CHECK_KEY(tokens[i]);
3304
3305 if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0)
3306 {
3307 ++i;
3308 out_sparse->count = cgltf_json_to_int(tokens + i, json_chunk);
3309 ++i;
3310 }
3311 else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0)
3312 {
3313 ++i;
3314 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3315
3316 int indices_size = tokens[i].size;
3317 ++i;
3318
3319 for (int k = 0; k < indices_size; ++k)
3320 {
3321 CGLTF_CHECK_KEY(tokens[i]);
3322
3323 if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0)
3324 {
3325 ++i;
3326 out_sparse->indices_buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
3327 ++i;
3328 }
3329 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
3330 {
3331 ++i;
3332 out_sparse->indices_byte_offset = cgltf_json_to_size(tokens + i, json_chunk);
3333 ++i;
3334 }
3335 else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0)
3336 {
3337 ++i;
3338 out_sparse->indices_component_type = cgltf_json_to_component_type(tokens + i, json_chunk);
3339 ++i;
3340 }
3341 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
3342 {
3343 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->indices_extras);
3344 }
3345 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
3346 {
3347 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->indices_extensions_count, &out_sparse->indices_extensions);
3348 }
3349 else
3350 {
3351 i = cgltf_skip_json(tokens, i+1);
3352 }
3353
3354 if (i < 0)
3355 {
3356 return i;
3357 }
3358 }
3359 }
3360 else if (cgltf_json_strcmp(tokens+i, json_chunk, "values") == 0)
3361 {
3362 ++i;
3363 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3364
3365 int values_size = tokens[i].size;
3366 ++i;
3367
3368 for (int k = 0; k < values_size; ++k)
3369 {
3370 CGLTF_CHECK_KEY(tokens[i]);
3371
3372 if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0)
3373 {
3374 ++i;
3375 out_sparse->values_buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
3376 ++i;
3377 }
3378 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
3379 {
3380 ++i;
3381 out_sparse->values_byte_offset = cgltf_json_to_size(tokens + i, json_chunk);
3382 ++i;
3383 }
3384 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
3385 {
3386 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->values_extras);
3387 }
3388 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
3389 {
3390 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->values_extensions_count, &out_sparse->values_extensions);
3391 }
3392 else
3393 {
3394 i = cgltf_skip_json(tokens, i+1);
3395 }
3396
3397 if (i < 0)
3398 {
3399 return i;
3400 }
3401 }
3402 }
3403 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
3404 {
3405 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->extras);
3406 }
3407 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
3408 {
3409 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->extensions_count, &out_sparse->extensions);
3410 }
3411 else
3412 {
3413 i = cgltf_skip_json(tokens, i+1);
3414 }
3415
3416 if (i < 0)
3417 {
3418 return i;
3419 }
3420 }
3421
3422 return i;
3423 }
3424
3425 static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor* out_accessor)
3426 {
3427 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3428
3429 int size = tokens[i].size;
3430 ++i;
3431
3432 for (int j = 0; j < size; ++j)
3433 {
3434 CGLTF_CHECK_KEY(tokens[i]);
3435
3436 if (cgltf_json_strcmp(tokens + i, json_chunk, "name") == 0)
3437 {
3438 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_accessor->name);
3439 }
3440 else if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0)
3441 {
3442 ++i;
3443 out_accessor->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
3444 ++i;
3445 }
3446 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
3447 {
3448 ++i;
3449 out_accessor->offset =
3450 cgltf_json_to_size(tokens+i, json_chunk);
3451 ++i;
3452 }
3453 else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0)
3454 {
3455 ++i;
3456 out_accessor->component_type = cgltf_json_to_component_type(tokens + i, json_chunk);
3457 ++i;
3458 }
3459 else if (cgltf_json_strcmp(tokens+i, json_chunk, "normalized") == 0)
3460 {
3461 ++i;
3462 out_accessor->normalized = cgltf_json_to_bool(tokens+i, json_chunk);
3463 ++i;
3464 }
3465 else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0)
3466 {
3467 ++i;
3468 out_accessor->count =
3469 cgltf_json_to_int(tokens+i, json_chunk);
3470 ++i;
3471 }
3472 else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0)
3473 {
3474 ++i;
3475 if (cgltf_json_strcmp(tokens+i, json_chunk, "SCALAR") == 0)
3476 {
3477 out_accessor->type = cgltf_type_scalar;
3478 }
3479 else if (cgltf_json_strcmp(tokens+i, json_chunk, "VEC2") == 0)
3480 {
3481 out_accessor->type = cgltf_type_vec2;
3482 }
3483 else if (cgltf_json_strcmp(tokens+i, json_chunk, "VEC3") == 0)
3484 {
3485 out_accessor->type = cgltf_type_vec3;
3486 }
3487 else if (cgltf_json_strcmp(tokens+i, json_chunk, "VEC4") == 0)
3488 {
3489 out_accessor->type = cgltf_type_vec4;
3490 }
3491 else if (cgltf_json_strcmp(tokens+i, json_chunk, "MAT2") == 0)
3492 {
3493 out_accessor->type = cgltf_type_mat2;
3494 }
3495 else if (cgltf_json_strcmp(tokens+i, json_chunk, "MAT3") == 0)
3496 {
3497 out_accessor->type = cgltf_type_mat3;
3498 }
3499 else if (cgltf_json_strcmp(tokens+i, json_chunk, "MAT4") == 0)
3500 {
3501 out_accessor->type = cgltf_type_mat4;
3502 }
3503 ++i;
3504 }
3505 else if (cgltf_json_strcmp(tokens + i, json_chunk, "min") == 0)
3506 {
3507 ++i;
3508 out_accessor->has_min = 1;
3509 // note: we can't parse the precise number of elements since type may not have been computed yet
3510 int min_size = tokens[i].size > 16 ? 16 : tokens[i].size;
3511 i = cgltf_parse_json_float_array(tokens, i, json_chunk, out_accessor->min, min_size);
3512 }
3513 else if (cgltf_json_strcmp(tokens + i, json_chunk, "max") == 0)
3514 {
3515 ++i;
3516 out_accessor->has_max = 1;
3517 // note: we can't parse the precise number of elements since type may not have been computed yet
3518 int max_size = tokens[i].size > 16 ? 16 : tokens[i].size;
3519 i = cgltf_parse_json_float_array(tokens, i, json_chunk, out_accessor->max, max_size);
3520 }
3521 else if (cgltf_json_strcmp(tokens + i, json_chunk, "sparse") == 0)
3522 {
3523 out_accessor->is_sparse = 1;
3524 i = cgltf_parse_json_accessor_sparse(options, tokens, i + 1, json_chunk, &out_accessor->sparse);
3525 }
3526 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
3527 {
3528 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_accessor->extras);
3529 }
3530 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
3531 {
3532 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_accessor->extensions_count, &out_accessor->extensions);
3533 }
3534 else
3535 {
3536 i = cgltf_skip_json(tokens, i+1);
3537 }
3538
3539 if (i < 0)
3540 {
3541 return i;
3542 }
3543 }
3544
3545 return i;
3546 }
3547
3548 static int cgltf_parse_json_texture_transform(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture_transform* out_texture_transform)
3549 {
3550 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3551
3552 int size = tokens[i].size;
3553 ++i;
3554
3555 for (int j = 0; j < size; ++j)
3556 {
3557 CGLTF_CHECK_KEY(tokens[i]);
3558
3559 if (cgltf_json_strcmp(tokens + i, json_chunk, "offset") == 0)
3560 {
3561 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_texture_transform->offset, 2);
3562 }
3563 else if (cgltf_json_strcmp(tokens + i, json_chunk, "rotation") == 0)
3564 {
3565 ++i;
3566 out_texture_transform->rotation = cgltf_json_to_float(tokens + i, json_chunk);
3567 ++i;
3568 }
3569 else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0)
3570 {
3571 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_texture_transform->scale, 2);
3572 }
3573 else if (cgltf_json_strcmp(tokens + i, json_chunk, "texCoord") == 0)
3574 {
3575 ++i;
3576 out_texture_transform->has_texcoord = 1;
3577 out_texture_transform->texcoord = cgltf_json_to_int(tokens + i, json_chunk);
3578 ++i;
3579 }
3580 else
3581 {
3582 i = cgltf_skip_json(tokens, i + 1);
3583 }
3584
3585 if (i < 0)
3586 {
3587 return i;
3588 }
3589 }
3590
3591 return i;
3592 }
3593
3594 static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture_view* out_texture_view)
3595 {
3596 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3597
3598 out_texture_view->scale = 1.0f;
3599 cgltf_fill_float_array(out_texture_view->transform.scale, 2, 1.0f);
3600
3601 int size = tokens[i].size;
3602 ++i;
3603
3604 for (int j = 0; j < size; ++j)
3605 {
3606 CGLTF_CHECK_KEY(tokens[i]);
3607
3608 if (cgltf_json_strcmp(tokens + i, json_chunk, "index") == 0)
3609 {
3610 ++i;
3611 out_texture_view->texture = CGLTF_PTRINDEX(cgltf_texture, cgltf_json_to_int(tokens + i, json_chunk));
3612 ++i;
3613 }
3614 else if (cgltf_json_strcmp(tokens + i, json_chunk, "texCoord") == 0)
3615 {
3616 ++i;
3617 out_texture_view->texcoord = cgltf_json_to_int(tokens + i, json_chunk);
3618 ++i;
3619 }
3620 else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0)
3621 {
3622 ++i;
3623 out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk);
3624 ++i;
3625 }
3626 else if (cgltf_json_strcmp(tokens + i, json_chunk, "strength") == 0)
3627 {
3628 ++i;
3629 out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk);
3630 ++i;
3631 }
3632 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
3633 {
3634 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_texture_view->extras);
3635 }
3636 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
3637 {
3638 ++i;
3639
3640 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3641 if(out_texture_view->extensions)
3642 {
3643 return CGLTF_ERROR_JSON;
3644 }
3645
3646 int extensions_size = tokens[i].size;
3647 out_texture_view->extensions_count = 0;
3648 out_texture_view->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
3649
3650 if (!out_texture_view->extensions)
3651 {
3652 return CGLTF_ERROR_NOMEM;
3653 }
3654
3655 ++i;
3656
3657 for (int k = 0; k < extensions_size; ++k)
3658 {
3659 CGLTF_CHECK_KEY(tokens[i]);
3660
3661 if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_texture_transform") == 0)
3662 {
3663 out_texture_view->has_transform = 1;
3664 i = cgltf_parse_json_texture_transform(tokens, i + 1, json_chunk, &out_texture_view->transform);
3665 }
3666 else
3667 {
3668 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_texture_view->extensions[out_texture_view->extensions_count++]));
3669 }
3670
3671 if (i < 0)
3672 {
3673 return i;
3674 }
3675 }
3676 }
3677 else
3678 {
3679 i = cgltf_skip_json(tokens, i + 1);
3680 }
3681
3682 if (i < 0)
3683 {
3684 return i;
3685 }
3686 }
3687
3688 return i;
3689 }
3690
3691 static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_pbr_metallic_roughness* out_pbr)
3692 {
3693 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3694
3695 int size = tokens[i].size;
3696 ++i;
3697
3698 for (int j = 0; j < size; ++j)
3699 {
3700 CGLTF_CHECK_KEY(tokens[i]);
3701
3702 if (cgltf_json_strcmp(tokens+i, json_chunk, "metallicFactor") == 0)
3703 {
3704 ++i;
3705 out_pbr->metallic_factor =
3706 cgltf_json_to_float(tokens + i, json_chunk);
3707 ++i;
3708 }
3709 else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0)
3710 {
3711 ++i;
3712 out_pbr->roughness_factor =
3713 cgltf_json_to_float(tokens+i, json_chunk);
3714 ++i;
3715 }
3716 else if (cgltf_json_strcmp(tokens+i, json_chunk, "baseColorFactor") == 0)
3717 {
3718 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->base_color_factor, 4);
3719 }
3720 else if (cgltf_json_strcmp(tokens+i, json_chunk, "baseColorTexture") == 0)
3721 {
3722 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk,
3723 &out_pbr->base_color_texture);
3724 }
3725 else if (cgltf_json_strcmp(tokens + i, json_chunk, "metallicRoughnessTexture") == 0)
3726 {
3727 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk,
3728 &out_pbr->metallic_roughness_texture);
3729 }
3730 else
3731 {
3732 i = cgltf_skip_json(tokens, i+1);
3733 }
3734
3735 if (i < 0)
3736 {
3737 return i;
3738 }
3739 }
3740
3741 return i;
3742 }
3743
3744 static int cgltf_parse_json_pbr_specular_glossiness(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_pbr_specular_glossiness* out_pbr)
3745 {
3746 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3747 int size = tokens[i].size;
3748 ++i;
3749
3750 for (int j = 0; j < size; ++j)
3751 {
3752 CGLTF_CHECK_KEY(tokens[i]);
3753
3754 if (cgltf_json_strcmp(tokens+i, json_chunk, "diffuseFactor") == 0)
3755 {
3756 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->diffuse_factor, 4);
3757 }
3758 else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularFactor") == 0)
3759 {
3760 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->specular_factor, 3);
3761 }
3762 else if (cgltf_json_strcmp(tokens+i, json_chunk, "glossinessFactor") == 0)
3763 {
3764 ++i;
3765 out_pbr->glossiness_factor = cgltf_json_to_float(tokens + i, json_chunk);
3766 ++i;
3767 }
3768 else if (cgltf_json_strcmp(tokens+i, json_chunk, "diffuseTexture") == 0)
3769 {
3770 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->diffuse_texture);
3771 }
3772 else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularGlossinessTexture") == 0)
3773 {
3774 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->specular_glossiness_texture);
3775 }
3776 else
3777 {
3778 i = cgltf_skip_json(tokens, i+1);
3779 }
3780
3781 if (i < 0)
3782 {
3783 return i;
3784 }
3785 }
3786
3787 return i;
3788 }
3789
3790 static int cgltf_parse_json_clearcoat(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_clearcoat* out_clearcoat)
3791 {
3792 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3793 int size = tokens[i].size;
3794 ++i;
3795
3796 for (int j = 0; j < size; ++j)
3797 {
3798 CGLTF_CHECK_KEY(tokens[i]);
3799
3800 if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatFactor") == 0)
3801 {
3802 ++i;
3803 out_clearcoat->clearcoat_factor = cgltf_json_to_float(tokens + i, json_chunk);
3804 ++i;
3805 }
3806 else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatRoughnessFactor") == 0)
3807 {
3808 ++i;
3809 out_clearcoat->clearcoat_roughness_factor = cgltf_json_to_float(tokens + i, json_chunk);
3810 ++i;
3811 }
3812 else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatTexture") == 0)
3813 {
3814 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_clearcoat->clearcoat_texture);
3815 }
3816 else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatRoughnessTexture") == 0)
3817 {
3818 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_clearcoat->clearcoat_roughness_texture);
3819 }
3820 else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatNormalTexture") == 0)
3821 {
3822 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_clearcoat->clearcoat_normal_texture);
3823 }
3824 else
3825 {
3826 i = cgltf_skip_json(tokens, i+1);
3827 }
3828
3829 if (i < 0)
3830 {
3831 return i;
3832 }
3833 }
3834
3835 return i;
3836 }
3837
3838 static int cgltf_parse_json_ior(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_ior* out_ior)
3839 {
3840 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3841 int size = tokens[i].size;
3842 ++i;
3843
3844 // Default values
3845 out_ior->ior = 1.5f;
3846
3847 for (int j = 0; j < size; ++j)
3848 {
3849 CGLTF_CHECK_KEY(tokens[i]);
3850
3851 if (cgltf_json_strcmp(tokens+i, json_chunk, "ior") == 0)
3852 {
3853 ++i;
3854 out_ior->ior = cgltf_json_to_float(tokens + i, json_chunk);
3855 ++i;
3856 }
3857 else
3858 {
3859 i = cgltf_skip_json(tokens, i+1);
3860 }
3861
3862 if (i < 0)
3863 {
3864 return i;
3865 }
3866 }
3867
3868 return i;
3869 }
3870
3871 static int cgltf_parse_json_specular(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_specular* out_specular)
3872 {
3873 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3874 int size = tokens[i].size;
3875 ++i;
3876
3877 // Default values
3878 out_specular->specular_factor = 1.0f;
3879 cgltf_fill_float_array(out_specular->specular_color_factor, 3, 1.0f);
3880
3881 for (int j = 0; j < size; ++j)
3882 {
3883 CGLTF_CHECK_KEY(tokens[i]);
3884
3885 if (cgltf_json_strcmp(tokens+i, json_chunk, "specularFactor") == 0)
3886 {
3887 ++i;
3888 out_specular->specular_factor = cgltf_json_to_float(tokens + i, json_chunk);
3889 ++i;
3890 }
3891 else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularColorFactor") == 0)
3892 {
3893 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_specular->specular_color_factor, 3);
3894 }
3895 else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularTexture") == 0)
3896 {
3897 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_specular->specular_texture);
3898 }
3899 else if (cgltf_json_strcmp(tokens + i, json_chunk, "specularColorTexture") == 0)
3900 {
3901 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_specular->specular_color_texture);
3902 }
3903 else
3904 {
3905 i = cgltf_skip_json(tokens, i+1);
3906 }
3907
3908 if (i < 0)
3909 {
3910 return i;
3911 }
3912 }
3913
3914 return i;
3915 }
3916
3917 static int cgltf_parse_json_transmission(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_transmission* out_transmission)
3918 {
3919 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3920 int size = tokens[i].size;
3921 ++i;
3922
3923 for (int j = 0; j < size; ++j)
3924 {
3925 CGLTF_CHECK_KEY(tokens[i]);
3926
3927 if (cgltf_json_strcmp(tokens+i, json_chunk, "transmissionFactor") == 0)
3928 {
3929 ++i;
3930 out_transmission->transmission_factor = cgltf_json_to_float(tokens + i, json_chunk);
3931 ++i;
3932 }
3933 else if (cgltf_json_strcmp(tokens+i, json_chunk, "transmissionTexture") == 0)
3934 {
3935 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_transmission->transmission_texture);
3936 }
3937 else
3938 {
3939 i = cgltf_skip_json(tokens, i+1);
3940 }
3941
3942 if (i < 0)
3943 {
3944 return i;
3945 }
3946 }
3947
3948 return i;
3949 }
3950
3951 static int cgltf_parse_json_volume(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_volume* out_volume)
3952 {
3953 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3954 int size = tokens[i].size;
3955 ++i;
3956
3957 for (int j = 0; j < size; ++j)
3958 {
3959 CGLTF_CHECK_KEY(tokens[i]);
3960
3961 if (cgltf_json_strcmp(tokens + i, json_chunk, "thicknessFactor") == 0)
3962 {
3963 ++i;
3964 out_volume->thickness_factor = cgltf_json_to_float(tokens + i, json_chunk);
3965 ++i;
3966 }
3967 else if (cgltf_json_strcmp(tokens + i, json_chunk, "thicknessTexture") == 0)
3968 {
3969 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_volume->thickness_texture);
3970 }
3971 else if (cgltf_json_strcmp(tokens + i, json_chunk, "attenuationColor") == 0)
3972 {
3973 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_volume->attenuation_color, 3);
3974 }
3975 else if (cgltf_json_strcmp(tokens + i, json_chunk, "attenuationDistance") == 0)
3976 {
3977 ++i;
3978 out_volume->attenuation_distance = cgltf_json_to_float(tokens + i, json_chunk);
3979 ++i;
3980 }
3981 else
3982 {
3983 i = cgltf_skip_json(tokens, i + 1);
3984 }
3985
3986 if (i < 0)
3987 {
3988 return i;
3989 }
3990 }
3991
3992 return i;
3993 }
3994
3995 static int cgltf_parse_json_sheen(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_sheen* out_sheen)
3996 {
3997 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3998 int size = tokens[i].size;
3999 ++i;
4000
4001 for (int j = 0; j < size; ++j)
4002 {
4003 CGLTF_CHECK_KEY(tokens[i]);
4004
4005 if (cgltf_json_strcmp(tokens+i, json_chunk, "sheenColorFactor") == 0)
4006 {
4007 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_sheen->sheen_color_factor, 3);
4008 }
4009 else if (cgltf_json_strcmp(tokens+i, json_chunk, "sheenColorTexture") == 0)
4010 {
4011 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_sheen->sheen_color_texture);
4012 }
4013 else if (cgltf_json_strcmp(tokens+i, json_chunk, "sheenRoughnessFactor") == 0)
4014 {
4015 ++i;
4016 out_sheen->sheen_roughness_factor = cgltf_json_to_float(tokens + i, json_chunk);
4017 ++i;
4018 }
4019 else if (cgltf_json_strcmp(tokens+i, json_chunk, "sheenRoughnessTexture") == 0)
4020 {
4021 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_sheen->sheen_roughness_texture);
4022 }
4023 else
4024 {
4025 i = cgltf_skip_json(tokens, i+1);
4026 }
4027
4028 if (i < 0)
4029 {
4030 return i;
4031 }
4032 }
4033
4034 return i;
4035 }
4036
4037 static int cgltf_parse_json_emissive_strength(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_emissive_strength* out_emissive_strength)
4038 {
4039 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4040 int size = tokens[i].size;
4041 ++i;
4042
4043 // Default
4044 out_emissive_strength->emissive_strength = 1.f;
4045
4046 for (int j = 0; j < size; ++j)
4047 {
4048 CGLTF_CHECK_KEY(tokens[i]);
4049
4050 if (cgltf_json_strcmp(tokens + i, json_chunk, "emissiveStrength") == 0)
4051 {
4052 ++i;
4053 out_emissive_strength->emissive_strength = cgltf_json_to_float(tokens + i, json_chunk);
4054 ++i;
4055 }
4056 else
4057 {
4058 i = cgltf_skip_json(tokens, i + 1);
4059 }
4060
4061 if (i < 0)
4062 {
4063 return i;
4064 }
4065 }
4066
4067 return i;
4068 }
4069
4070 static int cgltf_parse_json_iridescence(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_iridescence* out_iridescence)
4071 {
4072 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4073 int size = tokens[i].size;
4074 ++i;
4075
4076 // Default
4077 out_iridescence->iridescence_ior = 1.3f;
4078 out_iridescence->iridescence_thickness_min = 100.f;
4079 out_iridescence->iridescence_thickness_max = 400.f;
4080
4081 for (int j = 0; j < size; ++j)
4082 {
4083 CGLTF_CHECK_KEY(tokens[i]);
4084
4085 if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceFactor") == 0)
4086 {
4087 ++i;
4088 out_iridescence->iridescence_factor = cgltf_json_to_float(tokens + i, json_chunk);
4089 ++i;
4090 }
4091 else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceTexture") == 0)
4092 {
4093 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_iridescence->iridescence_texture);
4094 }
4095 else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceIor") == 0)
4096 {
4097 ++i;
4098 out_iridescence->iridescence_ior = cgltf_json_to_float(tokens + i, json_chunk);
4099 ++i;
4100 }
4101 else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceThicknessMinimum") == 0)
4102 {
4103 ++i;
4104 out_iridescence->iridescence_thickness_min = cgltf_json_to_float(tokens + i, json_chunk);
4105 ++i;
4106 }
4107 else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceThicknessMaximum") == 0)
4108 {
4109 ++i;
4110 out_iridescence->iridescence_thickness_max = cgltf_json_to_float(tokens + i, json_chunk);
4111 ++i;
4112 }
4113 else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceThicknessTexture") == 0)
4114 {
4115 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_iridescence->iridescence_thickness_texture);
4116 }
4117 else
4118 {
4119 i = cgltf_skip_json(tokens, i + 1);
4120 }
4121
4122 if (i < 0)
4123 {
4124 return i;
4125 }
4126 }
4127
4128 return i;
4129 }
4130
4131 static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_image* out_image)
4132 {
4133 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4134
4135 int size = tokens[i].size;
4136 ++i;
4137
4138 for (int j = 0; j < size; ++j)
4139 {
4140 CGLTF_CHECK_KEY(tokens[i]);
4141
4142 if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0)
4143 {
4144 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->uri);
4145 }
4146 else if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0)
4147 {
4148 ++i;
4149 out_image->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
4150 ++i;
4151 }
4152 else if (cgltf_json_strcmp(tokens + i, json_chunk, "mimeType") == 0)
4153 {
4154 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->mime_type);
4155 }
4156 else if (cgltf_json_strcmp(tokens + i, json_chunk, "name") == 0)
4157 {
4158 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->name);
4159 }
4160 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
4161 {
4162 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_image->extras);
4163 }
4164 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
4165 {
4166 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_image->extensions_count, &out_image->extensions);
4167 }
4168 else
4169 {
4170 i = cgltf_skip_json(tokens, i + 1);
4171 }
4172
4173 if (i < 0)
4174 {
4175 return i;
4176 }
4177 }
4178
4179 return i;
4180 }
4181
4182 static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_sampler* out_sampler)
4183 {
4184 (void)options;
4185 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4186
4187 out_sampler->wrap_s = 10497;
4188 out_sampler->wrap_t = 10497;
4189
4190 int size = tokens[i].size;
4191 ++i;
4192
4193 for (int j = 0; j < size; ++j)
4194 {
4195 CGLTF_CHECK_KEY(tokens[i]);
4196
4197 if (cgltf_json_strcmp(tokens + i, json_chunk, "name") == 0)
4198 {
4199 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_sampler->name);
4200 }
4201 else if (cgltf_json_strcmp(tokens + i, json_chunk, "magFilter") == 0)
4202 {
4203 ++i;
4204 out_sampler->mag_filter
4205 = cgltf_json_to_int(tokens + i, json_chunk);
4206 ++i;
4207 }
4208 else if (cgltf_json_strcmp(tokens + i, json_chunk, "minFilter") == 0)
4209 {
4210 ++i;
4211 out_sampler->min_filter
4212 = cgltf_json_to_int(tokens + i, json_chunk);
4213 ++i;
4214 }
4215 else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapS") == 0)
4216 {
4217 ++i;
4218 out_sampler->wrap_s
4219 = cgltf_json_to_int(tokens + i, json_chunk);
4220 ++i;
4221 }
4222 else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0)
4223 {
4224 ++i;
4225 out_sampler->wrap_t
4226 = cgltf_json_to_int(tokens + i, json_chunk);
4227 ++i;
4228 }
4229 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
4230 {
4231 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sampler->extras);
4232 }
4233 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
4234 {
4235 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sampler->extensions_count, &out_sampler->extensions);
4236 }
4237 else
4238 {
4239 i = cgltf_skip_json(tokens, i + 1);
4240 }
4241
4242 if (i < 0)
4243 {
4244 return i;
4245 }
4246 }
4247
4248 return i;
4249 }
4250
4251 static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture* out_texture)
4252 {
4253 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4254
4255 int size = tokens[i].size;
4256 ++i;
4257
4258 for (int j = 0; j < size; ++j)
4259 {
4260 CGLTF_CHECK_KEY(tokens[i]);
4261
4262 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
4263 {
4264 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_texture->name);
4265 }
4266 else if (cgltf_json_strcmp(tokens + i, json_chunk, "sampler") == 0)
4267 {
4268 ++i;
4269 out_texture->sampler = CGLTF_PTRINDEX(cgltf_sampler, cgltf_json_to_int(tokens + i, json_chunk));
4270 ++i;
4271 }
4272 else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
4273 {
4274 ++i;
4275 out_texture->image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk));
4276 ++i;
4277 }
4278 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
4279 {
4280 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_texture->extras);
4281 }
4282 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
4283 {
4284 ++i;
4285
4286 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4287 if (out_texture->extensions)
4288 {
4289 return CGLTF_ERROR_JSON;
4290 }
4291
4292 int extensions_size = tokens[i].size;
4293 ++i;
4294 out_texture->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
4295 out_texture->extensions_count = 0;
4296
4297 if (!out_texture->extensions)
4298 {
4299 return CGLTF_ERROR_NOMEM;
4300 }
4301
4302 for (int k = 0; k < extensions_size; ++k)
4303 {
4304 CGLTF_CHECK_KEY(tokens[i]);
4305
4306 if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_texture_basisu") == 0)
4307 {
4308 out_texture->has_basisu = 1;
4309 ++i;
4310 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4311 int num_properties = tokens[i].size;
4312 ++i;
4313
4314 for (int t = 0; t < num_properties; ++t)
4315 {
4316 CGLTF_CHECK_KEY(tokens[i]);
4317
4318 if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
4319 {
4320 ++i;
4321 out_texture->basisu_image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk));
4322 ++i;
4323 }
4324 else
4325 {
4326 i = cgltf_skip_json(tokens, i + 1);
4327 }
4328 if (i < 0)
4329 {
4330 return i;
4331 }
4332 }
4333 }
4334 else
4335 {
4336 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_texture->extensions[out_texture->extensions_count++]));
4337 }
4338
4339 if (i < 0)
4340 {
4341 return i;
4342 }
4343 }
4344 }
4345 else
4346 {
4347 i = cgltf_skip_json(tokens, i + 1);
4348 }
4349
4350 if (i < 0)
4351 {
4352 return i;
4353 }
4354 }
4355
4356 return i;
4357 }
4358
4359 static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_material* out_material)
4360 {
4361 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4362
4363 cgltf_fill_float_array(out_material->pbr_metallic_roughness.base_color_factor, 4, 1.0f);
4364 out_material->pbr_metallic_roughness.metallic_factor = 1.0f;
4365 out_material->pbr_metallic_roughness.roughness_factor = 1.0f;
4366
4367 cgltf_fill_float_array(out_material->pbr_specular_glossiness.diffuse_factor, 4, 1.0f);
4368 cgltf_fill_float_array(out_material->pbr_specular_glossiness.specular_factor, 3, 1.0f);
4369 out_material->pbr_specular_glossiness.glossiness_factor = 1.0f;
4370
4371 cgltf_fill_float_array(out_material->volume.attenuation_color, 3, 1.0f);
4372 out_material->volume.attenuation_distance = FLT_MAX;
4373
4374 out_material->alpha_cutoff = 0.5f;
4375
4376 int size = tokens[i].size;
4377 ++i;
4378
4379 for (int j = 0; j < size; ++j)
4380 {
4381 CGLTF_CHECK_KEY(tokens[i]);
4382
4383 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
4384 {
4385 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_material->name);
4386 }
4387 else if (cgltf_json_strcmp(tokens+i, json_chunk, "pbrMetallicRoughness") == 0)
4388 {
4389 out_material->has_pbr_metallic_roughness = 1;
4390 i = cgltf_parse_json_pbr_metallic_roughness(options, tokens, i + 1, json_chunk, &out_material->pbr_metallic_roughness);
4391 }
4392 else if (cgltf_json_strcmp(tokens+i, json_chunk, "emissiveFactor") == 0)
4393 {
4394 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_material->emissive_factor, 3);
4395 }
4396 else if (cgltf_json_strcmp(tokens + i, json_chunk, "normalTexture") == 0)
4397 {
4398 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk,
4399 &out_material->normal_texture);
4400 }
4401 else if (cgltf_json_strcmp(tokens + i, json_chunk, "occlusionTexture") == 0)
4402 {
4403 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk,
4404 &out_material->occlusion_texture);
4405 }
4406 else if (cgltf_json_strcmp(tokens + i, json_chunk, "emissiveTexture") == 0)
4407 {
4408 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk,
4409 &out_material->emissive_texture);
4410 }
4411 else if (cgltf_json_strcmp(tokens + i, json_chunk, "alphaMode") == 0)
4412 {
4413 ++i;
4414 if (cgltf_json_strcmp(tokens + i, json_chunk, "OPAQUE") == 0)
4415 {
4416 out_material->alpha_mode = cgltf_alpha_mode_opaque;
4417 }
4418 else if (cgltf_json_strcmp(tokens + i, json_chunk, "MASK") == 0)
4419 {
4420 out_material->alpha_mode = cgltf_alpha_mode_mask;
4421 }
4422 else if (cgltf_json_strcmp(tokens + i, json_chunk, "BLEND") == 0)
4423 {
4424 out_material->alpha_mode = cgltf_alpha_mode_blend;
4425 }
4426 ++i;
4427 }
4428 else if (cgltf_json_strcmp(tokens + i, json_chunk, "alphaCutoff") == 0)
4429 {
4430 ++i;
4431 out_material->alpha_cutoff = cgltf_json_to_float(tokens + i, json_chunk);
4432 ++i;
4433 }
4434 else if (cgltf_json_strcmp(tokens + i, json_chunk, "doubleSided") == 0)
4435 {
4436 ++i;
4437 out_material->double_sided =
4438 cgltf_json_to_bool(tokens + i, json_chunk);
4439 ++i;
4440 }
4441 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
4442 {
4443 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_material->extras);
4444 }
4445 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
4446 {
4447 ++i;
4448
4449 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4450 if(out_material->extensions)
4451 {
4452 return CGLTF_ERROR_JSON;
4453 }
4454
4455 int extensions_size = tokens[i].size;
4456 ++i;
4457 out_material->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
4458 out_material->extensions_count= 0;
4459
4460 if (!out_material->extensions)
4461 {
4462 return CGLTF_ERROR_NOMEM;
4463 }
4464
4465 for (int k = 0; k < extensions_size; ++k)
4466 {
4467 CGLTF_CHECK_KEY(tokens[i]);
4468
4469 if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_pbrSpecularGlossiness") == 0)
4470 {
4471 out_material->has_pbr_specular_glossiness = 1;
4472 i = cgltf_parse_json_pbr_specular_glossiness(options, tokens, i + 1, json_chunk, &out_material->pbr_specular_glossiness);
4473 }
4474 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_unlit") == 0)
4475 {
4476 out_material->unlit = 1;
4477 i = cgltf_skip_json(tokens, i+1);
4478 }
4479 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_clearcoat") == 0)
4480 {
4481 out_material->has_clearcoat = 1;
4482 i = cgltf_parse_json_clearcoat(options, tokens, i + 1, json_chunk, &out_material->clearcoat);
4483 }
4484 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_ior") == 0)
4485 {
4486 out_material->has_ior = 1;
4487 i = cgltf_parse_json_ior(tokens, i + 1, json_chunk, &out_material->ior);
4488 }
4489 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_specular") == 0)
4490 {
4491 out_material->has_specular = 1;
4492 i = cgltf_parse_json_specular(options, tokens, i + 1, json_chunk, &out_material->specular);
4493 }
4494 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_transmission") == 0)
4495 {
4496 out_material->has_transmission = 1;
4497 i = cgltf_parse_json_transmission(options, tokens, i + 1, json_chunk, &out_material->transmission);
4498 }
4499 else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_volume") == 0)
4500 {
4501 out_material->has_volume = 1;
4502 i = cgltf_parse_json_volume(options, tokens, i + 1, json_chunk, &out_material->volume);
4503 }
4504 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_sheen") == 0)
4505 {
4506 out_material->has_sheen = 1;
4507 i = cgltf_parse_json_sheen(options, tokens, i + 1, json_chunk, &out_material->sheen);
4508 }
4509 else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_emissive_strength") == 0)
4510 {
4511 out_material->has_emissive_strength = 1;
4512 i = cgltf_parse_json_emissive_strength(tokens, i + 1, json_chunk, &out_material->emissive_strength);
4513 }
4514 else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_iridescence") == 0)
4515 {
4516 out_material->has_iridescence = 1;
4517 i = cgltf_parse_json_iridescence(options, tokens, i + 1, json_chunk, &out_material->iridescence);
4518 }
4519 else
4520 {
4521 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_material->extensions[out_material->extensions_count++]));
4522 }
4523
4524 if (i < 0)
4525 {
4526 return i;
4527 }
4528 }
4529 }
4530 else
4531 {
4532 i = cgltf_skip_json(tokens, i+1);
4533 }
4534
4535 if (i < 0)
4536 {
4537 return i;
4538 }
4539 }
4540
4541 return i;
4542 }
4543
4544 static int cgltf_parse_json_accessors(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4545 {
4546 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_accessor), (void**)&out_data->accessors, &out_data->accessors_count);
4547 if (i < 0)
4548 {
4549 return i;
4550 }
4551
4552 for (cgltf_size j = 0; j < out_data->accessors_count; ++j)
4553 {
4554 i = cgltf_parse_json_accessor(options, tokens, i, json_chunk, &out_data->accessors[j]);
4555 if (i < 0)
4556 {
4557 return i;
4558 }
4559 }
4560 return i;
4561 }
4562
4563 static int cgltf_parse_json_materials(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4564 {
4565 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_material), (void**)&out_data->materials, &out_data->materials_count);
4566 if (i < 0)
4567 {
4568 return i;
4569 }
4570
4571 for (cgltf_size j = 0; j < out_data->materials_count; ++j)
4572 {
4573 i = cgltf_parse_json_material(options, tokens, i, json_chunk, &out_data->materials[j]);
4574 if (i < 0)
4575 {
4576 return i;
4577 }
4578 }
4579 return i;
4580 }
4581
4582 static int cgltf_parse_json_images(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4583 {
4584 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_image), (void**)&out_data->images, &out_data->images_count);
4585 if (i < 0)
4586 {
4587 return i;
4588 }
4589
4590 for (cgltf_size j = 0; j < out_data->images_count; ++j)
4591 {
4592 i = cgltf_parse_json_image(options, tokens, i, json_chunk, &out_data->images[j]);
4593 if (i < 0)
4594 {
4595 return i;
4596 }
4597 }
4598 return i;
4599 }
4600
4601 static int cgltf_parse_json_textures(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4602 {
4603 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_texture), (void**)&out_data->textures, &out_data->textures_count);
4604 if (i < 0)
4605 {
4606 return i;
4607 }
4608
4609 for (cgltf_size j = 0; j < out_data->textures_count; ++j)
4610 {
4611 i = cgltf_parse_json_texture(options, tokens, i, json_chunk, &out_data->textures[j]);
4612 if (i < 0)
4613 {
4614 return i;
4615 }
4616 }
4617 return i;
4618 }
4619
4620 static int cgltf_parse_json_samplers(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4621 {
4622 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_sampler), (void**)&out_data->samplers, &out_data->samplers_count);
4623 if (i < 0)
4624 {
4625 return i;
4626 }
4627
4628 for (cgltf_size j = 0; j < out_data->samplers_count; ++j)
4629 {
4630 i = cgltf_parse_json_sampler(options, tokens, i, json_chunk, &out_data->samplers[j]);
4631 if (i < 0)
4632 {
4633 return i;
4634 }
4635 }
4636 return i;
4637 }
4638
4639 static int cgltf_parse_json_meshopt_compression(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_meshopt_compression* out_meshopt_compression)
4640 {
4641 (void)options;
4642 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4643
4644 int size = tokens[i].size;
4645 ++i;
4646
4647 for (int j = 0; j < size; ++j)
4648 {
4649 CGLTF_CHECK_KEY(tokens[i]);
4650
4651 if (cgltf_json_strcmp(tokens+i, json_chunk, "buffer") == 0)
4652 {
4653 ++i;
4654 out_meshopt_compression->buffer = CGLTF_PTRINDEX(cgltf_buffer, cgltf_json_to_int(tokens + i, json_chunk));
4655 ++i;
4656 }
4657 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
4658 {
4659 ++i;
4660 out_meshopt_compression->offset = cgltf_json_to_size(tokens+i, json_chunk);
4661 ++i;
4662 }
4663 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0)
4664 {
4665 ++i;
4666 out_meshopt_compression->size = cgltf_json_to_size(tokens+i, json_chunk);
4667 ++i;
4668 }
4669 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteStride") == 0)
4670 {
4671 ++i;
4672 out_meshopt_compression->stride = cgltf_json_to_size(tokens+i, json_chunk);
4673 ++i;
4674 }
4675 else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0)
4676 {
4677 ++i;
4678 out_meshopt_compression->count = cgltf_json_to_int(tokens+i, json_chunk);
4679 ++i;
4680 }
4681 else if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0)
4682 {
4683 ++i;
4684 if (cgltf_json_strcmp(tokens+i, json_chunk, "ATTRIBUTES") == 0)
4685 {
4686 out_meshopt_compression->mode = cgltf_meshopt_compression_mode_attributes;
4687 }
4688 else if (cgltf_json_strcmp(tokens+i, json_chunk, "TRIANGLES") == 0)
4689 {
4690 out_meshopt_compression->mode = cgltf_meshopt_compression_mode_triangles;
4691 }
4692 else if (cgltf_json_strcmp(tokens+i, json_chunk, "INDICES") == 0)
4693 {
4694 out_meshopt_compression->mode = cgltf_meshopt_compression_mode_indices;
4695 }
4696 ++i;
4697 }
4698 else if (cgltf_json_strcmp(tokens+i, json_chunk, "filter") == 0)
4699 {
4700 ++i;
4701 if (cgltf_json_strcmp(tokens+i, json_chunk, "NONE") == 0)
4702 {
4703 out_meshopt_compression->filter = cgltf_meshopt_compression_filter_none;
4704 }
4705 else if (cgltf_json_strcmp(tokens+i, json_chunk, "OCTAHEDRAL") == 0)
4706 {
4707 out_meshopt_compression->filter = cgltf_meshopt_compression_filter_octahedral;
4708 }
4709 else if (cgltf_json_strcmp(tokens+i, json_chunk, "QUATERNION") == 0)
4710 {
4711 out_meshopt_compression->filter = cgltf_meshopt_compression_filter_quaternion;
4712 }
4713 else if (cgltf_json_strcmp(tokens+i, json_chunk, "EXPONENTIAL") == 0)
4714 {
4715 out_meshopt_compression->filter = cgltf_meshopt_compression_filter_exponential;
4716 }
4717 ++i;
4718 }
4719 else
4720 {
4721 i = cgltf_skip_json(tokens, i+1);
4722 }
4723
4724 if (i < 0)
4725 {
4726 return i;
4727 }
4728 }
4729
4730 return i;
4731 }
4732
4733 static int cgltf_parse_json_buffer_view(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_buffer_view* out_buffer_view)
4734 {
4735 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4736
4737 int size = tokens[i].size;
4738 ++i;
4739
4740 for (int j = 0; j < size; ++j)
4741 {
4742 CGLTF_CHECK_KEY(tokens[i]);
4743
4744 if (cgltf_json_strcmp(tokens + i, json_chunk, "name") == 0)
4745 {
4746 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_buffer_view->name);
4747 }
4748 else if (cgltf_json_strcmp(tokens+i, json_chunk, "buffer") == 0)
4749 {
4750 ++i;
4751 out_buffer_view->buffer = CGLTF_PTRINDEX(cgltf_buffer, cgltf_json_to_int(tokens + i, json_chunk));
4752 ++i;
4753 }
4754 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
4755 {
4756 ++i;
4757 out_buffer_view->offset =
4758 cgltf_json_to_size(tokens+i, json_chunk);
4759 ++i;
4760 }
4761 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0)
4762 {
4763 ++i;
4764 out_buffer_view->size =
4765 cgltf_json_to_size(tokens+i, json_chunk);
4766 ++i;
4767 }
4768 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteStride") == 0)
4769 {
4770 ++i;
4771 out_buffer_view->stride =
4772 cgltf_json_to_size(tokens+i, json_chunk);
4773 ++i;
4774 }
4775 else if (cgltf_json_strcmp(tokens+i, json_chunk, "target") == 0)
4776 {
4777 ++i;
4778 int type = cgltf_json_to_int(tokens+i, json_chunk);
4779 switch (type)
4780 {
4781 case 34962:
4782 type = cgltf_buffer_view_type_vertices;
4783 break;
4784 case 34963:
4785 type = cgltf_buffer_view_type_indices;
4786 break;
4787 default:
4788 type = cgltf_buffer_view_type_invalid;
4789 break;
4790 }
4791 out_buffer_view->type = (cgltf_buffer_view_type)type;
4792 ++i;
4793 }
4794 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
4795 {
4796 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_buffer_view->extras);
4797 }
4798 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
4799 {
4800 ++i;
4801
4802 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4803 if(out_buffer_view->extensions)
4804 {
4805 return CGLTF_ERROR_JSON;
4806 }
4807
4808 int extensions_size = tokens[i].size;
4809 out_buffer_view->extensions_count = 0;
4810 out_buffer_view->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
4811
4812 if (!out_buffer_view->extensions)
4813 {
4814 return CGLTF_ERROR_NOMEM;
4815 }
4816
4817 ++i;
4818 for (int k = 0; k < extensions_size; ++k)
4819 {
4820 CGLTF_CHECK_KEY(tokens[i]);
4821
4822 if (cgltf_json_strcmp(tokens+i, json_chunk, "EXT_meshopt_compression") == 0)
4823 {
4824 out_buffer_view->has_meshopt_compression = 1;
4825 i = cgltf_parse_json_meshopt_compression(options, tokens, i + 1, json_chunk, &out_buffer_view->meshopt_compression);
4826 }
4827 else
4828 {
4829 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_buffer_view->extensions[out_buffer_view->extensions_count++]));
4830 }
4831
4832 if (i < 0)
4833 {
4834 return i;
4835 }
4836 }
4837 }
4838 else
4839 {
4840 i = cgltf_skip_json(tokens, i+1);
4841 }
4842
4843 if (i < 0)
4844 {
4845 return i;
4846 }
4847 }
4848
4849 return i;
4850 }
4851
4852 static int cgltf_parse_json_buffer_views(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4853 {
4854 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_buffer_view), (void**)&out_data->buffer_views, &out_data->buffer_views_count);
4855 if (i < 0)
4856 {
4857 return i;
4858 }
4859
4860 for (cgltf_size j = 0; j < out_data->buffer_views_count; ++j)
4861 {
4862 i = cgltf_parse_json_buffer_view(options, tokens, i, json_chunk, &out_data->buffer_views[j]);
4863 if (i < 0)
4864 {
4865 return i;
4866 }
4867 }
4868 return i;
4869 }
4870
4871 static int cgltf_parse_json_buffer(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_buffer* out_buffer)
4872 {
4873 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4874
4875 int size = tokens[i].size;
4876 ++i;
4877
4878 for (int j = 0; j < size; ++j)
4879 {
4880 CGLTF_CHECK_KEY(tokens[i]);
4881
4882 if (cgltf_json_strcmp(tokens + i, json_chunk, "name") == 0)
4883 {
4884 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_buffer->name);
4885 }
4886 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0)
4887 {
4888 ++i;
4889 out_buffer->size =
4890 cgltf_json_to_size(tokens+i, json_chunk);
4891 ++i;
4892 }
4893 else if (cgltf_json_strcmp(tokens+i, json_chunk, "uri") == 0)
4894 {
4895 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_buffer->uri);
4896 }
4897 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
4898 {
4899 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_buffer->extras);
4900 }
4901 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
4902 {
4903 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_buffer->extensions_count, &out_buffer->extensions);
4904 }
4905 else
4906 {
4907 i = cgltf_skip_json(tokens, i+1);
4908 }
4909
4910 if (i < 0)
4911 {
4912 return i;
4913 }
4914 }
4915
4916 return i;
4917 }
4918
4919 static int cgltf_parse_json_buffers(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4920 {
4921 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_buffer), (void**)&out_data->buffers, &out_data->buffers_count);
4922 if (i < 0)
4923 {
4924 return i;
4925 }
4926
4927 for (cgltf_size j = 0; j < out_data->buffers_count; ++j)
4928 {
4929 i = cgltf_parse_json_buffer(options, tokens, i, json_chunk, &out_data->buffers[j]);
4930 if (i < 0)
4931 {
4932 return i;
4933 }
4934 }
4935 return i;
4936 }
4937
4938 static int cgltf_parse_json_skin(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_skin* out_skin)
4939 {
4940 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4941
4942 int size = tokens[i].size;
4943 ++i;
4944
4945 for (int j = 0; j < size; ++j)
4946 {
4947 CGLTF_CHECK_KEY(tokens[i]);
4948
4949 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
4950 {
4951 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_skin->name);
4952 }
4953 else if (cgltf_json_strcmp(tokens+i, json_chunk, "joints") == 0)
4954 {
4955 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_node*), (void**)&out_skin->joints, &out_skin->joints_count);
4956 if (i < 0)
4957 {
4958 return i;
4959 }
4960
4961 for (cgltf_size k = 0; k < out_skin->joints_count; ++k)
4962 {
4963 out_skin->joints[k] = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk));
4964 ++i;
4965 }
4966 }
4967 else if (cgltf_json_strcmp(tokens+i, json_chunk, "skeleton") == 0)
4968 {
4969 ++i;
4970 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
4971 out_skin->skeleton = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk));
4972 ++i;
4973 }
4974 else if (cgltf_json_strcmp(tokens+i, json_chunk, "inverseBindMatrices") == 0)
4975 {
4976 ++i;
4977 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
4978 out_skin->inverse_bind_matrices = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk));
4979 ++i;
4980 }
4981 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
4982 {
4983 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_skin->extras);
4984 }
4985 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
4986 {
4987 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_skin->extensions_count, &out_skin->extensions);
4988 }
4989 else
4990 {
4991 i = cgltf_skip_json(tokens, i+1);
4992 }
4993
4994 if (i < 0)
4995 {
4996 return i;
4997 }
4998 }
4999
5000 return i;
5001 }
5002
5003 static int cgltf_parse_json_skins(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5004 {
5005 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_skin), (void**)&out_data->skins, &out_data->skins_count);
5006 if (i < 0)
5007 {
5008 return i;
5009 }
5010
5011 for (cgltf_size j = 0; j < out_data->skins_count; ++j)
5012 {
5013 i = cgltf_parse_json_skin(options, tokens, i, json_chunk, &out_data->skins[j]);
5014 if (i < 0)
5015 {
5016 return i;
5017 }
5018 }
5019 return i;
5020 }
5021
5022 static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_camera* out_camera)
5023 {
5024 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5025
5026 int size = tokens[i].size;
5027 ++i;
5028
5029 for (int j = 0; j < size; ++j)
5030 {
5031 CGLTF_CHECK_KEY(tokens[i]);
5032
5033 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
5034 {
5035 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_camera->name);
5036 }
5037 else if (cgltf_json_strcmp(tokens+i, json_chunk, "perspective") == 0)
5038 {
5039 ++i;
5040
5041 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5042
5043 int data_size = tokens[i].size;
5044 ++i;
5045
5046 if (out_camera->type != cgltf_camera_type_invalid)
5047 {
5048 return CGLTF_ERROR_JSON;
5049 }
5050
5051 out_camera->type = cgltf_camera_type_perspective;
5052
5053 for (int k = 0; k < data_size; ++k)
5054 {
5055 CGLTF_CHECK_KEY(tokens[i]);
5056
5057 if (cgltf_json_strcmp(tokens+i, json_chunk, "aspectRatio") == 0)
5058 {
5059 ++i;
5060 out_camera->data.perspective.has_aspect_ratio = 1;
5061 out_camera->data.perspective.aspect_ratio = cgltf_json_to_float(tokens + i, json_chunk);
5062 ++i;
5063 }
5064 else if (cgltf_json_strcmp(tokens+i, json_chunk, "yfov") == 0)
5065 {
5066 ++i;
5067 out_camera->data.perspective.yfov = cgltf_json_to_float(tokens + i, json_chunk);
5068 ++i;
5069 }
5070 else if (cgltf_json_strcmp(tokens+i, json_chunk, "zfar") == 0)
5071 {
5072 ++i;
5073 out_camera->data.perspective.has_zfar = 1;
5074 out_camera->data.perspective.zfar = cgltf_json_to_float(tokens + i, json_chunk);
5075 ++i;
5076 }
5077 else if (cgltf_json_strcmp(tokens+i, json_chunk, "znear") == 0)
5078 {
5079 ++i;
5080 out_camera->data.perspective.znear = cgltf_json_to_float(tokens + i, json_chunk);
5081 ++i;
5082 }
5083 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5084 {
5085 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->data.perspective.extras);
5086 }
5087 else
5088 {
5089 i = cgltf_skip_json(tokens, i+1);
5090 }
5091
5092 if (i < 0)
5093 {
5094 return i;
5095 }
5096 }
5097 }
5098 else if (cgltf_json_strcmp(tokens+i, json_chunk, "orthographic") == 0)
5099 {
5100 ++i;
5101
5102 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5103
5104 int data_size = tokens[i].size;
5105 ++i;
5106
5107 if (out_camera->type != cgltf_camera_type_invalid)
5108 {
5109 return CGLTF_ERROR_JSON;
5110 }
5111
5112 out_camera->type = cgltf_camera_type_orthographic;
5113
5114 for (int k = 0; k < data_size; ++k)
5115 {
5116 CGLTF_CHECK_KEY(tokens[i]);
5117
5118 if (cgltf_json_strcmp(tokens+i, json_chunk, "xmag") == 0)
5119 {
5120 ++i;
5121 out_camera->data.orthographic.xmag = cgltf_json_to_float(tokens + i, json_chunk);
5122 ++i;
5123 }
5124 else if (cgltf_json_strcmp(tokens+i, json_chunk, "ymag") == 0)
5125 {
5126 ++i;
5127 out_camera->data.orthographic.ymag = cgltf_json_to_float(tokens + i, json_chunk);
5128 ++i;
5129 }
5130 else if (cgltf_json_strcmp(tokens+i, json_chunk, "zfar") == 0)
5131 {
5132 ++i;
5133 out_camera->data.orthographic.zfar = cgltf_json_to_float(tokens + i, json_chunk);
5134 ++i;
5135 }
5136 else if (cgltf_json_strcmp(tokens+i, json_chunk, "znear") == 0)
5137 {
5138 ++i;
5139 out_camera->data.orthographic.znear = cgltf_json_to_float(tokens + i, json_chunk);
5140 ++i;
5141 }
5142 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5143 {
5144 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->data.orthographic.extras);
5145 }
5146 else
5147 {
5148 i = cgltf_skip_json(tokens, i+1);
5149 }
5150
5151 if (i < 0)
5152 {
5153 return i;
5154 }
5155 }
5156 }
5157 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5158 {
5159 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->extras);
5160 }
5161 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5162 {
5163 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_camera->extensions_count, &out_camera->extensions);
5164 }
5165 else
5166 {
5167 i = cgltf_skip_json(tokens, i+1);
5168 }
5169
5170 if (i < 0)
5171 {
5172 return i;
5173 }
5174 }
5175
5176 return i;
5177 }
5178
5179 static int cgltf_parse_json_cameras(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5180 {
5181 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_camera), (void**)&out_data->cameras, &out_data->cameras_count);
5182 if (i < 0)
5183 {
5184 return i;
5185 }
5186
5187 for (cgltf_size j = 0; j < out_data->cameras_count; ++j)
5188 {
5189 i = cgltf_parse_json_camera(options, tokens, i, json_chunk, &out_data->cameras[j]);
5190 if (i < 0)
5191 {
5192 return i;
5193 }
5194 }
5195 return i;
5196 }
5197
5198 static int cgltf_parse_json_light(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_light* out_light)
5199 {
5200 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5201
5202 out_light->color[0] = 1.f;
5203 out_light->color[1] = 1.f;
5204 out_light->color[2] = 1.f;
5205 out_light->intensity = 1.f;
5206
5207 out_light->spot_inner_cone_angle = 0.f;
5208 out_light->spot_outer_cone_angle = 3.1415926535f / 4.0f;
5209
5210 int size = tokens[i].size;
5211 ++i;
5212
5213 for (int j = 0; j < size; ++j)
5214 {
5215 CGLTF_CHECK_KEY(tokens[i]);
5216
5217 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
5218 {
5219 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_light->name);
5220 }
5221 else if (cgltf_json_strcmp(tokens + i, json_chunk, "color") == 0)
5222 {
5223 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_light->color, 3);
5224 }
5225 else if (cgltf_json_strcmp(tokens + i, json_chunk, "intensity") == 0)
5226 {
5227 ++i;
5228 out_light->intensity = cgltf_json_to_float(tokens + i, json_chunk);
5229 ++i;
5230 }
5231 else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0)
5232 {
5233 ++i;
5234 if (cgltf_json_strcmp(tokens + i, json_chunk, "directional") == 0)
5235 {
5236 out_light->type = cgltf_light_type_directional;
5237 }
5238 else if (cgltf_json_strcmp(tokens + i, json_chunk, "point") == 0)
5239 {
5240 out_light->type = cgltf_light_type_point;
5241 }
5242 else if (cgltf_json_strcmp(tokens + i, json_chunk, "spot") == 0)
5243 {
5244 out_light->type = cgltf_light_type_spot;
5245 }
5246 ++i;
5247 }
5248 else if (cgltf_json_strcmp(tokens + i, json_chunk, "range") == 0)
5249 {
5250 ++i;
5251 out_light->range = cgltf_json_to_float(tokens + i, json_chunk);
5252 ++i;
5253 }
5254 else if (cgltf_json_strcmp(tokens+i, json_chunk, "spot") == 0)
5255 {
5256 ++i;
5257
5258 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5259
5260 int data_size = tokens[i].size;
5261 ++i;
5262
5263 for (int k = 0; k < data_size; ++k)
5264 {
5265 CGLTF_CHECK_KEY(tokens[i]);
5266
5267 if (cgltf_json_strcmp(tokens+i, json_chunk, "innerConeAngle") == 0)
5268 {
5269 ++i;
5270 out_light->spot_inner_cone_angle = cgltf_json_to_float(tokens + i, json_chunk);
5271 ++i;
5272 }
5273 else if (cgltf_json_strcmp(tokens+i, json_chunk, "outerConeAngle") == 0)
5274 {
5275 ++i;
5276 out_light->spot_outer_cone_angle = cgltf_json_to_float(tokens + i, json_chunk);
5277 ++i;
5278 }
5279 else
5280 {
5281 i = cgltf_skip_json(tokens, i+1);
5282 }
5283
5284 if (i < 0)
5285 {
5286 return i;
5287 }
5288 }
5289 }
5290 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5291 {
5292 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_light->extras);
5293 }
5294 else
5295 {
5296 i = cgltf_skip_json(tokens, i+1);
5297 }
5298
5299 if (i < 0)
5300 {
5301 return i;
5302 }
5303 }
5304
5305 return i;
5306 }
5307
5308 static int cgltf_parse_json_lights(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5309 {
5310 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_light), (void**)&out_data->lights, &out_data->lights_count);
5311 if (i < 0)
5312 {
5313 return i;
5314 }
5315
5316 for (cgltf_size j = 0; j < out_data->lights_count; ++j)
5317 {
5318 i = cgltf_parse_json_light(options, tokens, i, json_chunk, &out_data->lights[j]);
5319 if (i < 0)
5320 {
5321 return i;
5322 }
5323 }
5324 return i;
5325 }
5326
5327 static int cgltf_parse_json_node(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_node* out_node)
5328 {
5329 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5330
5331 out_node->rotation[3] = 1.0f;
5332 out_node->scale[0] = 1.0f;
5333 out_node->scale[1] = 1.0f;
5334 out_node->scale[2] = 1.0f;
5335 out_node->matrix[0] = 1.0f;
5336 out_node->matrix[5] = 1.0f;
5337 out_node->matrix[10] = 1.0f;
5338 out_node->matrix[15] = 1.0f;
5339
5340 int size = tokens[i].size;
5341 ++i;
5342
5343 for (int j = 0; j < size; ++j)
5344 {
5345 CGLTF_CHECK_KEY(tokens[i]);
5346
5347 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
5348 {
5349 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_node->name);
5350 }
5351 else if (cgltf_json_strcmp(tokens+i, json_chunk, "children") == 0)
5352 {
5353 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_node*), (void**)&out_node->children, &out_node->children_count);
5354 if (i < 0)
5355 {
5356 return i;
5357 }
5358
5359 for (cgltf_size k = 0; k < out_node->children_count; ++k)
5360 {
5361 out_node->children[k] = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk));
5362 ++i;
5363 }
5364 }
5365 else if (cgltf_json_strcmp(tokens+i, json_chunk, "mesh") == 0)
5366 {
5367 ++i;
5368 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
5369 out_node->mesh = CGLTF_PTRINDEX(cgltf_mesh, cgltf_json_to_int(tokens + i, json_chunk));
5370 ++i;
5371 }
5372 else if (cgltf_json_strcmp(tokens+i, json_chunk, "skin") == 0)
5373 {
5374 ++i;
5375 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
5376 out_node->skin = CGLTF_PTRINDEX(cgltf_skin, cgltf_json_to_int(tokens + i, json_chunk));
5377 ++i;
5378 }
5379 else if (cgltf_json_strcmp(tokens+i, json_chunk, "camera") == 0)
5380 {
5381 ++i;
5382 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
5383 out_node->camera = CGLTF_PTRINDEX(cgltf_camera, cgltf_json_to_int(tokens + i, json_chunk));
5384 ++i;
5385 }
5386 else if (cgltf_json_strcmp(tokens+i, json_chunk, "translation") == 0)
5387 {
5388 out_node->has_translation = 1;
5389 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->translation, 3);
5390 }
5391 else if (cgltf_json_strcmp(tokens+i, json_chunk, "rotation") == 0)
5392 {
5393 out_node->has_rotation = 1;
5394 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->rotation, 4);
5395 }
5396 else if (cgltf_json_strcmp(tokens+i, json_chunk, "scale") == 0)
5397 {
5398 out_node->has_scale = 1;
5399 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->scale, 3);
5400 }
5401 else if (cgltf_json_strcmp(tokens+i, json_chunk, "matrix") == 0)
5402 {
5403 out_node->has_matrix = 1;
5404 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->matrix, 16);
5405 }
5406 else if (cgltf_json_strcmp(tokens + i, json_chunk, "weights") == 0)
5407 {
5408 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_float), (void**)&out_node->weights, &out_node->weights_count);
5409 if (i < 0)
5410 {
5411 return i;
5412 }
5413
5414 i = cgltf_parse_json_float_array(tokens, i - 1, json_chunk, out_node->weights, (int)out_node->weights_count);
5415 }
5416 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5417 {
5418 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_node->extras);
5419 }
5420 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5421 {
5422 ++i;
5423
5424 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5425 if(out_node->extensions)
5426 {
5427 return CGLTF_ERROR_JSON;
5428 }
5429
5430 int extensions_size = tokens[i].size;
5431 out_node->extensions_count= 0;
5432 out_node->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
5433
5434 if (!out_node->extensions)
5435 {
5436 return CGLTF_ERROR_NOMEM;
5437 }
5438
5439 ++i;
5440
5441 for (int k = 0; k < extensions_size; ++k)
5442 {
5443 CGLTF_CHECK_KEY(tokens[i]);
5444
5445 if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_lights_punctual") == 0)
5446 {
5447 ++i;
5448
5449 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5450
5451 int data_size = tokens[i].size;
5452 ++i;
5453
5454 for (int m = 0; m < data_size; ++m)
5455 {
5456 CGLTF_CHECK_KEY(tokens[i]);
5457
5458 if (cgltf_json_strcmp(tokens + i, json_chunk, "light") == 0)
5459 {
5460 ++i;
5461 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
5462 out_node->light = CGLTF_PTRINDEX(cgltf_light, cgltf_json_to_int(tokens + i, json_chunk));
5463 ++i;
5464 }
5465 else
5466 {
5467 i = cgltf_skip_json(tokens, i + 1);
5468 }
5469
5470 if (i < 0)
5471 {
5472 return i;
5473 }
5474 }
5475 }
5476 else if (cgltf_json_strcmp(tokens + i, json_chunk, "EXT_mesh_gpu_instancing") == 0)
5477 {
5478 out_node->has_mesh_gpu_instancing = 1;
5479 i = cgltf_parse_json_mesh_gpu_instancing(options, tokens, i + 1, json_chunk, &out_node->mesh_gpu_instancing);
5480 }
5481 else
5482 {
5483 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_node->extensions[out_node->extensions_count++]));
5484 }
5485
5486 if (i < 0)
5487 {
5488 return i;
5489 }
5490 }
5491 }
5492 else
5493 {
5494 i = cgltf_skip_json(tokens, i+1);
5495 }
5496
5497 if (i < 0)
5498 {
5499 return i;
5500 }
5501 }
5502
5503 return i;
5504 }
5505
5506 static int cgltf_parse_json_nodes(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5507 {
5508 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_node), (void**)&out_data->nodes, &out_data->nodes_count);
5509 if (i < 0)
5510 {
5511 return i;
5512 }
5513
5514 for (cgltf_size j = 0; j < out_data->nodes_count; ++j)
5515 {
5516 i = cgltf_parse_json_node(options, tokens, i, json_chunk, &out_data->nodes[j]);
5517 if (i < 0)
5518 {
5519 return i;
5520 }
5521 }
5522 return i;
5523 }
5524
5525 static int cgltf_parse_json_scene(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_scene* out_scene)
5526 {
5527 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5528
5529 int size = tokens[i].size;
5530 ++i;
5531
5532 for (int j = 0; j < size; ++j)
5533 {
5534 CGLTF_CHECK_KEY(tokens[i]);
5535
5536 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
5537 {
5538 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_scene->name);
5539 }
5540 else if (cgltf_json_strcmp(tokens+i, json_chunk, "nodes") == 0)
5541 {
5542 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_node*), (void**)&out_scene->nodes, &out_scene->nodes_count);
5543 if (i < 0)
5544 {
5545 return i;
5546 }
5547
5548 for (cgltf_size k = 0; k < out_scene->nodes_count; ++k)
5549 {
5550 out_scene->nodes[k] = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk));
5551 ++i;
5552 }
5553 }
5554 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5555 {
5556 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_scene->extras);
5557 }
5558 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5559 {
5560 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_scene->extensions_count, &out_scene->extensions);
5561 }
5562 else
5563 {
5564 i = cgltf_skip_json(tokens, i+1);
5565 }
5566
5567 if (i < 0)
5568 {
5569 return i;
5570 }
5571 }
5572
5573 return i;
5574 }
5575
5576 static int cgltf_parse_json_scenes(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5577 {
5578 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_scene), (void**)&out_data->scenes, &out_data->scenes_count);
5579 if (i < 0)
5580 {
5581 return i;
5582 }
5583
5584 for (cgltf_size j = 0; j < out_data->scenes_count; ++j)
5585 {
5586 i = cgltf_parse_json_scene(options, tokens, i, json_chunk, &out_data->scenes[j]);
5587 if (i < 0)
5588 {
5589 return i;
5590 }
5591 }
5592 return i;
5593 }
5594
5595 static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation_sampler* out_sampler)
5596 {
5597 (void)options;
5598 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5599
5600 int size = tokens[i].size;
5601 ++i;
5602
5603 for (int j = 0; j < size; ++j)
5604 {
5605 CGLTF_CHECK_KEY(tokens[i]);
5606
5607 if (cgltf_json_strcmp(tokens+i, json_chunk, "input") == 0)
5608 {
5609 ++i;
5610 out_sampler->input = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk));
5611 ++i;
5612 }
5613 else if (cgltf_json_strcmp(tokens+i, json_chunk, "output") == 0)
5614 {
5615 ++i;
5616 out_sampler->output = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk));
5617 ++i;
5618 }
5619 else if (cgltf_json_strcmp(tokens+i, json_chunk, "interpolation") == 0)
5620 {
5621 ++i;
5622 if (cgltf_json_strcmp(tokens + i, json_chunk, "LINEAR") == 0)
5623 {
5624 out_sampler->interpolation = cgltf_interpolation_type_linear;
5625 }
5626 else if (cgltf_json_strcmp(tokens + i, json_chunk, "STEP") == 0)
5627 {
5628 out_sampler->interpolation = cgltf_interpolation_type_step;
5629 }
5630 else if (cgltf_json_strcmp(tokens + i, json_chunk, "CUBICSPLINE") == 0)
5631 {
5632 out_sampler->interpolation = cgltf_interpolation_type_cubic_spline;
5633 }
5634 ++i;
5635 }
5636 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5637 {
5638 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sampler->extras);
5639 }
5640 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5641 {
5642 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sampler->extensions_count, &out_sampler->extensions);
5643 }
5644 else
5645 {
5646 i = cgltf_skip_json(tokens, i+1);
5647 }
5648
5649 if (i < 0)
5650 {
5651 return i;
5652 }
5653 }
5654
5655 return i;
5656 }
5657
5658 static int cgltf_parse_json_animation_channel(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation_channel* out_channel)
5659 {
5660 (void)options;
5661 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5662
5663 int size = tokens[i].size;
5664 ++i;
5665
5666 for (int j = 0; j < size; ++j)
5667 {
5668 CGLTF_CHECK_KEY(tokens[i]);
5669
5670 if (cgltf_json_strcmp(tokens+i, json_chunk, "sampler") == 0)
5671 {
5672 ++i;
5673 out_channel->sampler = CGLTF_PTRINDEX(cgltf_animation_sampler, cgltf_json_to_int(tokens + i, json_chunk));
5674 ++i;
5675 }
5676 else if (cgltf_json_strcmp(tokens+i, json_chunk, "target") == 0)
5677 {
5678 ++i;
5679
5680 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5681
5682 int target_size = tokens[i].size;
5683 ++i;
5684
5685 for (int k = 0; k < target_size; ++k)
5686 {
5687 CGLTF_CHECK_KEY(tokens[i]);
5688
5689 if (cgltf_json_strcmp(tokens+i, json_chunk, "node") == 0)
5690 {
5691 ++i;
5692 out_channel->target_node = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk));
5693 ++i;
5694 }
5695 else if (cgltf_json_strcmp(tokens+i, json_chunk, "path") == 0)
5696 {
5697 ++i;
5698 if (cgltf_json_strcmp(tokens+i, json_chunk, "translation") == 0)
5699 {
5700 out_channel->target_path = cgltf_animation_path_type_translation;
5701 }
5702 else if (cgltf_json_strcmp(tokens+i, json_chunk, "rotation") == 0)
5703 {
5704 out_channel->target_path = cgltf_animation_path_type_rotation;
5705 }
5706 else if (cgltf_json_strcmp(tokens+i, json_chunk, "scale") == 0)
5707 {
5708 out_channel->target_path = cgltf_animation_path_type_scale;
5709 }
5710 else if (cgltf_json_strcmp(tokens+i, json_chunk, "weights") == 0)
5711 {
5712 out_channel->target_path = cgltf_animation_path_type_weights;
5713 }
5714 ++i;
5715 }
5716 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5717 {
5718 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_channel->extras);
5719 }
5720 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5721 {
5722 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_channel->extensions_count, &out_channel->extensions);
5723 }
5724 else
5725 {
5726 i = cgltf_skip_json(tokens, i+1);
5727 }
5728
5729 if (i < 0)
5730 {
5731 return i;
5732 }
5733 }
5734 }
5735 else
5736 {
5737 i = cgltf_skip_json(tokens, i+1);
5738 }
5739
5740 if (i < 0)
5741 {
5742 return i;
5743 }
5744 }
5745
5746 return i;
5747 }
5748
5749 static int cgltf_parse_json_animation(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation* out_animation)
5750 {
5751 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5752
5753 int size = tokens[i].size;
5754 ++i;
5755
5756 for (int j = 0; j < size; ++j)
5757 {
5758 CGLTF_CHECK_KEY(tokens[i]);
5759
5760 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
5761 {
5762 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_animation->name);
5763 }
5764 else if (cgltf_json_strcmp(tokens+i, json_chunk, "samplers") == 0)
5765 {
5766 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_animation_sampler), (void**)&out_animation->samplers, &out_animation->samplers_count);
5767 if (i < 0)
5768 {
5769 return i;
5770 }
5771
5772 for (cgltf_size k = 0; k < out_animation->samplers_count; ++k)
5773 {
5774 i = cgltf_parse_json_animation_sampler(options, tokens, i, json_chunk, &out_animation->samplers[k]);
5775 if (i < 0)
5776 {
5777 return i;
5778 }
5779 }
5780 }
5781 else if (cgltf_json_strcmp(tokens+i, json_chunk, "channels") == 0)
5782 {
5783 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_animation_channel), (void**)&out_animation->channels, &out_animation->channels_count);
5784 if (i < 0)
5785 {
5786 return i;
5787 }
5788
5789 for (cgltf_size k = 0; k < out_animation->channels_count; ++k)
5790 {
5791 i = cgltf_parse_json_animation_channel(options, tokens, i, json_chunk, &out_animation->channels[k]);
5792 if (i < 0)
5793 {
5794 return i;
5795 }
5796 }
5797 }
5798 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5799 {
5800 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_animation->extras);
5801 }
5802 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5803 {
5804 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_animation->extensions_count, &out_animation->extensions);
5805 }
5806 else
5807 {
5808 i = cgltf_skip_json(tokens, i+1);
5809 }
5810
5811 if (i < 0)
5812 {
5813 return i;
5814 }
5815 }
5816
5817 return i;
5818 }
5819
5820 static int cgltf_parse_json_animations(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5821 {
5822 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_animation), (void**)&out_data->animations, &out_data->animations_count);
5823 if (i < 0)
5824 {
5825 return i;
5826 }
5827
5828 for (cgltf_size j = 0; j < out_data->animations_count; ++j)
5829 {
5830 i = cgltf_parse_json_animation(options, tokens, i, json_chunk, &out_data->animations[j]);
5831 if (i < 0)
5832 {
5833 return i;
5834 }
5835 }
5836 return i;
5837 }
5838
5839 static int cgltf_parse_json_variant(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_material_variant* out_variant)
5840 {
5841 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5842
5843 int size = tokens[i].size;
5844 ++i;
5845
5846 for (int j = 0; j < size; ++j)
5847 {
5848 CGLTF_CHECK_KEY(tokens[i]);
5849
5850 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
5851 {
5852 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_variant->name);
5853 }
5854 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5855 {
5856 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_variant->extras);
5857 }
5858 else
5859 {
5860 i = cgltf_skip_json(tokens, i+1);
5861 }
5862
5863 if (i < 0)
5864 {
5865 return i;
5866 }
5867 }
5868
5869 return i;
5870 }
5871
5872 static int cgltf_parse_json_variants(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5873 {
5874 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_material_variant), (void**)&out_data->variants, &out_data->variants_count);
5875 if (i < 0)
5876 {
5877 return i;
5878 }
5879
5880 for (cgltf_size j = 0; j < out_data->variants_count; ++j)
5881 {
5882 i = cgltf_parse_json_variant(options, tokens, i, json_chunk, &out_data->variants[j]);
5883 if (i < 0)
5884 {
5885 return i;
5886 }
5887 }
5888 return i;
5889 }
5890
5891 static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_asset* out_asset)
5892 {
5893 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5894
5895 int size = tokens[i].size;
5896 ++i;
5897
5898 for (int j = 0; j < size; ++j)
5899 {
5900 CGLTF_CHECK_KEY(tokens[i]);
5901
5902 if (cgltf_json_strcmp(tokens+i, json_chunk, "copyright") == 0)
5903 {
5904 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->copyright);
5905 }
5906 else if (cgltf_json_strcmp(tokens+i, json_chunk, "generator") == 0)
5907 {
5908 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->generator);
5909 }
5910 else if (cgltf_json_strcmp(tokens+i, json_chunk, "version") == 0)
5911 {
5912 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->version);
5913 }
5914 else if (cgltf_json_strcmp(tokens+i, json_chunk, "minVersion") == 0)
5915 {
5916 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->min_version);
5917 }
5918 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5919 {
5920 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_asset->extras);
5921 }
5922 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5923 {
5924 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_asset->extensions_count, &out_asset->extensions);
5925 }
5926 else
5927 {
5928 i = cgltf_skip_json(tokens, i+1);
5929 }
5930
5931 if (i < 0)
5932 {
5933 return i;
5934 }
5935 }
5936
5937 if (out_asset->version && CGLTF_ATOF(out_asset->version) < 2)
5938 {
5939 return CGLTF_ERROR_LEGACY;
5940 }
5941
5942 return i;
5943 }
5944
5945 cgltf_size cgltf_num_components(cgltf_type type) {
5946 switch (type)
5947 {
5948 case cgltf_type_vec2:
5949 return 2;
5950 case cgltf_type_vec3:
5951 return 3;
5952 case cgltf_type_vec4:
5953 return 4;
5954 case cgltf_type_mat2:
5955 return 4;
5956 case cgltf_type_mat3:
5957 return 9;
5958 case cgltf_type_mat4:
5959 return 16;
5960 case cgltf_type_invalid:
5961 case cgltf_type_scalar:
5962 default:
5963 return 1;
5964 }
5965 }
5966
5967 cgltf_size cgltf_component_size(cgltf_component_type component_type) {
5968 switch (component_type)
5969 {
5970 case cgltf_component_type_r_8:
5971 case cgltf_component_type_r_8u:
5972 return 1;
5973 case cgltf_component_type_r_16:
5974 case cgltf_component_type_r_16u:
5975 return 2;
5976 case cgltf_component_type_r_32u:
5977 case cgltf_component_type_r_32f:
5978 return 4;
5979 case cgltf_component_type_invalid:
5980 default:
5981 return 0;
5982 }
5983 }
5984
5985 cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type)
5986 {
5987 cgltf_size component_size = cgltf_component_size(component_type);
5988 if (type == cgltf_type_mat2 && component_size == 1)
5989 {
5990 return 8 * component_size;
5991 }
5992 else if (type == cgltf_type_mat3 && (component_size == 1 || component_size == 2))
5993 {
5994 return 12 * component_size;
5995 }
5996 return component_size * cgltf_num_components(type);
5997 }
5998
5999 static int cgltf_fixup_pointers(cgltf_data* out_data);
6000
6001 static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
6002 {
6003 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
6004
6005 int size = tokens[i].size;
6006 ++i;
6007
6008 for (int j = 0; j < size; ++j)
6009 {
6010 CGLTF_CHECK_KEY(tokens[i]);
6011
6012 if (cgltf_json_strcmp(tokens + i, json_chunk, "asset") == 0)
6013 {
6014 i = cgltf_parse_json_asset(options, tokens, i + 1, json_chunk, &out_data->asset);
6015 }
6016 else if (cgltf_json_strcmp(tokens + i, json_chunk, "meshes") == 0)
6017 {
6018 i = cgltf_parse_json_meshes(options, tokens, i + 1, json_chunk, out_data);
6019 }
6020 else if (cgltf_json_strcmp(tokens + i, json_chunk, "accessors") == 0)
6021 {
6022 i = cgltf_parse_json_accessors(options, tokens, i + 1, json_chunk, out_data);
6023 }
6024 else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferViews") == 0)
6025 {
6026 i = cgltf_parse_json_buffer_views(options, tokens, i + 1, json_chunk, out_data);
6027 }
6028 else if (cgltf_json_strcmp(tokens + i, json_chunk, "buffers") == 0)
6029 {
6030 i = cgltf_parse_json_buffers(options, tokens, i + 1, json_chunk, out_data);
6031 }
6032 else if (cgltf_json_strcmp(tokens + i, json_chunk, "materials") == 0)
6033 {
6034 i = cgltf_parse_json_materials(options, tokens, i + 1, json_chunk, out_data);
6035 }
6036 else if (cgltf_json_strcmp(tokens + i, json_chunk, "images") == 0)
6037 {
6038 i = cgltf_parse_json_images(options, tokens, i + 1, json_chunk, out_data);
6039 }
6040 else if (cgltf_json_strcmp(tokens + i, json_chunk, "textures") == 0)
6041 {
6042 i = cgltf_parse_json_textures(options, tokens, i + 1, json_chunk, out_data);
6043 }
6044 else if (cgltf_json_strcmp(tokens + i, json_chunk, "samplers") == 0)
6045 {
6046 i = cgltf_parse_json_samplers(options, tokens, i + 1, json_chunk, out_data);
6047 }
6048 else if (cgltf_json_strcmp(tokens + i, json_chunk, "skins") == 0)
6049 {
6050 i = cgltf_parse_json_skins(options, tokens, i + 1, json_chunk, out_data);
6051 }
6052 else if (cgltf_json_strcmp(tokens + i, json_chunk, "cameras") == 0)
6053 {
6054 i = cgltf_parse_json_cameras(options, tokens, i + 1, json_chunk, out_data);
6055 }
6056 else if (cgltf_json_strcmp(tokens + i, json_chunk, "nodes") == 0)
6057 {
6058 i = cgltf_parse_json_nodes(options, tokens, i + 1, json_chunk, out_data);
6059 }
6060 else if (cgltf_json_strcmp(tokens + i, json_chunk, "scenes") == 0)
6061 {
6062 i = cgltf_parse_json_scenes(options, tokens, i + 1, json_chunk, out_data);
6063 }
6064 else if (cgltf_json_strcmp(tokens + i, json_chunk, "scene") == 0)
6065 {
6066 ++i;
6067 out_data->scene = CGLTF_PTRINDEX(cgltf_scene, cgltf_json_to_int(tokens + i, json_chunk));
6068 ++i;
6069 }
6070 else if (cgltf_json_strcmp(tokens + i, json_chunk, "animations") == 0)
6071 {
6072 i = cgltf_parse_json_animations(options, tokens, i + 1, json_chunk, out_data);
6073 }
6074 else if (cgltf_json_strcmp(tokens+i, json_chunk, "extras") == 0)
6075 {
6076 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_data->extras);
6077 }
6078 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
6079 {
6080 ++i;
6081
6082 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
6083 if(out_data->data_extensions)
6084 {
6085 return CGLTF_ERROR_JSON;
6086 }
6087
6088 int extensions_size = tokens[i].size;
6089 out_data->data_extensions_count = 0;
6090 out_data->data_extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
6091
6092 if (!out_data->data_extensions)
6093 {
6094 return CGLTF_ERROR_NOMEM;
6095 }
6096
6097 ++i;
6098
6099 for (int k = 0; k < extensions_size; ++k)
6100 {
6101 CGLTF_CHECK_KEY(tokens[i]);
6102
6103 if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_lights_punctual") == 0)
6104 {
6105 ++i;
6106
6107 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
6108
6109 int data_size = tokens[i].size;
6110 ++i;
6111
6112 for (int m = 0; m < data_size; ++m)
6113 {
6114 CGLTF_CHECK_KEY(tokens[i]);
6115
6116 if (cgltf_json_strcmp(tokens + i, json_chunk, "lights") == 0)
6117 {
6118 i = cgltf_parse_json_lights(options, tokens, i + 1, json_chunk, out_data);
6119 }
6120 else
6121 {
6122 i = cgltf_skip_json(tokens, i + 1);
6123 }
6124
6125 if (i < 0)
6126 {
6127 return i;
6128 }
6129 }
6130 }
6131 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_variants") == 0)
6132 {
6133 ++i;
6134
6135 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
6136
6137 int data_size = tokens[i].size;
6138 ++i;
6139
6140 for (int m = 0; m < data_size; ++m)
6141 {
6142 CGLTF_CHECK_KEY(tokens[i]);
6143
6144 if (cgltf_json_strcmp(tokens + i, json_chunk, "variants") == 0)
6145 {
6146 i = cgltf_parse_json_variants(options, tokens, i + 1, json_chunk, out_data);
6147 }
6148 else
6149 {
6150 i = cgltf_skip_json(tokens, i + 1);
6151 }
6152
6153 if (i < 0)
6154 {
6155 return i;
6156 }
6157 }
6158 }
6159 else
6160 {
6161 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_data->data_extensions[out_data->data_extensions_count++]));
6162 }
6163
6164 if (i < 0)
6165 {
6166 return i;
6167 }
6168 }
6169 }
6170 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensionsUsed") == 0)
6171 {
6172 i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_data->extensions_used, &out_data->extensions_used_count);
6173 }
6174 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensionsRequired") == 0)
6175 {
6176 i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_data->extensions_required, &out_data->extensions_required_count);
6177 }
6178 else
6179 {
6180 i = cgltf_skip_json(tokens, i + 1);
6181 }
6182
6183 if (i < 0)
6184 {
6185 return i;
6186 }
6187 }
6188
6189 return i;
6190 }
6191
6192 cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, cgltf_size size, cgltf_data** out_data)
6193 {
6194 jsmn_parser parser = { 0, 0, 0 };
6195
6196 if (options->json_token_count == 0)
6197 {
6198 int token_count = jsmn_parse(&parser, (const char*)json_chunk, size, NULL, 0);
6199
6200 if (token_count <= 0)
6201 {
6202 return cgltf_result_invalid_json;
6203 }
6204
6205 options->json_token_count = token_count;
6206 }
6207
6208 jsmntok_t* tokens = (jsmntok_t*)options->memory.alloc_func(options->memory.user_data, sizeof(jsmntok_t) * (options->json_token_count + 1));
6209
6210 if (!tokens)
6211 {
6212 return cgltf_result_out_of_memory;
6213 }
6214
6215 jsmn_init(&parser);
6216
6217 int token_count = jsmn_parse(&parser, (const char*)json_chunk, size, tokens, options->json_token_count);
6218
6219 if (token_count <= 0)
6220 {
6221 options->memory.free_func(options->memory.user_data, tokens);
6222 return cgltf_result_invalid_json;
6223 }
6224
6225 // this makes sure that we always have an UNDEFINED token at the end of the stream
6226 // for invalid JSON inputs this makes sure we don't perform out of bound reads of token data
6227 tokens[token_count].type = JSMN_UNDEFINED;
6228
6229 cgltf_data* data = (cgltf_data*)options->memory.alloc_func(options->memory.user_data, sizeof(cgltf_data));
6230
6231 if (!data)
6232 {
6233 options->memory.free_func(options->memory.user_data, tokens);
6234 return cgltf_result_out_of_memory;
6235 }
6236
6237 memset(data, 0, sizeof(cgltf_data));
6238 data->memory = options->memory;
6239 data->file = options->file;
6240
6241 int i = cgltf_parse_json_root(options, tokens, 0, json_chunk, data);
6242
6243 options->memory.free_func(options->memory.user_data, tokens);
6244
6245 if (i < 0)
6246 {
6247 cgltf_free(data);
6248
6249 switch (i)
6250 {
6251 case CGLTF_ERROR_NOMEM: return cgltf_result_out_of_memory;
6252 case CGLTF_ERROR_LEGACY: return cgltf_result_legacy_gltf;
6253 default: return cgltf_result_invalid_gltf;
6254 }
6255 }
6256
6257 if (cgltf_fixup_pointers(data) < 0)
6258 {
6259 cgltf_free(data);
6260 return cgltf_result_invalid_gltf;
6261 }
6262
6263 data->json = (const char*)json_chunk;
6264 data->json_size = size;
6265
6266 *out_data = data;
6267
6268 return cgltf_result_success;
6269 }
6270
6271 static int cgltf_fixup_pointers(cgltf_data* data)
6272 {
6273 for (cgltf_size i = 0; i < data->meshes_count; ++i)
6274 {
6275 for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j)
6276 {
6277 CGLTF_PTRFIXUP(data->meshes[i].primitives[j].indices, data->accessors, data->accessors_count);
6278 CGLTF_PTRFIXUP(data->meshes[i].primitives[j].material, data->materials, data->materials_count);
6279
6280 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k)
6281 {
6282 CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].attributes[k].data, data->accessors, data->accessors_count);
6283 }
6284
6285 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k)
6286 {
6287 for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m)
6288 {
6289 CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].targets[k].attributes[m].data, data->accessors, data->accessors_count);
6290 }
6291 }
6292
6293 if (data->meshes[i].primitives[j].has_draco_mesh_compression)
6294 {
6295 CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].draco_mesh_compression.buffer_view, data->buffer_views, data->buffer_views_count);
6296 for (cgltf_size m = 0; m < data->meshes[i].primitives[j].draco_mesh_compression.attributes_count; ++m)
6297 {
6298 CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].draco_mesh_compression.attributes[m].data, data->accessors, data->accessors_count);
6299 }
6300 }
6301
6302 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k)
6303 {
6304 CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].mappings[k].material, data->materials, data->materials_count);
6305 }
6306 }
6307 }
6308
6309 for (cgltf_size i = 0; i < data->accessors_count; ++i)
6310 {
6311 CGLTF_PTRFIXUP(data->accessors[i].buffer_view, data->buffer_views, data->buffer_views_count);
6312
6313 if (data->accessors[i].is_sparse)
6314 {
6315 CGLTF_PTRFIXUP_REQ(data->accessors[i].sparse.indices_buffer_view, data->buffer_views, data->buffer_views_count);
6316 CGLTF_PTRFIXUP_REQ(data->accessors[i].sparse.values_buffer_view, data->buffer_views, data->buffer_views_count);
6317 }
6318
6319 if (data->accessors[i].buffer_view)
6320 {
6321 data->accessors[i].stride = data->accessors[i].buffer_view->stride;
6322 }
6323
6324 if (data->accessors[i].stride == 0)
6325 {
6326 data->accessors[i].stride = cgltf_calc_size(data->accessors[i].type, data->accessors[i].component_type);
6327 }
6328 }
6329
6330 for (cgltf_size i = 0; i < data->textures_count; ++i)
6331 {
6332 CGLTF_PTRFIXUP(data->textures[i].image, data->images, data->images_count);
6333 CGLTF_PTRFIXUP(data->textures[i].basisu_image, data->images, data->images_count);
6334 CGLTF_PTRFIXUP(data->textures[i].sampler, data->samplers, data->samplers_count);
6335 }
6336
6337 for (cgltf_size i = 0; i < data->images_count; ++i)
6338 {
6339 CGLTF_PTRFIXUP(data->images[i].buffer_view, data->buffer_views, data->buffer_views_count);
6340 }
6341
6342 for (cgltf_size i = 0; i < data->materials_count; ++i)
6343 {
6344 CGLTF_PTRFIXUP(data->materials[i].normal_texture.texture, data->textures, data->textures_count);
6345 CGLTF_PTRFIXUP(data->materials[i].emissive_texture.texture, data->textures, data->textures_count);
6346 CGLTF_PTRFIXUP(data->materials[i].occlusion_texture.texture, data->textures, data->textures_count);
6347
6348 CGLTF_PTRFIXUP(data->materials[i].pbr_metallic_roughness.base_color_texture.texture, data->textures, data->textures_count);
6349 CGLTF_PTRFIXUP(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture, data->textures, data->textures_count);
6350
6351 CGLTF_PTRFIXUP(data->materials[i].pbr_specular_glossiness.diffuse_texture.texture, data->textures, data->textures_count);
6352 CGLTF_PTRFIXUP(data->materials[i].pbr_specular_glossiness.specular_glossiness_texture.texture, data->textures, data->textures_count);
6353
6354 CGLTF_PTRFIXUP(data->materials[i].clearcoat.clearcoat_texture.texture, data->textures, data->textures_count);
6355 CGLTF_PTRFIXUP(data->materials[i].clearcoat.clearcoat_roughness_texture.texture, data->textures, data->textures_count);
6356 CGLTF_PTRFIXUP(data->materials[i].clearcoat.clearcoat_normal_texture.texture, data->textures, data->textures_count);
6357
6358 CGLTF_PTRFIXUP(data->materials[i].specular.specular_texture.texture, data->textures, data->textures_count);
6359 CGLTF_PTRFIXUP(data->materials[i].specular.specular_color_texture.texture, data->textures, data->textures_count);
6360
6361 CGLTF_PTRFIXUP(data->materials[i].transmission.transmission_texture.texture, data->textures, data->textures_count);
6362
6363 CGLTF_PTRFIXUP(data->materials[i].volume.thickness_texture.texture, data->textures, data->textures_count);
6364
6365 CGLTF_PTRFIXUP(data->materials[i].sheen.sheen_color_texture.texture, data->textures, data->textures_count);
6366 CGLTF_PTRFIXUP(data->materials[i].sheen.sheen_roughness_texture.texture, data->textures, data->textures_count);
6367
6368 CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_texture.texture, data->textures, data->textures_count);
6369 CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_thickness_texture.texture, data->textures, data->textures_count);
6370 }
6371
6372 for (cgltf_size i = 0; i < data->buffer_views_count; ++i)
6373 {
6374 CGLTF_PTRFIXUP_REQ(data->buffer_views[i].buffer, data->buffers, data->buffers_count);
6375
6376 if (data->buffer_views[i].has_meshopt_compression)
6377 {
6378 CGLTF_PTRFIXUP_REQ(data->buffer_views[i].meshopt_compression.buffer, data->buffers, data->buffers_count);
6379 }
6380 }
6381
6382 for (cgltf_size i = 0; i < data->skins_count; ++i)
6383 {
6384 for (cgltf_size j = 0; j < data->skins[i].joints_count; ++j)
6385 {
6386 CGLTF_PTRFIXUP_REQ(data->skins[i].joints[j], data->nodes, data->nodes_count);
6387 }
6388
6389 CGLTF_PTRFIXUP(data->skins[i].skeleton, data->nodes, data->nodes_count);
6390 CGLTF_PTRFIXUP(data->skins[i].inverse_bind_matrices, data->accessors, data->accessors_count);
6391 }
6392
6393 for (cgltf_size i = 0; i < data->nodes_count; ++i)
6394 {
6395 for (cgltf_size j = 0; j < data->nodes[i].children_count; ++j)
6396 {
6397 CGLTF_PTRFIXUP_REQ(data->nodes[i].children[j], data->nodes, data->nodes_count);
6398
6399 if (data->nodes[i].children[j]->parent)
6400 {
6401 return CGLTF_ERROR_JSON;
6402 }
6403
6404 data->nodes[i].children[j]->parent = &data->nodes[i];
6405 }
6406
6407 CGLTF_PTRFIXUP(data->nodes[i].mesh, data->meshes, data->meshes_count);
6408 CGLTF_PTRFIXUP(data->nodes[i].skin, data->skins, data->skins_count);
6409 CGLTF_PTRFIXUP(data->nodes[i].camera, data->cameras, data->cameras_count);
6410 CGLTF_PTRFIXUP(data->nodes[i].light, data->lights, data->lights_count);
6411
6412 if (data->nodes[i].has_mesh_gpu_instancing)
6413 {
6414 CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.buffer_view, data->buffer_views, data->buffer_views_count);
6415 for (cgltf_size m = 0; m < data->nodes[i].mesh_gpu_instancing.attributes_count; ++m)
6416 {
6417 CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.attributes[m].data, data->accessors, data->accessors_count);
6418 }
6419 }
6420 }
6421
6422 for (cgltf_size i = 0; i < data->scenes_count; ++i)
6423 {
6424 for (cgltf_size j = 0; j < data->scenes[i].nodes_count; ++j)
6425 {
6426 CGLTF_PTRFIXUP_REQ(data->scenes[i].nodes[j], data->nodes, data->nodes_count);
6427
6428 if (data->scenes[i].nodes[j]->parent)
6429 {
6430 return CGLTF_ERROR_JSON;
6431 }
6432 }
6433 }
6434
6435 CGLTF_PTRFIXUP(data->scene, data->scenes, data->scenes_count);
6436
6437 for (cgltf_size i = 0; i < data->animations_count; ++i)
6438 {
6439 for (cgltf_size j = 0; j < data->animations[i].samplers_count; ++j)
6440 {
6441 CGLTF_PTRFIXUP_REQ(data->animations[i].samplers[j].input, data->accessors, data->accessors_count);
6442 CGLTF_PTRFIXUP_REQ(data->animations[i].samplers[j].output, data->accessors, data->accessors_count);
6443 }
6444
6445 for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j)
6446 {
6447 CGLTF_PTRFIXUP_REQ(data->animations[i].channels[j].sampler, data->animations[i].samplers, data->animations[i].samplers_count);
6448 CGLTF_PTRFIXUP(data->animations[i].channels[j].target_node, data->nodes, data->nodes_count);
6449 }
6450 }
6451
6452 return 0;
6453 }
6454
6455 /*
6456 * -- jsmn.c start --
6457 * Source: https://github.com/zserge/jsmn
6458 * License: MIT
6459 *
6460 * Copyright (c) 2010 Serge A. Zaitsev
6461
6462 * Permission is hereby granted, free of charge, to any person obtaining a copy
6463 * of this software and associated documentation files (the "Software"), to deal
6464 * in the Software without restriction, including without limitation the rights
6465 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6466 * copies of the Software, and to permit persons to whom the Software is
6467 * furnished to do so, subject to the following conditions:
6468
6469 * The above copyright notice and this permission notice shall be included in
6470 * all copies or substantial portions of the Software.
6471
6472 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6473 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6474 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6475 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6476 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6477 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6478 * THE SOFTWARE.
6479 */
6480
6481 /**
6482 * Allocates a fresh unused token from the token pull.
6483 */
6484 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
6485 jsmntok_t *tokens, size_t num_tokens) {
6486 jsmntok_t *tok;
6487 if (parser->toknext >= num_tokens) {
6488 return NULL;
6489 }
6490 tok = &tokens[parser->toknext++];
6491 tok->start = tok->end = -1;
6492 tok->size = 0;
6493 #ifdef JSMN_PARENT_LINKS
6494 tok->parent = -1;
6495 #endif
6496 return tok;
6497 }
6498
6499 /**
6500 * Fills token type and boundaries.
6501 */
6502 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
6503 ptrdiff_t start, ptrdiff_t end) {
6504 token->type = type;
6505 token->start = start;
6506 token->end = end;
6507 token->size = 0;
6508 }
6509
6510 /**
6511 * Fills next available token with JSON primitive.
6512 */
6513 static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
6514 size_t len, jsmntok_t *tokens, size_t num_tokens) {
6515 jsmntok_t *token;
6516 ptrdiff_t start;
6517
6518 start = parser->pos;
6519
6520 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
6521 switch (js[parser->pos]) {
6522 #ifndef JSMN_STRICT
6523 /* In strict mode primitive must be followed by "," or "}" or "]" */
6524 case ':':
6525 #endif
6526 case '\t' : case '\r' : case '\n' : case ' ' :
6527 case ',' : case ']' : case '}' :
6528 goto found;
6529 }
6530 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
6531 parser->pos = start;
6532 return JSMN_ERROR_INVAL;
6533 }
6534 }
6535 #ifdef JSMN_STRICT
6536 /* In strict mode primitive must be followed by a comma/object/array */
6537 parser->pos = start;
6538 return JSMN_ERROR_PART;
6539 #endif
6540
6541 found:
6542 if (tokens == NULL) {
6543 parser->pos--;
6544 return 0;
6545 }
6546 token = jsmn_alloc_token(parser, tokens, num_tokens);
6547 if (token == NULL) {
6548 parser->pos = start;
6549 return JSMN_ERROR_NOMEM;
6550 }
6551 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
6552 #ifdef JSMN_PARENT_LINKS
6553 token->parent = parser->toksuper;
6554 #endif
6555 parser->pos--;
6556 return 0;
6557 }
6558
6559 /**
6560 * Fills next token with JSON string.
6561 */
6562 static int jsmn_parse_string(jsmn_parser *parser, const char *js,
6563 size_t len, jsmntok_t *tokens, size_t num_tokens) {
6564 jsmntok_t *token;
6565
6566 ptrdiff_t start = parser->pos;
6567
6568 parser->pos++;
6569
6570 /* Skip starting quote */
6571 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
6572 char c = js[parser->pos];
6573
6574 /* Quote: end of string */
6575 if (c == '\"') {
6576 if (tokens == NULL) {
6577 return 0;
6578 }
6579 token = jsmn_alloc_token(parser, tokens, num_tokens);
6580 if (token == NULL) {
6581 parser->pos = start;
6582 return JSMN_ERROR_NOMEM;
6583 }
6584 jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
6585 #ifdef JSMN_PARENT_LINKS
6586 token->parent = parser->toksuper;
6587 #endif
6588 return 0;
6589 }
6590
6591 /* Backslash: Quoted symbol expected */
6592 if (c == '\\' && parser->pos + 1 < len) {
6593 int i;
6594 parser->pos++;
6595 switch (js[parser->pos]) {
6596 /* Allowed escaped symbols */
6597 case '\"': case '/' : case '\\' : case 'b' :
6598 case 'f' : case 'r' : case 'n' : case 't' :
6599 break;
6600 /* Allows escaped symbol \uXXXX */
6601 case 'u':
6602 parser->pos++;
6603 for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
6604 /* If it isn't a hex character we have an error */
6605 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
6606 (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
6607 (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
6608 parser->pos = start;
6609 return JSMN_ERROR_INVAL;
6610 }
6611 parser->pos++;
6612 }
6613 parser->pos--;
6614 break;
6615 /* Unexpected symbol */
6616 default:
6617 parser->pos = start;
6618 return JSMN_ERROR_INVAL;
6619 }
6620 }
6621 }
6622 parser->pos = start;
6623 return JSMN_ERROR_PART;
6624 }
6625
6626 /**
6627 * Parse JSON string and fill tokens.
6628 */
6629 static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
6630 jsmntok_t *tokens, size_t num_tokens) {
6631 int r;
6632 int i;
6633 jsmntok_t *token;
6634 int count = parser->toknext;
6635
6636 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
6637 char c;
6638 jsmntype_t type;
6639
6640 c = js[parser->pos];
6641 switch (c) {
6642 case '{': case '[':
6643 count++;
6644 if (tokens == NULL) {
6645 break;
6646 }
6647 token = jsmn_alloc_token(parser, tokens, num_tokens);
6648 if (token == NULL)
6649 return JSMN_ERROR_NOMEM;
6650 if (parser->toksuper != -1) {
6651 tokens[parser->toksuper].size++;
6652 #ifdef JSMN_PARENT_LINKS
6653 token->parent = parser->toksuper;
6654 #endif
6655 }
6656 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
6657 token->start = parser->pos;
6658 parser->toksuper = parser->toknext - 1;
6659 break;
6660 case '}': case ']':
6661 if (tokens == NULL)
6662 break;
6663 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
6664 #ifdef JSMN_PARENT_LINKS
6665 if (parser->toknext < 1) {
6666 return JSMN_ERROR_INVAL;
6667 }
6668 token = &tokens[parser->toknext - 1];
6669 for (;;) {
6670 if (token->start != -1 && token->end == -1) {
6671 if (token->type != type) {
6672 return JSMN_ERROR_INVAL;
6673 }
6674 token->end = parser->pos + 1;
6675 parser->toksuper = token->parent;
6676 break;
6677 }
6678 if (token->parent == -1) {
6679 if(token->type != type || parser->toksuper == -1) {
6680 return JSMN_ERROR_INVAL;
6681 }
6682 break;
6683 }
6684 token = &tokens[token->parent];
6685 }
6686 #else
6687 for (i = parser->toknext - 1; i >= 0; i--) {
6688 token = &tokens[i];
6689 if (token->start != -1 && token->end == -1) {
6690 if (token->type != type) {
6691 return JSMN_ERROR_INVAL;
6692 }
6693 parser->toksuper = -1;
6694 token->end = parser->pos + 1;
6695 break;
6696 }
6697 }
6698 /* Error if unmatched closing bracket */
6699 if (i == -1) return JSMN_ERROR_INVAL;
6700 for (; i >= 0; i--) {
6701 token = &tokens[i];
6702 if (token->start != -1 && token->end == -1) {
6703 parser->toksuper = i;
6704 break;
6705 }
6706 }
6707 #endif
6708 break;
6709 case '\"':
6710 r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
6711 if (r < 0) return r;
6712 count++;
6713 if (parser->toksuper != -1 && tokens != NULL)
6714 tokens[parser->toksuper].size++;
6715 break;
6716 case '\t' : case '\r' : case '\n' : case ' ':
6717 break;
6718 case ':':
6719 parser->toksuper = parser->toknext - 1;
6720 break;
6721 case ',':
6722 if (tokens != NULL && parser->toksuper != -1 &&
6723 tokens[parser->toksuper].type != JSMN_ARRAY &&
6724 tokens[parser->toksuper].type != JSMN_OBJECT) {
6725 #ifdef JSMN_PARENT_LINKS
6726 parser->toksuper = tokens[parser->toksuper].parent;
6727 #else
6728 for (i = parser->toknext - 1; i >= 0; i--) {
6729 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
6730 if (tokens[i].start != -1 && tokens[i].end == -1) {
6731 parser->toksuper = i;
6732 break;
6733 }
6734 }
6735 }
6736 #endif
6737 }
6738 break;
6739 #ifdef JSMN_STRICT
6740 /* In strict mode primitives are: numbers and booleans */
6741 case '-': case '0': case '1' : case '2': case '3' : case '4':
6742 case '5': case '6': case '7' : case '8': case '9':
6743 case 't': case 'f': case 'n' :
6744 /* And they must not be keys of the object */
6745 if (tokens != NULL && parser->toksuper != -1) {
6746 jsmntok_t *t = &tokens[parser->toksuper];
6747 if (t->type == JSMN_OBJECT ||
6748 (t->type == JSMN_STRING && t->size != 0)) {
6749 return JSMN_ERROR_INVAL;
6750 }
6751 }
6752 #else
6753 /* In non-strict mode every unquoted value is a primitive */
6754 default:
6755 #endif
6756 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
6757 if (r < 0) return r;
6758 count++;
6759 if (parser->toksuper != -1 && tokens != NULL)
6760 tokens[parser->toksuper].size++;
6761 break;
6762
6763 #ifdef JSMN_STRICT
6764 /* Unexpected char in strict mode */
6765 default:
6766 return JSMN_ERROR_INVAL;
6767 #endif
6768 }
6769 }
6770
6771 if (tokens != NULL) {
6772 for (i = parser->toknext - 1; i >= 0; i--) {
6773 /* Unmatched opened object or array */
6774 if (tokens[i].start != -1 && tokens[i].end == -1) {
6775 return JSMN_ERROR_PART;
6776 }
6777 }
6778 }
6779
6780 return count;
6781 }
6782
6783 /**
6784 * Creates a new parser based over a given buffer with an array of tokens
6785 * available.
6786 */
6787 static void jsmn_init(jsmn_parser *parser) {
6788 parser->pos = 0;
6789 parser->toknext = 0;
6790 parser->toksuper = -1;
6791 }
6792 /*
6793 * -- jsmn.c end --
6794 */
6795
6796 #endif /* #ifdef CGLTF_IMPLEMENTATION */
6797
6798 /* cgltf is distributed under MIT license:
6799 *
6800 * Copyright (c) 2018-2021 Johannes Kuhlmann
6801
6802 * Permission is hereby granted, free of charge, to any person obtaining a copy
6803 * of this software and associated documentation files (the "Software"), to deal
6804 * in the Software without restriction, including without limitation the rights
6805 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6806 * copies of the Software, and to permit persons to whom the Software is
6807 * furnished to do so, subject to the following conditions:
6808
6809 * The above copyright notice and this permission notice shall be included in all
6810 * copies or substantial portions of the Software.
6811
6812 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6813 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6814 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6815 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6816 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6817 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
6818 * SOFTWARE.
6819 */
6820