diff --git a/cgltf.h b/cgltf.h index aa8fb3f..540f972 100644 --- a/cgltf.h +++ b/cgltf.h @@ -227,6 +227,7 @@ typedef enum cgltf_animation_path_type { cgltf_animation_path_type_rotation, cgltf_animation_path_type_scale, cgltf_animation_path_type_weights, + cgltf_animation_path_type_pointer, cgltf_animation_path_type_max_enum } cgltf_animation_path_type; @@ -733,6 +734,7 @@ typedef struct cgltf_animation_channel { cgltf_animation_sampler* sampler; cgltf_node* target_node; cgltf_animation_path_type target_path; + char* target_pointer; cgltf_extras extras; cgltf_size extensions_count; cgltf_extension* extensions; @@ -1772,7 +1774,7 @@ cgltf_result cgltf_validate(cgltf_data* data) { cgltf_animation_channel* channel = &data->animations[i].channels[j]; - if (!channel->target_node) + if (!channel->target_node && channel->target_path != cgltf_animation_path_type_pointer) { continue; } @@ -2087,6 +2089,7 @@ void cgltf_free(cgltf_data* data) for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j) { + data->memory.free_func(data->memory.user_data, data->animations[i].channels[j].target_pointer); cgltf_free_extensions(data, data->animations[i].channels[j].extensions, data->animations[i].channels[j].extensions_count); cgltf_free_extras(data, &data->animations[i].channels[j].extras); } @@ -4338,7 +4341,7 @@ static int cgltf_parse_json_diffuse_transmission(cgltf_options* options, jsmntok // Defaults cgltf_fill_float_array(out_diff_transmission->diffuse_transmission_color_factor, 3, 1.0f); out_diff_transmission->diffuse_transmission_factor = 0.f; - + for (int j = 0; j < size; ++j) { CGLTF_CHECK_KEY(tokens[i]); @@ -6017,6 +6020,34 @@ static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t return i; } +static int cgltf_parse_json_animation_pointer(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation_channel* out_channel) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + int size = tokens[i].size; + ++i; + + for (int j = 0; j < size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "pointer") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_channel->target_pointer); + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + 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; @@ -6073,6 +6104,10 @@ static int cgltf_parse_json_animation_channel(cgltf_options* options, jsmntok_t { out_channel->target_path = cgltf_animation_path_type_weights; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "pointer") == 0) + { + out_channel->target_path = cgltf_animation_path_type_pointer; + } ++i; } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) @@ -6081,7 +6116,42 @@ static int cgltf_parse_json_animation_channel(cgltf_options* options, jsmntok_t } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_channel->extensions_count, &out_channel->extensions); + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if (out_channel->extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + ++i; + out_channel->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + out_channel->extensions_count = 0; + + if (!out_channel->extensions) + { + return CGLTF_ERROR_NOMEM; + } + + for (int k = 0; k < extensions_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_animation_pointer") == 0) + { + i = cgltf_parse_json_animation_pointer(options, tokens, i + 1, json_chunk, out_channel); + } + else + { + i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_channel->extensions[out_channel->extensions_count++])); + } + + if (i < 0) + { + return i; + } + } } else { diff --git a/cgltf_write.h b/cgltf_write.h index dd3f82c..8f85cfd 100644 --- a/cgltf_write.h +++ b/cgltf_write.h @@ -89,6 +89,7 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si #define CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION (1 << 17) #define CGLTF_EXTENSION_FLAG_TEXTURE_WEBP (1 << 18) #define CGLTF_EXTENSION_FLAG_MATERIALS_DIFFUSE_TRANSMISSION (1 << 19) +#define CGLTF_EXTENSION_FLAG_ANIMATION_POINTER (1 << 20) typedef struct { char* buffer; @@ -906,6 +907,8 @@ static const char* cgltf_write_str_path_type(cgltf_animation_path_type path_type return "scale"; case cgltf_animation_path_type_weights: return "weights"; + case cgltf_animation_path_type_pointer: + return "pointer"; default: break; } @@ -955,6 +958,21 @@ static void cgltf_write_animation_channel(cgltf_write_context* context, const cg cgltf_write_line(context, "\"target\": {"); CGLTF_WRITE_IDXPROP("node", animation_channel->target_node, context->data->nodes); cgltf_write_path_type(context, "path", animation_channel->target_path); + if (animation_channel->target_path == cgltf_animation_path_type_pointer && + animation_channel->target_pointer != NULL) + { + context->extension_flags |= CGLTF_EXTENSION_FLAG_ANIMATION_POINTER; + cgltf_write_line(context, "\"extensions\": {"); + cgltf_write_line(context, "\"KHR_animation_pointer\": {"); + cgltf_write_strprop(context, "pointer", animation_channel->target_pointer); + cgltf_write_line(context, "}"); + cgltf_write_line(context, "}"); + } + else + { + // Can't use the pointer enum with a null json pointer. + assert(animation_channel->target_path != cgltf_animation_path_type_pointer); + } cgltf_write_line(context, "}"); cgltf_write_extras(context, &animation_channel->extras); cgltf_write_line(context, "}"); @@ -1329,6 +1347,9 @@ static void cgltf_write_extensions(cgltf_write_context* context, uint32_t extens if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION) { cgltf_write_stritem(context, "KHR_materials_dispersion"); } + if (extension_flags & CGLTF_EXTENSION_FLAG_ANIMATION_POINTER) { + cgltf_write_stritem(context, "KHR_animation_pointer"); + } } cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data)