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