summaryrefslogtreecommitdiffhomepage
path: root/src/external/cgltf.h
diff options
context:
space:
mode:
authorRay <[email protected]>2019-08-07 00:33:57 +0200
committerRay <[email protected]>2019-08-07 00:33:57 +0200
commit3d46297cc150803a55e27f446b2d4708ff0b04bd (patch)
treeed441cacca41738d27371e2d49c11be250ba2462 /src/external/cgltf.h
parent439e73a8ece912f2a7df5f4c0ed7fc6fb7673672 (diff)
downloadraylib-3d46297cc150803a55e27f446b2d4708ff0b04bd.tar.gz
raylib-3d46297cc150803a55e27f446b2d4708ff0b04bd.zip
Update external libraries
Diffstat (limited to 'src/external/cgltf.h')
-rw-r--r--src/external/cgltf.h598
1 files changed, 497 insertions, 101 deletions
diff --git a/src/external/cgltf.h b/src/external/cgltf.h
index 85d5c985..7f3f77f7 100644
--- a/src/external/cgltf.h
+++ b/src/external/cgltf.h
@@ -1,7 +1,7 @@
/**
* cgltf - a single-file glTF 2.0 parser written in C99.
*
- * Version: 1.0
+ * Version: 1.2
*
* Website: https://github.com/jkuhlmann/cgltf
*
@@ -35,8 +35,15 @@
* variable.
*
* `cgltf_result cgltf_load_buffers(const cgltf_options*, cgltf_data*,
- * const char*)` can be optionally called to open and read buffer
- * files using the `FILE*` APIs.
+ * const char* gltf_path)` can be optionally called to open and read buffer
+ * files using the `FILE*` APIs. The `gltf_path` argument is the path to
+ * the original glTF file, which allows the parser to resolve the path to
+ * buffer files.
+ *
+ * `cgltf_result cgltf_load_buffer_base64(const cgltf_options* options,
+ * cgltf_size size, const char* base64, void** out_data)` decodes
+ * base64-encoded data content. Used internally by `cgltf_load_buffers()`
+ * and may be useful if you're not dealing with normal files.
*
* `cgltf_result cgltf_parse_file(const cgltf_options* options, const
* char* path, cgltf_data** out_data)` can be used to open the given
@@ -44,6 +51,29 @@
*
* `cgltf_result cgltf_validate(cgltf_data*)` can be used to do additional
* checks to make sure the parsed glTF data is valid.
+ *
+ * `cgltf_node_transform_local` converts the translation / rotation / scale properties of a node
+ * into a mat4.
+ *
+ * `cgltf_node_transform_world` calls `cgltf_node_transform_local` on every ancestor in order
+ * to compute the root-to-node transformation.
+ *
+ * `cgltf_accessor_read_float` reads a certain element from an accessor and converts it to
+ * floating point, assuming that `cgltf_load_buffers` has already been called. The passed-in element
+ * size is the number of floats in the output buffer, which should be in the range [1, 16]. Returns
+ * false if the passed-in element_size is too small, or if the accessor is sparse.
+ *
+ * `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t
+ * and only works with single-component data types.
+ *
+ * `cgltf_result cgltf_copy_extras_json(const cgltf_data*, const cgltf_extras*,
+ * char* dest, cgltf_size* dest_size)` allows to retrieve the "extras" data that
+ * can be attached to many glTF objects (which can be arbitrary JSON data). The
+ * `cgltf_extras` struct stores the offsets of the start and end of the extras JSON data
+ * as it appears in the complete glTF JSON data. This function copies the extras data
+ * into the provided buffer. If `dest` is NULL, the length of the data is written into
+ * `dest_size`. You can then parse this data using your own JSON parser
+ * or, if you've included the cgltf implementation using the integrated JSMN JSON parser.
*/
#ifndef CGLTF_H_INCLUDED__
#define CGLTF_H_INCLUDED__
@@ -175,11 +205,17 @@ typedef enum cgltf_light_type {
cgltf_light_type_spot,
} cgltf_light_type;
+typedef struct cgltf_extras {
+ cgltf_size start_offset;
+ cgltf_size end_offset;
+} cgltf_extras;
+
typedef struct cgltf_buffer
{
cgltf_size size;
char* uri;
void* data; /* loaded by cgltf_load_buffers */
+ cgltf_extras extras;
} cgltf_buffer;
typedef struct cgltf_buffer_view
@@ -189,6 +225,7 @@ typedef struct cgltf_buffer_view
cgltf_size size;
cgltf_size stride; /* 0 == automatically determined by accessor */
cgltf_buffer_view_type type;
+ cgltf_extras extras;
} cgltf_buffer_view;
typedef struct cgltf_accessor_sparse
@@ -199,6 +236,9 @@ typedef struct cgltf_accessor_sparse
cgltf_component_type indices_component_type;
cgltf_buffer_view* values_buffer_view;
cgltf_size values_byte_offset;
+ cgltf_extras extras;
+ cgltf_extras indices_extras;
+ cgltf_extras values_extras;
} cgltf_accessor_sparse;
typedef struct cgltf_accessor
@@ -216,6 +256,7 @@ typedef struct cgltf_accessor
cgltf_float max[16];
cgltf_bool is_sparse;
cgltf_accessor_sparse sparse;
+ cgltf_extras extras;
} cgltf_accessor;
typedef struct cgltf_attribute
@@ -232,6 +273,7 @@ typedef struct cgltf_image
char* uri;
cgltf_buffer_view* buffer_view;
char* mime_type;
+ cgltf_extras extras;
} cgltf_image;
typedef struct cgltf_sampler
@@ -240,6 +282,7 @@ typedef struct cgltf_sampler
cgltf_int min_filter;
cgltf_int wrap_s;
cgltf_int wrap_t;
+ cgltf_extras extras;
} cgltf_sampler;
typedef struct cgltf_texture
@@ -247,6 +290,7 @@ typedef struct cgltf_texture
char* name;
cgltf_image* image;
cgltf_sampler* sampler;
+ cgltf_extras extras;
} cgltf_texture;
typedef struct cgltf_texture_transform
@@ -264,6 +308,7 @@ typedef struct cgltf_texture_view
cgltf_float scale; /* equivalent to strength for occlusion_texture */
cgltf_bool has_transform;
cgltf_texture_transform transform;
+ cgltf_extras extras;
} cgltf_texture_view;
typedef struct cgltf_pbr_metallic_roughness
@@ -274,6 +319,8 @@ typedef struct cgltf_pbr_metallic_roughness
cgltf_float base_color_factor[4];
cgltf_float metallic_factor;
cgltf_float roughness_factor;
+
+ cgltf_extras extras;
} cgltf_pbr_metallic_roughness;
typedef struct cgltf_pbr_specular_glossiness
@@ -301,6 +348,7 @@ typedef struct cgltf_material
cgltf_float alpha_cutoff;
cgltf_bool double_sided;
cgltf_bool unlit;
+ cgltf_extras extras;
} cgltf_material;
typedef struct cgltf_morph_target {
@@ -316,6 +364,7 @@ typedef struct cgltf_primitive {
cgltf_size attributes_count;
cgltf_morph_target* targets;
cgltf_size targets_count;
+ cgltf_extras extras;
} cgltf_primitive;
typedef struct cgltf_mesh {
@@ -324,6 +373,7 @@ typedef struct cgltf_mesh {
cgltf_size primitives_count;
cgltf_float* weights;
cgltf_size weights_count;
+ cgltf_extras extras;
} cgltf_mesh;
typedef struct cgltf_node cgltf_node;
@@ -334,6 +384,7 @@ typedef struct cgltf_skin {
cgltf_size joints_count;
cgltf_node* skeleton;
cgltf_accessor* inverse_bind_matrices;
+ cgltf_extras extras;
} cgltf_skin;
typedef struct cgltf_camera_perspective {
@@ -341,6 +392,7 @@ typedef struct cgltf_camera_perspective {
cgltf_float yfov;
cgltf_float zfar;
cgltf_float znear;
+ cgltf_extras extras;
} cgltf_camera_perspective;
typedef struct cgltf_camera_orthographic {
@@ -348,6 +400,7 @@ typedef struct cgltf_camera_orthographic {
cgltf_float ymag;
cgltf_float zfar;
cgltf_float znear;
+ cgltf_extras extras;
} cgltf_camera_orthographic;
typedef struct cgltf_camera {
@@ -357,6 +410,7 @@ typedef struct cgltf_camera {
cgltf_camera_perspective perspective;
cgltf_camera_orthographic orthographic;
};
+ cgltf_extras extras;
} cgltf_camera;
typedef struct cgltf_light {
@@ -388,24 +442,28 @@ struct cgltf_node {
cgltf_float rotation[4];
cgltf_float scale[3];
cgltf_float matrix[16];
+ cgltf_extras extras;
};
typedef struct cgltf_scene {
char* name;
cgltf_node** nodes;
cgltf_size nodes_count;
+ cgltf_extras extras;
} cgltf_scene;
typedef struct cgltf_animation_sampler {
cgltf_accessor* input;
cgltf_accessor* output;
cgltf_interpolation_type interpolation;
+ cgltf_extras extras;
} cgltf_animation_sampler;
typedef struct cgltf_animation_channel {
cgltf_animation_sampler* sampler;
cgltf_node* target_node;
cgltf_animation_path_type target_path;
+ cgltf_extras extras;
} cgltf_animation_channel;
typedef struct cgltf_animation {
@@ -414,6 +472,7 @@ typedef struct cgltf_animation {
cgltf_size samplers_count;
cgltf_animation_channel* channels;
cgltf_size channels_count;
+ cgltf_extras extras;
} cgltf_animation;
typedef struct cgltf_asset {
@@ -421,6 +480,7 @@ typedef struct cgltf_asset {
char* generator;
char* version;
char* min_version;
+ cgltf_extras extras;
} cgltf_asset;
typedef struct cgltf_data
@@ -474,6 +534,17 @@ typedef struct cgltf_data
cgltf_animation* animations;
cgltf_size animations_count;
+ cgltf_extras extras;
+
+ char** extensions_used;
+ cgltf_size extensions_used_count;
+
+ char** extensions_required;
+ cgltf_size extensions_required_count;
+
+ const char* json;
+ cgltf_size json_size;
+
const void* bin;
cgltf_size bin_size;
@@ -495,7 +566,10 @@ cgltf_result cgltf_parse_file(
cgltf_result cgltf_load_buffers(
const cgltf_options* options,
cgltf_data* data,
- const char* base_path);
+ const char* gltf_path);
+
+
+cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data);
cgltf_result cgltf_validate(
cgltf_data* data);
@@ -505,6 +579,11 @@ void cgltf_free(cgltf_data* data);
void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix);
void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix);
+cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size);
+cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index);
+
+cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size);
+
#ifdef __cplusplus
}
#endif
@@ -528,7 +607,14 @@ void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix)
#include <stdint.h> /* For uint8_t, uint32_t */
#include <string.h> /* For strncpy */
#include <stdlib.h> /* For malloc, free */
-#include <stdio.h> /* For fopen */
+#include <stdio.h> /* For fopen */
+#include <limits.h> /* For UINT_MAX etc */
+
+/* JSMN_PARENT_LINKS is necessary to make parsing large structures linear in input size */
+#define JSMN_PARENT_LINKS
+
+/* JSMN_STRICT is necessary to reject invalid JSON documents */
+#define JSMN_STRICT
/*
* -- jsmn.h start --
@@ -580,11 +666,13 @@ static const uint32_t GlbMagicBinChunk = 0x004E4942;
static void* cgltf_default_alloc(void* user, cgltf_size size)
{
+ (void)user;
return malloc(size);
}
static void cgltf_default_free(void* user, void* ptr)
{
+ (void)user;
free(ptr);
}
@@ -810,22 +898,22 @@ static void cgltf_combine_paths(char* path, const char* base, const char* uri)
}
else
{
- strcpy(path, base);
+ strcpy(path, uri);
}
}
-static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_size size, const char* uri, const char* base_path, void** out_data)
+static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_size size, const char* uri, const char* gltf_path, void** out_data)
{
void* (*memory_alloc)(void*, cgltf_size) = options->memory_alloc ? options->memory_alloc : &cgltf_default_alloc;
void (*memory_free)(void*, void*) = options->memory_free ? options->memory_free : &cgltf_default_free;
- char* path = (char*)memory_alloc(options->memory_user_data, strlen(uri) + strlen(base_path) + 1);
+ char* path = (char*)memory_alloc(options->memory_user_data, strlen(uri) + strlen(gltf_path) + 1);
if (!path)
{
return cgltf_result_out_of_memory;
}
- cgltf_combine_paths(path, base_path, uri);
+ cgltf_combine_paths(path, gltf_path, uri);
FILE* file = fopen(path, "rb");
@@ -858,7 +946,7 @@ static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_s
return cgltf_result_success;
}
-static cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data)
+cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data)
{
void* (*memory_alloc)(void*, cgltf_size) = options->memory_alloc ? options->memory_alloc : &cgltf_default_alloc;
void (*memory_free)(void*, void*) = options->memory_free ? options->memory_free : &cgltf_default_free;
@@ -905,7 +993,7 @@ static cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf
return cgltf_result_success;
}
-cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, const char* base_path)
+cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, const char* gltf_path)
{
if (options == NULL)
{
@@ -954,9 +1042,9 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data,
return cgltf_result_unknown_format;
}
}
- else if (strstr(uri, "://") == NULL)
+ else if (strstr(uri, "://") == NULL && gltf_path)
{
- cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, base_path, &data->buffers[i].data);
+ cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data);
if (res != cgltf_result_success)
{
@@ -1150,6 +1238,34 @@ cgltf_result cgltf_validate(cgltf_data* data)
return cgltf_result_success;
}
+cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size)
+{
+ cgltf_size json_size = extras->end_offset - extras->start_offset;
+
+ if (!dest)
+ {
+ if (dest_size)
+ {
+ *dest_size = json_size + 1;
+ return cgltf_result_success;
+ }
+ return cgltf_result_invalid_options;
+ }
+
+ if (*dest_size + 1 < json_size)
+ {
+ strncpy(dest, data->json + extras->start_offset, *dest_size - 1);
+ dest[*dest_size - 1] = 0;
+ }
+ else
+ {
+ strncpy(dest, data->json + extras->start_offset, json_size);
+ dest[json_size] = 0;
+ }
+
+ return cgltf_result_success;
+}
+
void cgltf_free(cgltf_data* data)
{
if (!data)
@@ -1282,6 +1398,20 @@ void cgltf_free(cgltf_data* data)
data->memory_free(data->memory_user_data, data->animations);
+ for (cgltf_size i = 0; i < data->extensions_used_count; ++i)
+ {
+ data->memory_free(data->memory_user_data, data->extensions_used[i]);
+ }
+
+ data->memory_free(data->memory_user_data, data->extensions_used);
+
+ for (cgltf_size i = 0; i < data->extensions_required_count; ++i)
+ {
+ data->memory_free(data->memory_user_data, data->extensions_required[i]);
+ }
+
+ data->memory_free(data->memory_user_data, data->extensions_required);
+
data->memory_free(data->memory_user_data, data->file_data);
data->memory_free(data->memory_user_data, data);
@@ -1367,6 +1497,142 @@ void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix)
}
}
+static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_type component_type)
+{
+ switch (component_type)
+ {
+ case cgltf_component_type_r_16:
+ return *((const int16_t*) in);
+ case cgltf_component_type_r_16u:
+ return *((const uint16_t*) in);
+ case cgltf_component_type_r_32u:
+ return *((const uint32_t*) in);
+ case cgltf_component_type_r_32f:
+ return (cgltf_size)*((const float*) in);
+ case cgltf_component_type_r_8:
+ return *((const int8_t*) in);
+ case cgltf_component_type_r_8u:
+ case cgltf_component_type_invalid:
+ default:
+ return *((const uint8_t*) in);
+ }
+}
+
+static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_type component_type, cgltf_bool normalized)
+{
+ if (component_type == cgltf_component_type_r_32f)
+ {
+ return *((const float*) in);
+ }
+
+ if (normalized)
+ {
+ switch (component_type)
+ {
+ case cgltf_component_type_r_32u:
+ return *((const uint32_t*) in) / (float) UINT_MAX;
+ case cgltf_component_type_r_16:
+ return *((const int16_t*) in) / (float) SHRT_MAX;
+ case cgltf_component_type_r_16u:
+ return *((const uint16_t*) in) / (float) USHRT_MAX;
+ case cgltf_component_type_r_8:
+ return *((const int8_t*) in) / (float) SCHAR_MAX;
+ case cgltf_component_type_r_8u:
+ case cgltf_component_type_invalid:
+ default:
+ return *((const uint8_t*) in) / (float) CHAR_MAX;
+ }
+ }
+
+ return (cgltf_float)cgltf_component_read_index(in, component_type);
+}
+
+static cgltf_size cgltf_num_components(cgltf_type type);
+static cgltf_size cgltf_component_size(cgltf_component_type component_type);
+
+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)
+{
+ cgltf_size num_components = cgltf_num_components(type);
+
+ if (element_size < num_components) {
+ return 0;
+ }
+
+ // There are three special cases for component extraction, see #data-alignment in the 2.0 spec.
+
+ cgltf_size component_size = cgltf_component_size(component_type);
+
+ if (type == cgltf_type_mat2 && component_size == 1)
+ {
+ out[0] = cgltf_component_read_float(element, component_type, normalized);
+ out[1] = cgltf_component_read_float(element + 1, component_type, normalized);
+ out[2] = cgltf_component_read_float(element + 4, component_type, normalized);
+ out[3] = cgltf_component_read_float(element + 5, component_type, normalized);
+ return 1;
+ }
+
+ if (type == cgltf_type_mat3 && component_size == 1)
+ {
+ out[0] = cgltf_component_read_float(element, component_type, normalized);
+ out[1] = cgltf_component_read_float(element + 1, component_type, normalized);
+ out[2] = cgltf_component_read_float(element + 2, component_type, normalized);
+ out[3] = cgltf_component_read_float(element + 4, component_type, normalized);
+ out[4] = cgltf_component_read_float(element + 5, component_type, normalized);
+ out[5] = cgltf_component_read_float(element + 6, component_type, normalized);
+ out[6] = cgltf_component_read_float(element + 8, component_type, normalized);
+ out[7] = cgltf_component_read_float(element + 9, component_type, normalized);
+ out[8] = cgltf_component_read_float(element + 10, component_type, normalized);
+ return 1;
+ }
+
+ if (type == cgltf_type_mat3 && component_size == 2)
+ {
+ out[0] = cgltf_component_read_float(element, component_type, normalized);
+ out[1] = cgltf_component_read_float(element + 2, component_type, normalized);
+ out[2] = cgltf_component_read_float(element + 4, component_type, normalized);
+ out[3] = cgltf_component_read_float(element + 8, component_type, normalized);
+ out[4] = cgltf_component_read_float(element + 10, component_type, normalized);
+ out[5] = cgltf_component_read_float(element + 12, component_type, normalized);
+ out[6] = cgltf_component_read_float(element + 16, component_type, normalized);
+ out[7] = cgltf_component_read_float(element + 18, component_type, normalized);
+ out[8] = cgltf_component_read_float(element + 20, component_type, normalized);
+ return 1;
+ }
+
+ for (cgltf_size i = 0; i < num_components; ++i)
+ {
+ out[i] = cgltf_component_read_float(element + component_size * i, component_type, normalized);
+ }
+ return 1;
+}
+
+
+cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size)
+{
+ if (accessor->is_sparse || accessor->buffer_view == NULL)
+ {
+ return 0;
+ }
+
+ cgltf_size offset = accessor->offset + accessor->buffer_view->offset;
+ const uint8_t* element = (const uint8_t*) accessor->buffer_view->buffer->data;
+ element += offset + accessor->stride * index;
+ return cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, out, element_size);
+}
+
+cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index)
+{
+ if (accessor->buffer_view)
+ {
+ cgltf_size offset = accessor->offset + accessor->buffer_view->offset;
+ const uint8_t* element = (const uint8_t*) accessor->buffer_view->buffer->data;
+ element += offset + accessor->stride * index;
+ return cgltf_component_read_index(element, accessor->component_type);
+ }
+
+ return 0;
+}
+
#define CGLTF_ERROR_JSON -1
#define CGLTF_ERROR_NOMEM -2
@@ -1413,39 +1679,31 @@ static cgltf_bool cgltf_json_to_bool(jsmntok_t const* tok, const uint8_t* json_c
static int cgltf_skip_json(jsmntok_t const* tokens, int i)
{
- if (tokens[i].type == JSMN_ARRAY)
- {
- int size = tokens[i].size;
- ++i;
- for (int j = 0; j < size; ++j)
- {
- i = cgltf_skip_json(tokens, i);
- if (i < 0)
- {
- return i;
- }
- }
- }
- else if (tokens[i].type == JSMN_OBJECT)
+ int end = i + 1;
+
+ while (i < end)
{
- int size = tokens[i].size;
- ++i;
- for (int j = 0; j < size; ++j)
+ switch (tokens[i].type)
{
- CGLTF_CHECK_KEY(tokens[i]);
- ++i;
- i = cgltf_skip_json(tokens, i);
- if (i < 0)
- {
- return i;
- }
+ case JSMN_OBJECT:
+ end += tokens[i].size * 2;
+ break;
+
+ case JSMN_ARRAY:
+ end += tokens[i].size;
+ break;
+
+ case JSMN_PRIMITIVE:
+ case JSMN_STRING:
+ break;
+
+ default:
+ return -1;
}
+
+ i++;
}
- else if (tokens[i].type == JSMN_PRIMITIVE
- || tokens[i].type == JSMN_STRING)
- {
- return i + 1;
- }
+
return i;
}
@@ -1495,6 +1753,7 @@ static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* toke
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)
{
+ (void)json_chunk;
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY);
if (*out_array)
{
@@ -1511,6 +1770,26 @@ static int cgltf_parse_json_array(cgltf_options* options, jsmntok_t const* token
return i + 1;
}
+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)
+{
+ CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY);
+ i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(char*), (void**)out_array, out_size);
+ if (i < 0)
+ {
+ return i;
+ }
+
+ for (cgltf_size j = 0; j < *out_size; ++j)
+ {
+ i = cgltf_parse_json_string(options, tokens, i, json_chunk, j + (*out_array));
+ if (i < 0)
+ {
+ return i;
+ }
+ }
+ return i;
+}
+
static void cgltf_parse_attribute_type(const char* name, cgltf_attribute_type* out_type, int* out_index)
{
const char* us = strchr(name, '_');
@@ -1592,6 +1871,15 @@ static int cgltf_parse_json_attribute_list(cgltf_options* options, jsmntok_t con
return i;
}
+static int cgltf_parse_json_extras(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extras* out_extras)
+{
+ (void)json_chunk;
+ out_extras->start_offset = tokens[i].start;
+ out_extras->end_offset = tokens[i].end;
+ i = cgltf_skip_json(tokens, i);
+ return i;
+}
+
static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_primitive* out_prim)
{
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
@@ -1637,15 +1925,19 @@ static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* t
return i;
}
- for (cgltf_size j = 0; j < out_prim->targets_count; ++j)
+ for (cgltf_size k = 0; k < out_prim->targets_count; ++k)
{
- i = cgltf_parse_json_attribute_list(options, tokens, i, json_chunk, &out_prim->targets[j].attributes, &out_prim->targets[j].attributes_count);
+ i = cgltf_parse_json_attribute_list(options, tokens, i, json_chunk, &out_prim->targets[k].attributes, &out_prim->targets[k].attributes_count);
if (i < 0)
{
return i;
}
}
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_prim->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -1702,6 +1994,10 @@ static int cgltf_parse_json_mesh(cgltf_options* options, jsmntok_t const* tokens
i = cgltf_parse_json_float_array(tokens, i - 1, json_chunk, out_mesh->weights, (int)out_mesh->weights_count);
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_mesh->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -1805,6 +2101,10 @@ static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, cons
out_sparse->indices_component_type = cgltf_json_to_component_type(tokens + i, json_chunk);
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->indices_extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -1840,6 +2140,10 @@ static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, cons
out_sparse->values_byte_offset = cgltf_json_to_int(tokens + i, json_chunk);
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->values_extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -1851,6 +2155,10 @@ static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, cons
}
}
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -1962,6 +2270,10 @@ static int cgltf_parse_json_accessor(jsmntok_t const* tokens, int i, const uint8
out_accessor->is_sparse = 1;
i = cgltf_parse_json_accessor_sparse(tokens, i + 1, json_chunk, &out_accessor->sparse);
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_accessor->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -2059,6 +2371,10 @@ static int cgltf_parse_json_texture_view(jsmntok_t const* tokens, int i, const u
out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk);
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_texture_view->extras);
+ }
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
{
++i;
@@ -2070,6 +2386,8 @@ static int cgltf_parse_json_texture_view(jsmntok_t const* tokens, int i, const u
for (int k = 0; k < extensions_size; ++k)
{
+ CGLTF_CHECK_KEY(tokens[i]);
+
if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_texture_transform") == 0)
{
out_texture_view->has_transform = 1;
@@ -2079,6 +2397,11 @@ static int cgltf_parse_json_texture_view(jsmntok_t const* tokens, int i, const u
{
i = cgltf_skip_json(tokens, i+1);
}
+
+ if (i < 0)
+ {
+ return i;
+ }
}
}
else
@@ -2134,6 +2457,10 @@ static int cgltf_parse_json_pbr_metallic_roughness(jsmntok_t const* tokens, int
i = cgltf_parse_json_texture_view(tokens, i + 1, json_chunk,
&out_pbr->metallic_roughness_texture);
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_pbr->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -2161,18 +2488,10 @@ static int cgltf_parse_json_pbr_specular_glossiness(jsmntok_t const* tokens, int
if (cgltf_json_strcmp(tokens+i, json_chunk, "diffuseFactor") == 0)
{
i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->diffuse_factor, 4);
- if (i < 0)
- {
- return i;
- }
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularFactor") == 0)
{
i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->specular_factor, 3);
- if (i < 0)
- {
- return i;
- }
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "glossinessFactor") == 0)
{
@@ -2183,18 +2502,10 @@ static int cgltf_parse_json_pbr_specular_glossiness(jsmntok_t const* tokens, int
else if (cgltf_json_strcmp(tokens+i, json_chunk, "diffuseTexture") == 0)
{
i = cgltf_parse_json_texture_view(tokens, i + 1, json_chunk, &out_pbr->diffuse_texture);
- if (i < 0)
- {
- return i;
- }
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularGlossinessTexture") == 0)
{
i = cgltf_parse_json_texture_view(tokens, i + 1, json_chunk, &out_pbr->specular_glossiness_texture);
- if (i < 0)
- {
- return i;
- }
}
else
{
@@ -2205,7 +2516,6 @@ static int cgltf_parse_json_pbr_specular_glossiness(jsmntok_t const* tokens, int
{
return i;
}
-
}
return i;
@@ -2240,6 +2550,10 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token
{
i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->name);
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_image->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i + 1);
@@ -2256,6 +2570,7 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token
static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_sampler* out_sampler)
{
+ (void)options;
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
out_sampler->wrap_s = 10497;
@@ -2296,6 +2611,10 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok
= cgltf_json_to_int(tokens + i, json_chunk);
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sampler->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i + 1);
@@ -2338,6 +2657,10 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok
out_texture->image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk));
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_texture->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i + 1);
@@ -2431,6 +2754,10 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to
cgltf_json_to_bool(tokens + i, json_chunk);
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_material->extras);
+ }
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
{
++i;
@@ -2631,6 +2958,10 @@ static int cgltf_parse_json_buffer_view(jsmntok_t const* tokens, int i, const ui
out_buffer_view->type = (cgltf_buffer_view_type)type;
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_buffer_view->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -2686,6 +3017,10 @@ static int cgltf_parse_json_buffer(cgltf_options* options, jsmntok_t const* toke
{
i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_buffer->uri);
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_buffer->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -2762,6 +3097,10 @@ static int cgltf_parse_json_skin(cgltf_options* options, jsmntok_t const* tokens
out_skin->inverse_bind_matrices = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk));
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_skin->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -2862,6 +3201,10 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke
out_camera->perspective.znear = cgltf_json_to_float(tokens + i, json_chunk);
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->perspective.extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -2912,6 +3255,10 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke
out_camera->orthographic.znear = cgltf_json_to_float(tokens + i, json_chunk);
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->orthographic.extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -2923,6 +3270,10 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke
}
}
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -3162,6 +3513,10 @@ static int cgltf_parse_json_node(cgltf_options* options, jsmntok_t const* tokens
i = cgltf_parse_json_float_array(tokens, i - 1, json_chunk, out_node->weights, (int)out_node->weights_count);
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_node->extras);
+ }
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
{
++i;
@@ -3279,6 +3634,10 @@ static int cgltf_parse_json_scene(cgltf_options* options, jsmntok_t const* token
++i;
}
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_scene->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -3314,6 +3673,7 @@ static int cgltf_parse_json_scenes(cgltf_options* options, jsmntok_t const* toke
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)
{
+ (void)options;
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
int size = tokens[i].size;
@@ -3352,6 +3712,10 @@ static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t
}
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sampler->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -3368,6 +3732,7 @@ static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t
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)
{
+ (void)options;
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
int size = tokens[i].size;
@@ -3423,6 +3788,10 @@ static int cgltf_parse_json_animation_channel(cgltf_options* options, jsmntok_t
}
++i;
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_channel->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -3497,6 +3866,10 @@ static int cgltf_parse_json_animation(cgltf_options* options, jsmntok_t const* t
}
}
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_animation->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -3557,6 +3930,10 @@ static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* token
{
i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->min_version);
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_asset->extras);
+ }
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -3571,58 +3948,58 @@ static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* token
return i;
}
-static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type)
-{
- cgltf_size size = 0;
+static cgltf_size cgltf_num_components(cgltf_type type) {
+ switch (type)
+ {
+ case cgltf_type_vec2:
+ return 2;
+ case cgltf_type_vec3:
+ return 3;
+ case cgltf_type_vec4:
+ return 4;
+ case cgltf_type_mat2:
+ return 4;
+ case cgltf_type_mat3:
+ return 9;
+ case cgltf_type_mat4:
+ return 16;
+ case cgltf_type_invalid:
+ case cgltf_type_scalar:
+ default:
+ return 1;
+ }
+}
+static cgltf_size cgltf_component_size(cgltf_component_type component_type) {
switch (component_type)
{
case cgltf_component_type_r_8:
case cgltf_component_type_r_8u:
- size = 1;
- break;
+ return 1;
case cgltf_component_type_r_16:
case cgltf_component_type_r_16u:
- size = 2;
- break;
+ return 2;
case cgltf_component_type_r_32u:
case cgltf_component_type_r_32f:
- size = 4;
- break;
+ return 4;
case cgltf_component_type_invalid:
default:
- size = 0;
- break;
+ return 0;
}
+}
- switch (type)
+static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type)
+{
+ cgltf_size component_size = cgltf_component_size(component_type);
+ if (type == cgltf_type_mat2 && component_size == 1)
{
- case cgltf_type_vec2:
- size *= 2;
- break;
- case cgltf_type_vec3:
- size *= 3;
- break;
- case cgltf_type_vec4:
- size *= 4;
- break;
- case cgltf_type_mat2:
- size *= 4;
- break;
- case cgltf_type_mat3:
- size *= 9;
- break;
- case cgltf_type_mat4:
- size *= 16;
- break;
- case cgltf_type_invalid:
- case cgltf_type_scalar:
- default:
- size *= 1;
- break;
+ return 8 * component_size;
}
-
- return size;
+ else if (type == cgltf_type_mat3 && (component_size == 1 || component_size == 2))
+ {
+ return 12 * component_size;
+ }
+ return component_size * cgltf_num_components(type);
}
static int cgltf_fixup_pointers(cgltf_data* out_data);
@@ -3700,6 +4077,10 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens
{
i = cgltf_parse_json_animations(options, tokens, i + 1, json_chunk, out_data);
}
+ else if (cgltf_json_strcmp(tokens+i, json_chunk, "extras") == 0)
+ {
+ i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_data->extras);
+ }
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
{
++i;
@@ -3743,7 +4124,7 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens
}
else
{
- i = cgltf_skip_json(tokens, i+1);
+ i = cgltf_skip_json(tokens, i + 1);
}
if (i < 0)
@@ -3752,6 +4133,14 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens
}
}
}
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensionsUsed") == 0)
+ {
+ i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_data->extensions_used, &out_data->extensions_used_count);
+ }
+ else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensionsRequired") == 0)
+ {
+ i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_data->extensions_required, &out_data->extensions_required_count);
+ }
else
{
i = cgltf_skip_json(tokens, i + 1);
@@ -3768,7 +4157,7 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens
cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, cgltf_size size, cgltf_data** out_data)
{
- jsmn_parser parser = { 0 };
+ jsmn_parser parser = { 0, 0, 0 };
if (options->json_token_count == 0)
{
@@ -3782,7 +4171,7 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk,
options->json_token_count = token_count;
}
- jsmntok_t* tokens = (jsmntok_t*)options->memory_alloc(options->memory_user_data, sizeof(jsmntok_t) * options->json_token_count);
+ jsmntok_t* tokens = (jsmntok_t*)options->memory_alloc(options->memory_user_data, sizeof(jsmntok_t) * (options->json_token_count + 1));
if (!tokens)
{
@@ -3799,6 +4188,10 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk,
return cgltf_result_invalid_json;
}
+ // this makes sure that we always have an UNDEFINED token at the end of the stream
+ // for invalid JSON inputs this makes sure we don't perform out of bound reads of token data
+ tokens[token_count].type = JSMN_UNDEFINED;
+
cgltf_data* data = (cgltf_data*)options->memory_alloc(options->memory_user_data, sizeof(cgltf_data));
if (!data)
@@ -3827,6 +4220,9 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk,
return cgltf_result_invalid_gltf;
}
+ data->json = (const char*)json_chunk;
+ data->json_size = size;
+
*out_data = data;
return cgltf_result_success;