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