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