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

Generated with cgit - Back to sebastiano.tronto.net