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