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