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