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