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