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