diff --git a/cgltf.h b/cgltf.h index 3231201..4ea4cda 100644 --- a/cgltf.h +++ b/cgltf.h @@ -128,7 +128,7 @@ typedef enum cgltf_result cgltf_result_io_error, cgltf_result_out_of_memory, cgltf_result_legacy_gltf, - cgltf_result_max_enum + cgltf_result_max_enum } cgltf_result; typedef struct cgltf_memory_options @@ -184,7 +184,7 @@ typedef enum cgltf_component_type cgltf_component_type_r_16u, /* UNSIGNED_SHORT */ cgltf_component_type_r_32u, /* UNSIGNED_INT */ cgltf_component_type_r_32f, /* FLOAT */ - cgltf_component_type_max_enum + cgltf_component_type_max_enum } cgltf_component_type; typedef enum cgltf_type @@ -259,6 +259,11 @@ typedef enum cgltf_data_free_method { cgltf_data_free_method_max_enum } cgltf_data_free_method; +typedef struct cgltf_xmp_json_ld_packet +{ + char* data; +} cgltf_xmp_json_ld_packet; + typedef struct cgltf_extras { cgltf_size start_offset; /* this field is deprecated and will be removed in the future; use data instead */ cgltf_size end_offset; /* this field is deprecated and will be removed in the future; use data instead */ @@ -279,6 +284,7 @@ typedef struct cgltf_buffer void* data; /* loaded by cgltf_load_buffers */ cgltf_data_free_method data_free_method; cgltf_extras extras; + cgltf_xmp_json_ld_packet *xmp_json_ld; cgltf_size extensions_count; cgltf_extension* extensions; } cgltf_buffer; @@ -372,6 +378,7 @@ typedef struct cgltf_image cgltf_buffer_view* buffer_view; char* mime_type; cgltf_extras extras; + cgltf_xmp_json_ld_packet *xmp_json_ld; cgltf_size extensions_count; cgltf_extension* extensions; } cgltf_image; @@ -546,6 +553,7 @@ typedef struct cgltf_material cgltf_bool double_sided; cgltf_bool unlit; cgltf_extras extras; + cgltf_xmp_json_ld_packet *xmp_json_ld; cgltf_size extensions_count; cgltf_extension* extensions; } cgltf_material; @@ -599,6 +607,7 @@ typedef struct cgltf_mesh { char** target_names; cgltf_size target_names_count; cgltf_extras extras; + cgltf_xmp_json_ld_packet *xmp_json_ld; cgltf_size extensions_count; cgltf_extension* extensions; } cgltf_mesh; @@ -677,6 +686,7 @@ struct cgltf_node { cgltf_float scale[3]; cgltf_float matrix[16]; cgltf_extras extras; + cgltf_xmp_json_ld_packet *xmp_json_ld; cgltf_bool has_mesh_gpu_instancing; cgltf_mesh_gpu_instancing mesh_gpu_instancing; cgltf_size extensions_count; @@ -688,6 +698,7 @@ typedef struct cgltf_scene { cgltf_node** nodes; cgltf_size nodes_count; cgltf_extras extras; + cgltf_xmp_json_ld_packet *xmp_json_ld; cgltf_size extensions_count; cgltf_extension* extensions; } cgltf_scene; @@ -717,6 +728,7 @@ typedef struct cgltf_animation { cgltf_animation_channel* channels; cgltf_size channels_count; cgltf_extras extras; + cgltf_xmp_json_ld_packet *xmp_json_ld; cgltf_size extensions_count; cgltf_extension* extensions; } cgltf_animation; @@ -733,6 +745,7 @@ typedef struct cgltf_asset { char* version; char* min_version; cgltf_extras extras; + cgltf_xmp_json_ld_packet *xmp_json_ld; cgltf_size extensions_count; cgltf_extension* extensions; } cgltf_asset; @@ -793,6 +806,9 @@ typedef struct cgltf_data cgltf_extras extras; + cgltf_size xmp_json_ld_packets_count; + cgltf_xmp_json_ld_packet* xmp_json_ld_packets; // just store the packets + cgltf_size data_extensions_count; cgltf_extension* data_extensions; @@ -872,6 +888,7 @@ cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object); cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object); cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object); cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object); +cgltf_size cgltf_xmp_json_ld_packet_index(const cgltf_data* data, const cgltf_xmp_json_ld_packet* object); #ifdef __cplusplus } @@ -951,8 +968,8 @@ static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t #ifndef CGLTF_CONSTS -#define GlbHeaderSize 12 -#define GlbChunkHeaderSize 8 +static const cgltf_size GlbHeaderSize = 12; +static const cgltf_size GlbChunkHeaderSize = 8; static const uint32_t GlbVersion = 2; static const uint32_t GlbMagic = 0x46546C67; static const uint32_t GlbMagicJsonChunk = 0x4E4F534A; @@ -2064,6 +2081,12 @@ void cgltf_free(cgltf_data* data) data->memory.free_func(data->memory.user_data, data->variants); + for (cgltf_size i = 0; i < data->xmp_json_ld_packets_count; ++i) + { + data->memory.free_func(data->memory.user_data, data->xmp_json_ld_packets[i].data); + } + data->memory.free_func(data->memory.user_data, data->xmp_json_ld_packets); + cgltf_free_extensions(data, data->data_extensions, data->data_extensions_count); cgltf_free_extras(data, &data->extras); @@ -2633,6 +2656,12 @@ cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* o return index_count; } +cgltf_size cgltf_xmp_json_ld_packet_index(const cgltf_data* data, const cgltf_xmp_json_ld_packet* object) +{ + assert(object && (cgltf_size)(object - data->xmp_json_ld_packets) < data->xmp_json_ld_packets_count); + return (cgltf_size)(object - data->xmp_json_ld_packets); +} + #define CGLTF_ERROR_JSON -1 #define CGLTF_ERROR_NOMEM -2 #define CGLTF_ERROR_LEGACY -3 @@ -2923,6 +2952,15 @@ static int cgltf_parse_json_extras(cgltf_options* options, jsmntok_t const* toke return i; } +static int cgltf_parse_xmp_json_lds(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_xmp_json_ld_packet** xmp_json_ld) +{ + i = cgltf_skip_json(tokens, i); // we do not care of the key 'packet' + int index = cgltf_json_to_int(tokens + i, json_chunk); + *xmp_json_ld = CGLTF_PTRINDEX(cgltf_xmp_json_ld_packet, index); + i = cgltf_skip_json(tokens, i); + return i; +} + static int cgltf_parse_json_unprocessed_extension(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extension* out_extension) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_STRING); @@ -3409,7 +3447,38 @@ static int cgltf_parse_json_mesh(cgltf_options* options, jsmntok_t const* tokens } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_mesh->extensions_count, &out_mesh->extensions); + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(out_mesh->extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + ++i; + out_mesh->extensions_count = 0; + out_mesh->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + + for (int j = 0; j < extensions_size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_xmp_json_ld") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + i = cgltf_parse_xmp_json_lds(tokens, i + 1, json_chunk, &(out_mesh->xmp_json_ld)); + } + else + { + i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_mesh->extensions[out_mesh->extensions_count++])); + } + if (i < 0) + { + return i; + } + } + } else { @@ -4370,7 +4439,39 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_image->extensions_count, &out_image->extensions); + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(out_image->extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + ++i; + out_image->extensions_count = 0; + out_image->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + + + for (int j = 0; j < extensions_size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_xmp_json_ld") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + i = cgltf_parse_xmp_json_lds(tokens, i + 1, json_chunk, &(out_image->xmp_json_ld)); + } + else + { + i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_image->extensions[out_image->extensions_count++])); + } + if (i < 0) + { + return i; + } + } + } else { @@ -4498,8 +4599,8 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok int extensions_size = tokens[i].size; ++i; + out_texture->extensions_count = 0; out_texture->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); - out_texture->extensions_count = 0; if (!out_texture->extensions) { @@ -4728,6 +4829,11 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to out_material->has_anisotropy = 1; i = cgltf_parse_json_anisotropy(options, tokens, i + 1, json_chunk, &out_material->anisotropy); } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_xmp_json_ld") == 0) { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + i = cgltf_parse_xmp_json_lds(tokens, i + 1, json_chunk, &(out_material->xmp_json_ld)); + } else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_dispersion") == 0) { out_material->has_dispersion = 1; @@ -5695,6 +5801,12 @@ static int cgltf_parse_json_node(cgltf_options* options, jsmntok_t const* tokens out_node->has_mesh_gpu_instancing = 1; i = cgltf_parse_json_mesh_gpu_instancing(options, tokens, i + 1, json_chunk, &out_node->mesh_gpu_instancing); } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_xmp_json_ld") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + i = cgltf_parse_xmp_json_lds(tokens, i + 1, json_chunk, &(out_node->xmp_json_ld)); + } else { i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_node->extensions[out_node->extensions_count++])); @@ -5774,7 +5886,37 @@ static int cgltf_parse_json_scene(cgltf_options* options, jsmntok_t const* token } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_scene->extensions_count, &out_scene->extensions); + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(out_scene->extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + ++i; + out_scene->extensions_count = 0; + out_scene->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + + for (int j = 0; j < extensions_size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_xmp_json_ld") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + i = cgltf_parse_xmp_json_lds(tokens, i + 1, json_chunk, &(out_scene->xmp_json_ld)); + } + else + { + i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_scene->extensions[out_scene->extensions_count++])); + } + if (i < 0) + { + return i; + } + } } else { @@ -6018,7 +6160,37 @@ static int cgltf_parse_json_animation(cgltf_options* options, jsmntok_t const* t } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_animation->extensions_count, &out_animation->extensions); + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(out_animation->extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + ++i; + out_animation->extensions_count = 0; + out_animation->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + + for (int j = 0; j < extensions_size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_xmp_json_ld") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + i = cgltf_parse_xmp_json_lds(tokens, i + 1, json_chunk, &(out_animation->xmp_json_ld)); + } + else + { + i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_animation->extensions[out_animation->extensions_count++])); + } + if (i < 0) + { + return i; + } + } } else { @@ -6138,7 +6310,37 @@ static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* token } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_asset->extensions_count, &out_asset->extensions); + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(out_asset->extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + ++i; + out_asset->extensions_count = 0; + out_asset->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + + for (int j = 0; j < extensions_size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_xmp_json_ld") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + i = cgltf_parse_xmp_json_lds(tokens, i + 1, json_chunk, &(out_asset->xmp_json_ld)); + } + else + { + i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_asset->extensions[out_asset->extensions_count++])); + } + if (i < 0) + { + return i; + } + } } else { @@ -6159,6 +6361,43 @@ static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* token return i; } +static int cgltf_parse_xmp_json_ld_packet(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_xmp_json_ld_packet* packet) +{ + size_t start = tokens[i].start; + size_t size = tokens[i].end - start; + packet->data = (char*)options->memory.alloc_func(options->memory.user_data, size + 1); + if (!packet->data) + { + return CGLTF_ERROR_NOMEM; + } + strncpy(packet->data, (const char*)json_chunk + start, size); + packet->data[size] = '\0'; + + i = cgltf_skip_json(tokens, i); + return i; +} + +static int cgltf_parse_xmp_json_ld_packets(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_material_variant), + (void**)&out_data->xmp_json_ld_packets, &out_data->xmp_json_ld_packets_count); + + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->xmp_json_ld_packets_count; ++j) + { + i = cgltf_parse_xmp_json_ld_packet(options, tokens, i, json_chunk, &out_data->xmp_json_ld_packets[j]); + if (i < 0) + { + return i; + } + } + return i; +} + cgltf_size cgltf_num_components(cgltf_type type) { switch (type) { @@ -6373,6 +6612,33 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens } } } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_xmp_json_ld") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + int data_size = tokens[i].size; + ++i; + + for (int m = 0; m < data_size; ++m) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "packets") == 0) + { + i = cgltf_parse_xmp_json_ld_packets(options, tokens, i + 1, json_chunk, out_data); + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + if (i < 0) + { + return i; + } + } + } else { i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_data->data_extensions[out_data->data_extensions_count++])); @@ -6521,6 +6787,7 @@ static int cgltf_fixup_pointers(cgltf_data* data) CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].mappings[k].material, data->materials, data->materials_count); } } + CGLTF_PTRFIXUP(data->meshes[i].xmp_json_ld, data->xmp_json_ld_packets, data->xmp_json_ld_packets_count); } for (cgltf_size i = 0; i < data->accessors_count; ++i) @@ -6554,6 +6821,7 @@ static int cgltf_fixup_pointers(cgltf_data* data) for (cgltf_size i = 0; i < data->images_count; ++i) { CGLTF_PTRFIXUP(data->images[i].buffer_view, data->buffer_views, data->buffer_views_count); + CGLTF_PTRFIXUP(data->images[i].xmp_json_ld, data->xmp_json_ld_packets, data->xmp_json_ld_packets_count); } for (cgltf_size i = 0; i < data->materials_count; ++i) @@ -6586,6 +6854,7 @@ static int cgltf_fixup_pointers(cgltf_data* data) CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_thickness_texture.texture, data->textures, data->textures_count); CGLTF_PTRFIXUP(data->materials[i].anisotropy.anisotropy_texture.texture, data->textures, data->textures_count); + CGLTF_PTRFIXUP(data->materials[i].xmp_json_ld, data->xmp_json_ld_packets, data->xmp_json_ld_packets_count); } for (cgltf_size i = 0; i < data->buffer_views_count; ++i) @@ -6635,6 +6904,8 @@ static int cgltf_fixup_pointers(cgltf_data* data) CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.attributes[m].data, data->accessors, data->accessors_count); } } + + CGLTF_PTRFIXUP(data->nodes[i].xmp_json_ld, data->xmp_json_ld_packets, data->xmp_json_ld_packets_count); } for (cgltf_size i = 0; i < data->scenes_count; ++i) @@ -6648,6 +6919,8 @@ static int cgltf_fixup_pointers(cgltf_data* data) return CGLTF_ERROR_JSON; } } + + CGLTF_PTRFIXUP(data->scenes[i].xmp_json_ld, data->xmp_json_ld_packets, data->xmp_json_ld_packets_count); } CGLTF_PTRFIXUP(data->scene, data->scenes, data->scenes_count); @@ -6665,8 +6938,12 @@ static int cgltf_fixup_pointers(cgltf_data* data) CGLTF_PTRFIXUP_REQ(data->animations[i].channels[j].sampler, data->animations[i].samplers, data->animations[i].samplers_count); CGLTF_PTRFIXUP(data->animations[i].channels[j].target_node, data->nodes, data->nodes_count); } + + CGLTF_PTRFIXUP(data->animations[i].xmp_json_ld, data->xmp_json_ld_packets, data->xmp_json_ld_packets_count); } + CGLTF_PTRFIXUP(data->asset.xmp_json_ld, data->xmp_json_ld_packets, data->xmp_json_ld_packets_count); + return 0; } diff --git a/cgltf_write.h b/cgltf_write.h index d5615cd..ee442f3 100644 --- a/cgltf_write.h +++ b/cgltf_write.h @@ -87,6 +87,7 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si #define CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE (1 << 15) #define CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY (1 << 16) #define CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION (1 << 17) +#define CGLTF_EXTENSION_FLAG_XMP_JSON_LD (1 << 18) typedef struct { char* buffer; @@ -179,8 +180,8 @@ typedef struct { cgltf_write_line(context, "}"); } #ifndef CGLTF_CONSTS -#define GlbHeaderSize 12 -#define GlbChunkHeaderSize 8 +static const cgltf_size GlbHeaderSize = 12; +static const cgltf_size GlbChunkHeaderSize = 8; static const uint32_t GlbVersion = 2; static const uint32_t GlbMagic = 0x46546C67; static const uint32_t GlbMagicJsonChunk = 0x4E4F534A; @@ -463,7 +464,26 @@ static void cgltf_write_asset(cgltf_write_context* context, const cgltf_asset* a cgltf_write_strprop(context, "generator", asset->generator); cgltf_write_strprop(context, "version", asset->version); cgltf_write_strprop(context, "min_version", asset->min_version); - cgltf_write_extras(context, &asset->extras); + + bool has_extension = (asset->xmp_json_ld != nullptr); + + if(has_extension) + { + cgltf_write_line(context, "\"extensions\": {"); + } + + if (asset->xmp_json_ld) + { + cgltf_write_line(context, "\"KHR_xmp_json_ld\": {"); + CGLTF_WRITE_IDXPROP("packet", asset->xmp_json_ld, context->data->xmp_json_ld_packets); + cgltf_write_line(context, "}"); + } + + if (has_extension) + cgltf_write_line(context, "}"); + + + cgltf_write_extras(context, &asset->extras); cgltf_write_line(context, "}"); } @@ -566,6 +586,23 @@ static void cgltf_write_mesh(cgltf_write_context* context, const cgltf_mesh* mes cgltf_write_floatarrayprop(context, "weights", mesh->weights, mesh->weights_count); } + bool has_extension = (mesh->xmp_json_ld != nullptr); + if (has_extension) + { + cgltf_write_line(context, "\"extensions\": {"); + } + + if(mesh->xmp_json_ld) { + cgltf_write_line(context, "\"KHR_xmp_json_ld\": {"); + CGLTF_WRITE_IDXPROP("packet", mesh->xmp_json_ld, context->data->xmp_json_ld_packets); + cgltf_write_line(context, "}"); + } + + if (has_extension) + { + cgltf_write_line(context, "}"); + } + cgltf_write_extras(context, &mesh->extras); cgltf_write_line(context, "}"); } @@ -660,6 +697,11 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY; } + if (material->xmp_json_ld) + { + context->extension_flags |= CGLTF_EXTENSION_FLAG_XMP_JSON_LD; + } + if (material->has_dispersion) { context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION; @@ -680,7 +722,7 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater cgltf_write_line(context, "}"); } - if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence || material->has_anisotropy || material->has_dispersion) + if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence || material->has_anisotropy || material->has_dispersion || material->xmp_json_ld) { cgltf_write_line(context, "\"extensions\": {"); if (material->has_clearcoat) @@ -800,6 +842,12 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater CGLTF_WRITE_TEXTURE_INFO("anisotropyTexture", params->anisotropy_texture); cgltf_write_line(context, "}"); } + if (material->xmp_json_ld) + { + cgltf_write_line(context, "\"KHR_xmp_json_ld\": {"); + CGLTF_WRITE_IDXPROP("packet", material->xmp_json_ld, context->data->xmp_json_ld_packets); + cgltf_write_line(context, "}"); + } if (material->has_dispersion) { cgltf_write_line(context, "\"KHR_materials_dispersion\": {"); @@ -829,7 +877,25 @@ static void cgltf_write_image(cgltf_write_context* context, const cgltf_image* i cgltf_write_strprop(context, "uri", image->uri); CGLTF_WRITE_IDXPROP("bufferView", image->buffer_view, context->data->buffer_views); cgltf_write_strprop(context, "mimeType", image->mime_type); - cgltf_write_extras(context, &image->extras); + + bool has_extension = (image->xmp_json_ld != nullptr); + + if(has_extension) + { + cgltf_write_line(context, "\"extensions\": {"); + } + + if (image->xmp_json_ld) + { + cgltf_write_line(context, "\"KHR_xmp_json_ld\": {"); + CGLTF_WRITE_IDXPROP("packet", image->xmp_json_ld, context->data->xmp_json_ld_packets); + cgltf_write_line(context, "}"); + } + + if (has_extension) + cgltf_write_line(context, "}"); + + cgltf_write_extras(context, &image->extras); cgltf_write_line(context, "}"); } @@ -955,7 +1021,25 @@ static void cgltf_write_animation(cgltf_write_context* context, const cgltf_anim } cgltf_write_line(context, "]"); } - cgltf_write_extras(context, &animation->extras); + + bool has_extension = (animation->xmp_json_ld != nullptr); + + if(has_extension) + { + cgltf_write_line(context, "\"extensions\": {"); + } + + if (animation->xmp_json_ld) + { + cgltf_write_line(context, "\"KHR_xmp_json_ld\": {"); + CGLTF_WRITE_IDXPROP("packet", animation->xmp_json_ld, context->data->xmp_json_ld_packets); + cgltf_write_line(context, "}"); + } + + if (has_extension) + cgltf_write_line(context, "}"); + + cgltf_write_extras(context, &animation->extras); cgltf_write_line(context, "}"); } @@ -998,7 +1082,7 @@ static void cgltf_write_node(cgltf_write_context* context, const cgltf_node* nod CGLTF_WRITE_IDXPROP("skin", node->skin, context->data->skins); } - bool has_extension = node->light || (node->has_mesh_gpu_instancing && node->mesh_gpu_instancing.attributes_count > 0); + bool has_extension = node->light || (node->has_mesh_gpu_instancing && node->mesh_gpu_instancing.attributes_count > 0) || node->xmp_json_ld; if(has_extension) cgltf_write_line(context, "\"extensions\": {"); @@ -1030,6 +1114,13 @@ static void cgltf_write_node(cgltf_write_context* context, const cgltf_node* nod cgltf_write_line(context, "}"); } + if (node->xmp_json_ld) + { + cgltf_write_line(context, "\"KHR_xmp_json_ld\": {"); + CGLTF_WRITE_IDXPROP("packet", node->xmp_json_ld, context->data->xmp_json_ld_packets); + cgltf_write_line(context, "}"); + } + if (has_extension) cgltf_write_line(context, "}"); @@ -1052,6 +1143,24 @@ static void cgltf_write_scene(cgltf_write_context* context, const cgltf_scene* s cgltf_write_line(context, "{"); cgltf_write_strprop(context, "name", scene->name); CGLTF_WRITE_IDXARRPROP("nodes", scene->nodes_count, scene->nodes, context->data->nodes); + + bool has_extension = (scene->xmp_json_ld != nullptr); + + if(has_extension) + { + cgltf_write_line(context, "\"extensions\": {"); + } + + if (scene->xmp_json_ld) + { + cgltf_write_line(context, "\"KHR_xmp_json_ld\": {"); + CGLTF_WRITE_IDXPROP("packet", scene->xmp_json_ld, context->data->xmp_json_ld_packets); + cgltf_write_line(context, "}"); + } + + if (has_extension) + cgltf_write_line(context, "}"); + cgltf_write_extras(context, &scene->extras); cgltf_write_line(context, "}"); } @@ -1173,6 +1282,20 @@ static void cgltf_write_variant(cgltf_write_context* context, const cgltf_materi cgltf_write_line(context, "}"); } +static void cgltf_write_xmp_json_ld(cgltf_write_context* context, const cgltf_xmp_json_ld_packet* xmp_json_ld_packet) +{ + if (xmp_json_ld_packet == nullptr) + { + return; + } + + context->extension_flags |= CGLTF_EXTENSION_FLAG_XMP_JSON_LD; + + cgltf_write_indent(context); + CGLTF_SPRINTF("%s", xmp_json_ld_packet->data); + context->needs_comma = 1; +} + static void cgltf_write_glb(FILE* file, const void* json_buf, const cgltf_size json_size, const void* bin_buf, const cgltf_size bin_size) { char header[GlbHeaderSize]; @@ -1292,6 +1415,9 @@ static void cgltf_write_extensions(cgltf_write_context* context, uint32_t extens if (extension_flags & CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING) { cgltf_write_stritem(context, "EXT_mesh_gpu_instancing"); } + if (extension_flags & CGLTF_EXTENSION_FLAG_XMP_JSON_LD) { + cgltf_write_stritem(context, "KHR_xmp_json_ld"); + } if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION) { cgltf_write_stritem(context, "KHR_materials_dispersion"); } @@ -1451,7 +1577,9 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si cgltf_write_line(context, "]"); } - if (data->lights_count > 0 || data->variants_count > 0) + if (data->lights_count > 0 || + data->variants_count > 0 || + data->xmp_json_ld_packets_count > 0) { cgltf_write_line(context, "\"extensions\": {"); @@ -1479,6 +1607,18 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si cgltf_write_line(context, "}"); } + if (data->xmp_json_ld_packets_count) + { + cgltf_write_line(context, "\"KHR_xmp_json_ld\": {"); + cgltf_write_line(context, "\"packets\": ["); + for (cgltf_size i = 0; i < data->xmp_json_ld_packets_count; ++i) + { + cgltf_write_xmp_json_ld(context, data->xmp_json_ld_packets + i); + } + cgltf_write_line(context, "]"); + cgltf_write_line(context, "}"); + } + cgltf_write_line(context, "}"); }