From b553b8ca1d3ec784e81e91e0b533b21df83c8aac Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Sat, 16 Sep 2023 12:21:39 +0300 Subject: [PATCH] Animation crash debugging --- src/modules/.clang-tidy | 44 ++ src/modules/character/animation_system.cpp | 584 +++++++++++++++------ src/modules/character/animation_system.h | 203 +++++-- 3 files changed, 610 insertions(+), 221 deletions(-) create mode 100644 src/modules/.clang-tidy diff --git a/src/modules/.clang-tidy b/src/modules/.clang-tidy new file mode 100644 index 0000000..caabeb9 --- /dev/null +++ b/src/modules/.clang-tidy @@ -0,0 +1,44 @@ +--- +Checks: 'clang-diagnostic-*,clang-analyzer-*,-*,modernize-redundant-void-arg,modernize-use-bool-literals,modernize-use-nullptr,readability-braces-around-statements' +WarningsAsErrors: '' +HeaderFilterRegex: '.*' +AnalyzeTemporaryDtors: false +FormatStyle: none +CheckOptions: +CheckOptions: + - key: cert-dcl16-c.NewSuffixes + value: 'L;LL;LU;LLU' + - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField + value: '0' + - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors + value: '1' + - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic + value: '1' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' + - key: modernize-loop-convert.MaxCopySize + value: '16' + - key: modernize-loop-convert.MinConfidence + value: reasonable + - key: modernize-loop-convert.NamingStyle + value: CamelCase + - key: modernize-pass-by-value.IncludeStyle + value: llvm + - key: modernize-replace-auto-ptr.IncludeStyle + value: llvm + - key: modernize-use-bool-literals.IgnoreMacros + value: '0' + - key: modernize-use-default-member-init.IgnoreMacros + value: '0' + - key: modernize-use-default-member-init.UseAssignment + value: '1' + - key: modernize-use-nullptr.NullMacros + value: 'NULL' + - key: readability-braces-around-statements.ShortStatementLines + value: '0' +... + diff --git a/src/modules/character/animation_system.cpp b/src/modules/character/animation_system.cpp index 71b0700..5c1daed 100644 --- a/src/modules/character/animation_system.cpp +++ b/src/modules/character/animation_system.cpp @@ -1,32 +1,37 @@ +#include #include #include +#include + #include "animation_system.h" + /* private functions */ namespace ECS { -static void _animation_process_animation(struct AnimationPlayerData *player, AnimationData *p_anim, - float p_time, float p_delta, float p_interp, +static void _animation_process_animation(struct AnimationPlayerData *player, + AnimationData *p_anim, float p_time, float p_delta, float p_interp, bool p_is_current = true, bool p_seeked = false, bool p_started = false); static void _ensure_node_caches(struct AnimationPlayerData *player, AnimationData *p_anim, Node *p_root_override = NULL); static void _animation_process_data(struct AnimationPlayerData *player, - PlaybackData &cd, float p_delta, float p_blend, bool p_seeked, bool p_started); -static void _animation_process2(struct AnimationPlayerData *player, - float p_delta, bool p_started); + PlaybackData &cd, float p_delta, float p_blend, bool p_seeked, + bool p_started); +static void _animation_process2( + struct AnimationPlayerData *player, float p_delta, bool p_started); static void _animation_update_transforms(struct AnimationPlayerData *player); -static void _animation_process(struct AnimationPlayerData *player, - float p_delta); +static void _animation_process( + struct AnimationPlayerData *player, float p_delta); // static void _node_removed(struct AnimationPlayerData *player, // Node *p_node); static void _stop_playing_caches(struct AnimationPlayerData *player); static void _animation_changed(struct AnimationPlayerData *player); -static void _ref_anim(struct AnimationPlayerData *player, - const Ref &p_anim); -static void _unref_anim(struct AnimationPlayerData *player, - const Ref &p_anim); -static void _set_process(struct AnimationPlayerData *player, - bool p_process, bool p_force = false); +static void _ref_anim( + struct AnimationPlayerData *player, const Ref &p_anim); +static void _unref_anim( + struct AnimationPlayerData *player, const Ref &p_anim); +static void _set_process(struct AnimationPlayerData *player, bool p_process, + bool p_force = false); /* protected functions (need redesign) */ #if 0 bool _set(const StringName &p_name, const Variant &p_value); @@ -38,8 +43,7 @@ static void _bind_methods(); #endif } //namespace ECS void ECS::play(struct ECS::AnimationPlayerData *player, - const StringName &p_name, - float p_custom_blend, float p_custom_scale, + const StringName &p_name, float p_custom_blend, float p_custom_scale, bool p_from_end) { StringName name = p_name; @@ -48,7 +52,8 @@ void ECS::play(struct ECS::AnimationPlayerData *player, name = player->playback.assigned; } - ERR_FAIL_COND_MSG(!player->animation_set.has(name), "Animation not found: " + name + "."); + ERR_FAIL_COND_MSG(!player->animation_set.has(name), + "Animation not found: " + name + "."); Playback &c = player->playback; @@ -77,7 +82,8 @@ void ECS::play(struct ECS::AnimationPlayerData *player, } } - if (p_custom_blend < 0 && blend_time == 0 && player->default_blend_time) { + if (p_custom_blend < 0 && blend_time == 0 && + player->default_blend_time) { blend_time = player->default_blend_time; } if (blend_time > 0) { @@ -95,13 +101,20 @@ void ECS::play(struct ECS::AnimationPlayerData *player, c.current.from = &player->animation_set[name]; if (c.assigned != name) { // reset - c.current.pos = p_from_end ? c.current.from->animation->get_length() : 0; + c.current.pos = p_from_end + ? c.current.from->animation->get_length() + : 0; } else { if (p_from_end && c.current.pos == 0) { - // Animation reset BUT played backwards, set position to the end - c.current.pos = c.current.from->animation->get_length(); - } else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) { - // Animation resumed but already ended, set position to the beginning + // Animation reset BUT played backwards, set position + // to the end + c.current.pos = + c.current.from->animation->get_length(); + } else if (!p_from_end && + c.current.pos == + c.current.from->animation->get_length()) { + // Animation resumed but already ended, set position to + // the beginning c.current.pos = 0; } } @@ -114,7 +127,8 @@ void ECS::play(struct ECS::AnimationPlayerData *player, if (!player->end_reached) { player->queued.clear(); } - _set_process(player, true); // always process when starting an animation + _set_process( + player, true); // always process when starting an animation player->playing = true; #if 0 @@ -134,7 +148,12 @@ static void ECS::_ensure_node_caches(struct ECS::AnimationPlayerData *player, AnimationData *p_anim, Node *p_root_override) { // Already cached? - if (p_anim->node_cache.size() == p_anim->animation->get_track_count()) { + assert(p_anim->animation.is_valid()); + flecs::log::trace("cached tracks %d", p_anim->node_cache_size); + flecs::log::trace( + "animation tracks %d", p_anim->animation->get_track_count()); + flecs::log::trace("animation %p", p_anim->animation.ptr()); + if (p_anim->node_cache_size == p_anim->animation->get_track_count()) { return; } #if 0 @@ -145,13 +164,14 @@ static void ECS::_ensure_node_caches(struct ECS::AnimationPlayerData *player, Animation *a = p_anim->animation.operator->(); - p_anim->node_cache.resize(a->get_track_count()); + p_anim->node_cache_size = a->get_track_count(); for (int i = 0; i < a->get_track_count(); i++) { - p_anim->node_cache.write[i] = NULL; + p_anim->node_cache[i] = NULL; RES resource; Vector leftover_path; /* handle entities here instead */ + print_line("TRACK: " + itos(i)); #if 0 Node *child = parent->get_node_and_resource(a->track_get_path(i), resource, leftover_path); ERR_CONTINUE_MSG(!child, "On Animation: '" + p_anim->name + "', couldn't resolve track: '" + String(a->track_get_path(i)) + "'."); // couldn't find the child node @@ -159,8 +179,13 @@ static void ECS::_ensure_node_caches(struct ECS::AnimationPlayerData *player, #endif int bone_idx = -1; int id = -1; /* supposed to be object id but... */ + NodePath np = a->track_get_path(i); + String vpath = np; + print_line("path: " + vpath); - if (a->track_get_path(i).get_subname_count() == 1 /* && Object::cast_to(child) */) { + if (!np.is_empty() && + np.get_subname_count() == + 1 /* && Object::cast_to(child) */) { /* use entities */ #if 0 Skeleton *sk = Object::cast_to(child); @@ -182,11 +207,15 @@ static void ECS::_ensure_node_caches(struct ECS::AnimationPlayerData *player, ECS::TrackNodeCacheKey key; key.id = id; key.bone_idx = bone_idx; + String path = a->track_get_path(i); + print_line("TRACK: " + itos(i) + + " BONE IDX: " + itos(bone_idx) + " ID: " + itos(id) + + " PATH: " + path); if (!player->node_cache_map.has(key)) player->node_cache_map[key] = ECS::TrackNodeCache(); - p_anim->node_cache.write[i] = &player->node_cache_map[key]; + p_anim->node_cache[i] = &player->node_cache_map[key]; p_anim->node_cache[i]->path = a->track_get_path(i); #if 0 p_anim->node_cache[i]->node = child; @@ -204,20 +233,28 @@ static void ECS::_ensure_node_caches(struct ECS::AnimationPlayerData *player, p_anim->node_cache[i]->skeleton = Object::cast_to(child); #endif if (true /* || p_anim->node_cache[i]->skeleton */) { - if (a->track_get_path(i).get_subname_count() == 1) { - StringName bone_name = a->track_get_path(i).get_subname(0); + if (a->track_get_path(i).get_subname_count() == + 1) { + StringName bone_name = + a->track_get_path(i) + .get_subname(0); /* use entities */ #if 0 p_anim->node_cache[i]->bone_idx = p_anim->node_cache[i]->skeleton->find_bone(bone_name); #endif - if (p_anim->node_cache[i]->bone_idx < 0) { - // broken track (nonexistent bone) + if (p_anim->node_cache[i]->bone_idx < + 0) { + // broken track (nonexistent + // bone) #if 0 p_anim->node_cache[i]->skeleton = nullptr; p_anim->node_cache[i]->spatial = nullptr; #endif - ERR_CONTINUE(p_anim->node_cache[i]->bone_idx < 0); + ERR_CONTINUE( + p_anim->node_cache[i] + ->bone_idx < + 0); } } else { #if 0 @@ -229,7 +266,9 @@ static void ECS::_ensure_node_caches(struct ECS::AnimationPlayerData *player, } if (a->track_get_type(i) == Animation::TYPE_VALUE) { - if (!p_anim->node_cache[i]->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) { + if (!p_anim->node_cache[i]->property_anim.has( + a->track_get_path(i) + .get_concatenated_subnames())) { TrackNodeCache::PropertyAnim pa; pa.subpath = leftover_path; #if 0 @@ -237,12 +276,18 @@ static void ECS::_ensure_node_caches(struct ECS::AnimationPlayerData *player, #endif pa.special = SP_NONE; pa.owner = p_anim->node_cache[i]; - p_anim->node_cache[i]->property_anim[a->track_get_path(i).get_concatenated_subnames()] = pa; + p_anim->node_cache[i]->property_anim + [a->track_get_path(i) + .get_concatenated_subnames()] = + pa; } } - if (a->track_get_type(i) == Animation::TYPE_BEZIER && leftover_path.size()) { - if (!p_anim->node_cache[i]->bezier_anim.has(a->track_get_path(i).get_concatenated_subnames())) { + if (a->track_get_type(i) == Animation::TYPE_BEZIER && + leftover_path.size()) { + if (!p_anim->node_cache[i]->bezier_anim.has( + a->track_get_path(i) + .get_concatenated_subnames())) { TrackNodeCache::BezierAnim ba; ba.bezier_property = leftover_path; #if 0 @@ -250,28 +295,32 @@ static void ECS::_ensure_node_caches(struct ECS::AnimationPlayerData *player, #endif ba.owner = p_anim->node_cache[i]; - p_anim->node_cache[i]->bezier_anim[a->track_get_path(i).get_concatenated_subnames()] = ba; + p_anim->node_cache[i]->bezier_anim + [a->track_get_path(i) + .get_concatenated_subnames()] = + ba; } } } } -static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *player, ECS::AnimationData *p_anim, - float p_time, float p_delta, float p_interp, - bool p_is_current, bool p_seeked, - bool p_started) +static void ECS::_animation_process_animation( + struct ECS::AnimationPlayerData *player, ECS::AnimationData *p_anim, + float p_time, float p_delta, float p_interp, bool p_is_current, + bool p_seeked, bool p_started) { _ensure_node_caches(player, p_anim); - ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count()); + ERR_FAIL_COND(p_anim->node_cache_size != + p_anim->animation->get_track_count()); - Animation *a = p_anim->animation.operator->(); + Animation *a = p_anim->animation.ptr(); #if 0 bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint(); #endif for (int i = 0; i < a->get_track_count(); i++) { - // If an animation changes this animation (or it animates itself) - // we need to recreate our animation cache - if (p_anim->node_cache.size() != a->get_track_count()) { + // If an animation changes this animation (or it animates + // itself) we need to recreate our animation cache + if (p_anim->node_cache_size != a->get_track_count()) { _ensure_node_caches(player, p_anim); } @@ -284,7 +333,7 @@ static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *p if (!a->track_is_enabled(i)) { continue; // do nothing if the track is disabled } - + flecs::log::trace("track keys: %d", i); if (a->track_get_key_count(i) == 0) { continue; // do nothing if track is empty } @@ -300,25 +349,39 @@ static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *p Quat rot; Vector3 scale; - Error err = a->transform_track_interpolate(i, p_time, &loc, &rot, &scale); - //ERR_CONTINUE(err!=OK); //used for testing, should be removed + Error err = a->transform_track_interpolate( + i, p_time, &loc, &rot, &scale); + //ERR_CONTINUE(err!=OK); //used for testing, + //should be removed if (err != OK) { continue; } if (nc->accum_pass != player->accum_pass) { - ERR_CONTINUE(player->cache_update_size >= NODE_CACHE_UPDATE_MAX); - player->cache_update[player->cache_update_size++] = nc; + ERR_CONTINUE( + player->cache_update_size >= + NODE_CACHE_UPDATE_MAX); + player->cache_update + [player->cache_update_size++] = + nc; nc->accum_pass = player->accum_pass; nc->loc_accum = loc; nc->rot_accum = rot; nc->scale_accum = scale; } else { - nc->loc_accum = nc->loc_accum.linear_interpolate(loc, p_interp); - nc->rot_accum = nc->rot_accum.slerp(rot, p_interp); - nc->scale_accum = nc->scale_accum.linear_interpolate(scale, p_interp); + nc->loc_accum = + nc->loc_accum + .linear_interpolate( + loc, p_interp); + nc->rot_accum = nc->rot_accum.slerp( + rot, p_interp); + nc->scale_accum = + nc->scale_accum + .linear_interpolate( + scale, + p_interp); } } break; @@ -328,91 +391,157 @@ static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *p continue; } #endif + //StringName + //property=a->track_get_path(i).get_property(); - //StringName property=a->track_get_path(i).get_property(); - - Map::Element *E = nc->property_anim.find(a->track_get_path(i).get_concatenated_subnames()); - ERR_CONTINUE(!E); //should it continue, or create a new one? + Map::Element + *E = nc->property_anim.find( + a->track_get_path(i) + .get_concatenated_subnames()); + ERR_CONTINUE(!E); //should it continue, or + //create a new one? TrackNodeCache::PropertyAnim *pa = &E->get(); - Animation::UpdateMode update_mode = a->value_track_get_update_mode(i); + Animation::UpdateMode update_mode = + a->value_track_get_update_mode(i); if (update_mode == Animation::UPDATE_CAPTURE) { - if (p_started || pa->capture == Variant()) { - pa->capture = pa->object->get_indexed(pa->subpath); + if (p_started || + pa->capture == Variant()) { + pa->capture = + pa->object->get_indexed( + pa->subpath); } - int key_count = a->track_get_key_count(i); + int key_count = + a->track_get_key_count(i); if (key_count == 0) { continue; //eeh not worth it } - float first_key_time = a->track_get_key_time(i, 0); + float first_key_time = + a->track_get_key_time(i, 0); float transition = 1.0; int first_key = 0; if (first_key_time == 0.0) { //ignore, use for transition if (key_count == 1) { - continue; //with one key we can't do anything + continue; //with one + //key we + //can't do + //anything } - transition = a->track_get_key_transition(i, 0); - first_key_time = a->track_get_key_time(i, 1); + transition = + a->track_get_key_transition( + i, 0); + first_key_time = + a->track_get_key_time( + i, 1); first_key = 1; } if (p_time < first_key_time) { - float c = Math::ease(p_time / first_key_time, transition); - Variant first_value = a->track_get_key_value(i, first_key); + float c = Math::ease(p_time / + first_key_time, + transition); + Variant first_value = + a->track_get_key_value( + i, first_key); Variant interp_value; - Variant::interpolate(pa->capture, first_value, c, interp_value); + Variant::interpolate( + pa->capture, + first_value, c, + interp_value); - if (pa->accum_pass != player->accum_pass) { - ERR_CONTINUE(player->cache_update_prop_size >= NODE_CACHE_UPDATE_MAX); - player->cache_update_prop[player->cache_update_prop_size++] = pa; - pa->value_accum = interp_value; - pa->accum_pass = player->accum_pass; + if (pa->accum_pass != + player->accum_pass) { + ERR_CONTINUE( + player->cache_update_prop_size >= + NODE_CACHE_UPDATE_MAX); + player->cache_update_prop + [player->cache_update_prop_size++] = + pa; + pa->value_accum = + interp_value; + pa->accum_pass = + player->accum_pass; } else { - Variant::interpolate(pa->value_accum, interp_value, p_interp, pa->value_accum); + Variant::interpolate( + pa->value_accum, + interp_value, + p_interp, + pa->value_accum); } continue; //handled } } - if (update_mode == Animation::UPDATE_CONTINUOUS || update_mode == Animation::UPDATE_CAPTURE || (p_delta == 0 && update_mode == Animation::UPDATE_DISCRETE)) { //delta == 0 means seek + if (update_mode == + Animation::UPDATE_CONTINUOUS || + update_mode == + Animation::UPDATE_CAPTURE || + (p_delta == 0 && + update_mode == + Animation:: + UPDATE_DISCRETE)) { //delta == 0 means seek - Variant value = a->value_track_interpolate(i, p_time); + Variant value = + a->value_track_interpolate( + i, p_time); if (value == Variant()) { continue; } - //thanks to trigger mode, this should be solved now.. + //thanks to trigger mode, this should + //be solved now.. /* - if (p_delta==0 && value.get_type()==Variant::STRING) - continue; // doing this with strings is messy, should find another way + if (p_delta==0 && + value.get_type()==Variant::STRING) + continue; // doing this with + strings is messy, should find another + way */ - if (pa->accum_pass != player->accum_pass) { - ERR_CONTINUE(player->cache_update_prop_size >= NODE_CACHE_UPDATE_MAX); - player->cache_update_prop[player->cache_update_prop_size++] = pa; + if (pa->accum_pass != + player->accum_pass) { + ERR_CONTINUE( + player->cache_update_prop_size >= + NODE_CACHE_UPDATE_MAX); + player->cache_update_prop + [player->cache_update_prop_size++] = + pa; pa->value_accum = value; - pa->accum_pass = player->accum_pass; + pa->accum_pass = + player->accum_pass; } else { - Variant::interpolate(pa->value_accum, value, p_interp, pa->value_accum); + Variant::interpolate( + pa->value_accum, value, + p_interp, + pa->value_accum); } } else if (p_is_current && p_delta != 0) { List indices; - a->value_track_get_key_indices(i, p_time, p_delta, &indices); + a->value_track_get_key_indices( + i, p_time, p_delta, &indices); - for (List::Element *F = indices.front(); F; F = F->next()) { - Variant value = a->track_get_key_value(i, F->get()); + for (List::Element *F = + indices.front(); + F; F = F->next()) { + Variant value = + a->track_get_key_value( + i, F->get()); switch (pa->special) { case SP_NONE: { bool valid; - pa->object->set_indexed(pa->subpath, value, &valid); //you are not speshul + pa->object->set_indexed( + pa->subpath, + value, + &valid); //you are not speshul #if 0 #ifdef DEBUG_ENABLED if (!valid) { @@ -470,11 +599,17 @@ static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *p List indices; - a->method_track_get_key_indices(i, p_time, p_delta, &indices); + a->method_track_get_key_indices( + i, p_time, p_delta, &indices); - for (List::Element *E = indices.front(); E; E = E->next()) { - StringName method = a->method_track_get_name(i, E->get()); - Vector params = a->method_track_get_params(i, E->get()); + for (List::Element *E = indices.front(); + E; E = E->next()) { + StringName method = + a->method_track_get_name( + i, E->get()); + Vector params = + a->method_track_get_params( + i, E->get()); int s = params.size(); @@ -487,7 +622,10 @@ static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *p #endif #endif - static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8"); + static_assert(VARIANT_ARG_MAX == 8, + "This code needs to be " + "updated if VARIANT_ARG_MAX " + "!= 8"); #if 0 if (player->can_call) { if (method_call_mode == ANIMATION_METHOD_CALL_DEFERRED) { @@ -525,20 +663,31 @@ static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *p continue; } #endif - - Map::Element *E = nc->bezier_anim.find(a->track_get_path(i).get_concatenated_subnames()); - ERR_CONTINUE(!E); //should it continue, or create a new one? + Map::Element + *E = nc->bezier_anim.find( + a->track_get_path(i) + .get_concatenated_subnames()); + ERR_CONTINUE(!E); //should it continue, or + //create a new one? TrackNodeCache::BezierAnim *ba = &E->get(); - float bezier = a->bezier_track_interpolate(i, p_time); + float bezier = + a->bezier_track_interpolate(i, p_time); if (ba->accum_pass != player->accum_pass) { - ERR_CONTINUE(player->cache_update_bezier_size >= NODE_CACHE_UPDATE_MAX); - player->cache_update_bezier[player->cache_update_bezier_size++] = ba; + ERR_CONTINUE( + player->cache_update_bezier_size >= + NODE_CACHE_UPDATE_MAX); + player->cache_update_bezier + [player->cache_update_bezier_size++] = + ba; ba->bezier_accum = bezier; ba->accum_pass = player->accum_pass; } else { - ba->bezier_accum = Math::lerp(ba->bezier_accum, bezier, p_interp); + ba->bezier_accum = + Math::lerp(ba->bezier_accum, + bezier, p_interp); } } break; @@ -560,25 +709,38 @@ static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *p continue; } - Ref stream = a->audio_track_get_key_stream(i, idx); + Ref stream = + a->audio_track_get_key_stream( + i, idx); if (!stream.is_valid()) { #if 0 nc->node->call("stop"); #endif nc->audio_playing = false; - player->playing_caches.erase(nc); + player->playing_caches.erase( + nc); } else { - float start_ofs = a->audio_track_get_key_start_offset(i, idx); - start_ofs += p_time - a->track_get_key_time(i, idx); - float end_ofs = a->audio_track_get_key_end_offset(i, idx); - float len = stream->get_length(); + float start_ofs = + a->audio_track_get_key_start_offset( + i, idx); + start_ofs += p_time - + a->track_get_key_time( + i, idx); + float end_ofs = + a->audio_track_get_key_end_offset( + i, idx); + float len = + stream->get_length(); - if (start_ofs > len - end_ofs) { + if (start_ofs > + len - end_ofs) { #if 0 nc->node->call("stop"); #endif - nc->audio_playing = false; - player->playing_caches.erase(nc); + nc->audio_playing = + false; + player->playing_caches + .erase(nc); continue; } @@ -588,9 +750,16 @@ static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *p #endif nc->audio_playing = true; - player->playing_caches.insert(nc); - if (len && end_ofs > 0) { //force a end at a time - nc->audio_len = len - start_ofs - end_ofs; + player->playing_caches.insert( + nc); + if (len && + end_ofs > + 0) { //force a + //end at a + //time + nc->audio_len = len - + start_ofs - + end_ofs; } else { nc->audio_len = 0; } @@ -601,48 +770,80 @@ static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *p } else { //find stuff to play List to_play; - a->track_get_key_indices_in_range(i, p_time, p_delta, &to_play); + a->track_get_key_indices_in_range( + i, p_time, p_delta, &to_play); if (to_play.size()) { - int idx = to_play.back()->get(); + int idx = + to_play.back()->get(); - Ref stream = a->audio_track_get_key_stream(i, idx); + Ref stream = + a->audio_track_get_key_stream( + i, idx); if (!stream.is_valid()) { #if 0 nc->node->call("stop"); #endif - nc->audio_playing = false; - player->playing_caches.erase(nc); + nc->audio_playing = + false; + player->playing_caches + .erase(nc); } else { - float start_ofs = a->audio_track_get_key_start_offset(i, idx); - float end_ofs = a->audio_track_get_key_end_offset(i, idx); - float len = stream->get_length(); + float start_ofs = + a->audio_track_get_key_start_offset( + i, + idx); + float end_ofs = + a->audio_track_get_key_end_offset( + i, + idx); + float len = + stream->get_length(); #if 0 nc->node->call("set_stream", stream); nc->node->call("play", start_ofs); #endif - nc->audio_playing = true; - player->playing_caches.insert(nc); - if (len && end_ofs > 0) { //force a end at a time - nc->audio_len = len - start_ofs - end_ofs; + nc->audio_playing = + true; + player->playing_caches + .insert(nc); + if (len && + end_ofs > + 0) { //force a end at a time + nc->audio_len = + len - + start_ofs - + end_ofs; } else { - nc->audio_len = 0; + nc->audio_len = + 0; } - nc->audio_start = p_time; + nc->audio_start = + p_time; } } else if (nc->audio_playing) { bool loop = a->has_loop(); bool stop = false; - if (!loop && p_time < nc->audio_start) { + if (!loop && + p_time < + nc->audio_start) { stop = true; } else if (nc->audio_len > 0) { - float len = nc->audio_start > p_time ? (a->get_length() - nc->audio_start) + p_time : p_time - nc->audio_start; + float len = + nc->audio_start > + p_time + ? (a->get_length() - + nc->audio_start) + + p_time + : p_time - + nc->audio_start; - if (len > nc->audio_len) { + if (len > + nc->audio_len) { stop = true; } } @@ -652,8 +853,10 @@ static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *p #if 0 nc->node->call("stop"); #endif - nc->audio_playing = false; - player->playing_caches.erase(nc); + nc->audio_playing = + false; + player->playing_caches + .erase(nc); } } } @@ -727,8 +930,9 @@ static void ECS::_animation_process_animation(struct ECS::AnimationPlayerData *p } } } -static void ECS::_animation_process_data(struct ECS::AnimationPlayerData *player, - PlaybackData &cd, float p_delta, float p_blend, bool p_seeked, bool p_started) +static void ECS::_animation_process_data( + struct ECS::AnimationPlayerData *player, PlaybackData &cd, + float p_delta, float p_blend, bool p_seeked, bool p_started) { float delta = p_delta * player->speed_scale * cd.speed_scale; float next_pos = cd.pos + delta; @@ -736,6 +940,8 @@ static void ECS::_animation_process_data(struct ECS::AnimationPlayerData *player ERR_PRINT("bad animation"); return; } + assert(cd.from->animation.is_valid()); + flecs::log::trace("animation %p", cd.from->animation.ptr()); float len = cd.from->animation->get_length(); bool loop = cd.from->animation->has_loop(); if (!loop) { @@ -744,18 +950,24 @@ static void ECS::_animation_process_data(struct ECS::AnimationPlayerData *player else if (next_pos > len) next_pos = len; } - bool backwards = signbit(delta); // Negative zero means playing backwards too - delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here) + bool backwards = + signbit(delta); // Negative zero means playing backwards too + delta = next_pos - + cd.pos; // Fix delta (after determination of backwards because + // negative zero is lost here) if (&cd == &player->playback.current) { if (!backwards && cd.pos <= len && next_pos == len) { //playback finished player->end_reached = true; - player->end_notify = cd.pos < len; // Notify only if not already at the end + player->end_notify = cd.pos < + len; // Notify only if not already at the end } if (backwards && cd.pos >= 0 && next_pos == 0) { //playback finished player->end_reached = true; - player->end_notify = cd.pos > 0; // Notify only if not already at the beginning + player->end_notify = + cd.pos > 0; // Notify only if not already at + // the beginning } } else { float looped_next_pos = Math::fposmod(next_pos, len); @@ -767,12 +979,11 @@ static void ECS::_animation_process_data(struct ECS::AnimationPlayerData *player next_pos = looped_next_pos; } cd.pos = next_pos; - _animation_process_animation(player, cd.from, - cd.pos, delta, p_blend, &cd == &player->playback.current, - p_seeked, p_started); + _animation_process_animation(player, cd.from, cd.pos, delta, p_blend, + &cd == &player->playback.current, p_seeked, p_started); } -static void ECS::_animation_process2(struct ECS::AnimationPlayerData *player, - float p_delta, bool p_started) +static void ECS::_animation_process2( + struct ECS::AnimationPlayerData *player, float p_delta, bool p_started) { ECS::Playback &c = player->playback; player->accum_pass++; @@ -781,8 +992,9 @@ static void ECS::_animation_process2(struct ECS::AnimationPlayerData *player, ERR_PRINT("bad animation2"); return; } - _animation_process_data(player, c.current, - p_delta, 1.0f, + flecs::log::trace("length: %d", + player->playback.current.from->animation->get_length()); + _animation_process_data(player, c.current, p_delta, 1.0f, c.seeked && p_delta != 0, p_started); if (p_delta != 0) c.seeked = false; @@ -792,20 +1004,23 @@ static void ECS::_animation_process2(struct ECS::AnimationPlayerData *player, float blend = b.blend_left / b.blend_time; if (b.data.from->animation.is_null()) { ERR_PRINT("bad animation3"); - b.blend_left -= Math::absf(player->speed_scale * p_delta); + b.blend_left -= + Math::absf(player->speed_scale * p_delta); prev = E->prev(); if (b.blend_left < 0) c.blend.erase(E); continue; } - _animation_process_data(player, b.data, p_delta, blend, false, false); + _animation_process_data( + player, b.data, p_delta, blend, false, false); b.blend_left -= Math::absf(player->speed_scale * p_delta); prev = E->prev(); if (b.blend_left < 0) c.blend.erase(E); } } -static void ECS::_animation_update_transforms(struct ECS::AnimationPlayerData *player) +static void ECS::_animation_update_transforms( + struct ECS::AnimationPlayerData *player) { int i; { @@ -825,42 +1040,60 @@ static void ECS::_animation_update_transforms(struct ECS::AnimationPlayerData *p } player->cache_update_size = 0; for (i = 0; i < player->cache_update_prop_size; i++) { - TrackNodeCache::PropertyAnim *pa = player->cache_update_prop[i]; + TrackNodeCache::PropertyAnim *pa = + player->cache_update_prop[i]; switch (pa->special) { case SP_NONE: { bool valid; - pa->object->set_indexed(pa->subpath, pa->value_accum, &valid); + pa->object->set_indexed( + pa->subpath, pa->value_accum, &valid); if (!valid) { /* error setting key - ERR_PRINT("Failed setting key at time " + rtos(playback.current.pos) + " in Animation '" + get_current_animation() + "' at Node '" + get_path() + "', Track '" + String(pa->owner->path) + "'. Check if property exists or the type of key is right for the property"); + ERR_PRINT("Failed setting key at time " + + rtos(playback.current.pos) + " in + Animation '" + get_current_animation() + + "' at Node '" + get_path() + "', + Track '" + String(pa->owner->path) + + "'. Check if property exists or the + type of key is right for the + property"); */ } } break; case SP_NODE2D_POS: - // static_cast(pa->object)->set_position(pa->value_accum); + // static_cast(pa->object)->set_position(pa->value_accum); break; case SP_NODE2D_ROT: - // static_cast(pa->object)->set_rotation(Math::deg2rad((double)pa->value_accum)); + // static_cast(pa->object)->set_rotation(Math::deg2rad((double)pa->value_accum)); break; case SP_NODE2D_SCALE: - // static_cast(pa->object)->set_scale(pa->value_accum); + // static_cast(pa->object)->set_scale(pa->value_accum); break; } } player->cache_update_prop_size = 0; for (i = 0; i < player->cache_update_bezier_size; i++) { - TrackNodeCache::BezierAnim *ba = player->cache_update_bezier[i]; + TrackNodeCache::BezierAnim *ba = + player->cache_update_bezier[i]; ba->object->set_indexed(ba->bezier_property, ba->bezier_accum); } player->cache_update_bezier_size = 0; } -static void ECS::_set_process(struct ECS::AnimationPlayerData *player, bool p_process, bool p_force) +static void ECS::_set_process( + struct ECS::AnimationPlayerData *player, bool p_process, bool p_force) { /* Nothing */ } -static void ECS::_animation_process(struct ECS::AnimationPlayerData *player, float p_time) +static void ECS::_animation_process( + struct ECS::AnimationPlayerData *player, float p_time) { if (player->playback.current.from) { + flecs::log::trace("length: %f", + player->playback.current.from->animation + ->get_length()); player->end_reached = false; player->end_notify = false; _animation_process2(player, p_time, player->playback.started); @@ -907,8 +1140,8 @@ void ECS::_stop_playing_caches(struct ECS::AnimationPlayerData *player) player->playing_caches.clear(); } -void ECS::queue(struct ECS::AnimationPlayerData *player, - const StringName &p_name) +void ECS::queue( + struct ECS::AnimationPlayerData *player, const StringName &p_name) { if (!player->playing) { play(player, p_name); @@ -916,8 +1149,8 @@ void ECS::queue(struct ECS::AnimationPlayerData *player, player->queued.push_back(p_name); } } -StringName ECS::animation_get_next(struct ECS::AnimationPlayerData *player, - const StringName &p_animation) +StringName ECS::animation_get_next( + struct ECS::AnimationPlayerData *player, const StringName &p_animation) { if (!player->animation_set.has(p_animation)) { return StringName(); @@ -945,31 +1178,34 @@ Error ECS::add_animation(struct ECS::AnimationPlayerData *player, ad.animation = p_animation; ad.name = p_name; player->animation_set[p_name] = ad; + player->animation_set[p_name].animation = p_animation; } _ref_anim(player, p_animation); return OK; } -void ECS::remove_animation(struct ECS::AnimationPlayerData *player, - const StringName &p_name) +void ECS::remove_animation( + struct ECS::AnimationPlayerData *player, const StringName &p_name) { ERR_FAIL_COND(!player->animation_set.has(p_name)); #if 0 stop(); #endif +#if 0 _unref_anim(player, player->animation_set[p_name].animation); +#endif player->animation_set.erase(p_name); clear_caches(player); } -static void ECS::_ref_anim(struct ECS::AnimationPlayerData *player, - const Ref &p_anim) +static void ECS::_ref_anim( + struct ECS::AnimationPlayerData *player, const Ref &p_anim) { } -static void ECS::_unref_anim(struct ECS::AnimationPlayerData *player, - const Ref &p_anim) +static void ECS::_unref_anim( + struct ECS::AnimationPlayerData *player, const Ref &p_anim) { } @@ -977,8 +1213,10 @@ void ECS::clear_caches(struct ECS::AnimationPlayerData *player) { _stop_playing_caches(player); player->node_cache_map.clear(); - for (Map::Element *E = player->animation_set.front(); E; E = E->next()) - E->get().node_cache.clear(); + for (Map::Element *E = + player->animation_set.front(); + E; E = E->next()) + E->get().node_cache_size = 0; player->cache_update_size = 0; player->cache_update_prop_size = 0; player->cache_update_bezier_size = 0; @@ -986,5 +1224,11 @@ void ECS::clear_caches(struct ECS::AnimationPlayerData *player) void ECS::advance(struct ECS::AnimationPlayerData *player, float p_time) { + if (player->playback.current.from) { + flecs::log::trace("length: %f", + player->playback.current.from->animation + ->get_length()); + } ECS::_animation_process(player, p_time); + player->playback.current.from = nullptr; } diff --git a/src/modules/character/animation_system.h b/src/modules/character/animation_system.h index c037b90..acdbb32 100644 --- a/src/modules/character/animation_system.h +++ b/src/modules/character/animation_system.h @@ -66,7 +66,9 @@ struct TrackNodeCache { owner(nullptr), bezier_accum(0.0), object(nullptr), - accum_pass(0) {} + accum_pass(0) + { + } }; Map bezier_anim; TrackNodeCache() : @@ -86,11 +88,112 @@ struct TrackNodeCache { { } }; +struct Track { + Animation::TrackType type; + Animation::InterpolationType interpolation; + bool loop_wrap; + NodePath path; // path to something + bool imported; + bool enabled; + Track() + { + interpolation = Animation::INTERPOLATION_LINEAR; + imported = false; + loop_wrap = true; + enabled = true; + } + virtual ~Track() {} +}; +struct Key { + float transition; + float time; // time in secs + Key() { transition = 1; } +}; + +// transform key holds either Vector3 or Quaternion +template struct TKey : public Key { + T value; +}; + +struct TransformKey { + Vector3 loc; + Quat rot; + Vector3 scale; +}; + +struct TransformTrack : public Track { + Vector> transforms; + + TransformTrack() { type = Animation::TYPE_TRANSFORM; } +}; + +struct ValueTrack : public Track { + Animation::UpdateMode update_mode; + bool update_on_seek; + Vector> values; + + ValueTrack() + { + type = Animation::TYPE_VALUE; + update_mode = Animation::UPDATE_CONTINUOUS; + } +}; + +struct MethodKey : public Key { + StringName method; + Vector params; +}; + +struct MethodTrack : public Track { + Vector methods; + MethodTrack() { type = Animation::TYPE_METHOD; } +}; + +struct BezierKey { + Vector2 in_handle; //relative (x always <0) + Vector2 out_handle; //relative (x always >0) + float value; +}; + +struct BezierTrack : public Track { + Vector> values; + + BezierTrack() { type = Animation::TYPE_BEZIER; } +}; + +struct AudioKey { + RES stream; + float start_offset; //offset from start + float end_offset; //offset from end, if 0 then full length or infinite + AudioKey() + { + start_offset = 0; + end_offset = 0; + } +}; + +struct AudioTrack : public Track { + Vector> values; + + AudioTrack() { type = Animation::TYPE_AUDIO; } +}; + +struct BasicTrack : public Track { + uint8_t data[256]; + BasicTrack() { type = Animation::TYPE_TRANSFORM; } +}; + struct AnimationData { String name; StringName next; - Vector node_cache; + int node_cache_size; + struct TrackNodeCache *node_cache[128]; Ref animation; + AnimationData(Ref anim) : + animation(anim), node_cache_size(0) + { + } + AnimationData() : animation(Ref()), node_cache_size(0) {} }; struct PlaybackData { AnimationData *from; @@ -124,7 +227,11 @@ struct Playback { struct BlendKey { StringName from; StringName to; - bool operator<(const BlendKey &bk) const { return from == bk.from ? String(to) < String(bk.to) : String(from) < String(bk.from); } + bool operator<(const BlendKey &bk) const + { + return from == bk.from ? String(to) < String(bk.to) + : String(from) < String(bk.from); + } }; struct TrackNodeCacheKey { uint32_t id; @@ -141,10 +248,7 @@ struct TrackNodeCacheKey { } } }; -enum { - NODE_CACHE_UPDATE_MAX = 1024, - BLEND_FROM_MAX = 3 -}; +enum { NODE_CACHE_UPDATE_MAX = 1024, BLEND_FROM_MAX = 3 }; struct AnimationPlayerData { Map node_cache_map; TrackNodeCache *cache_update[NODE_CACHE_UPDATE_MAX]; @@ -176,75 +280,72 @@ struct AnimationPlayerData { bool playing; }; /* public functions */ -StringName find_animation(struct AnimationPlayerData *player, - const Ref &p_animation); +StringName find_animation( + struct AnimationPlayerData *player, const Ref &p_animation); Error add_animation(struct AnimationPlayerData *player, const StringName &p_name, const Ref &p_animation); -void remove_animation(struct AnimationPlayerData *player, - const StringName &p_name); +void remove_animation( + struct AnimationPlayerData *player, const StringName &p_name); void rename_animation(struct AnimationPlayerData *player, const StringName &p_name, const StringName &p_new_name); -bool has_animation(struct AnimationPlayerData *player, - const StringName &p_name); -Ref get_animation(struct AnimationPlayerData *player, - const StringName &p_name); -void get_animation_list(struct AnimationPlayerData *player, - List *p_animations); +bool has_animation( + struct AnimationPlayerData *player, const StringName &p_name); +Ref get_animation( + struct AnimationPlayerData *player, const StringName &p_name); +void get_animation_list( + struct AnimationPlayerData *player, List *p_animations); void set_blend_time(struct AnimationPlayerData *player, - const StringName &p_animation1, const StringName &p_animation2, float p_time); + const StringName &p_animation1, const StringName &p_animation2, + float p_time); float get_blend_time(struct AnimationPlayerData *player, const StringName &p_animation1, const StringName &p_animation2); void animation_set_next(struct AnimationPlayerData *player, const StringName &p_animation, const StringName &p_next); -StringName animation_get_next(struct AnimationPlayerData *player, - const StringName &p_animation); -void set_default_blend_time(struct AnimationPlayerData *player, - float p_default); +StringName animation_get_next( + struct AnimationPlayerData *player, const StringName &p_animation); +void set_default_blend_time( + struct AnimationPlayerData *player, float p_default); float get_default_blend_time(struct AnimationPlayerData *player); void play(struct AnimationPlayerData *player, - const StringName &p_name = StringName(), - float p_custom_blend = -1, float p_custom_scale = 1.0, - bool p_from_end = false); + const StringName &p_name = StringName(), float p_custom_blend = -1, + float p_custom_scale = 1.0, bool p_from_end = false); void play_backwards(struct AnimationPlayerData *player, const StringName &p_name = StringName(), float p_custom_blend = -1); -void queue(struct AnimationPlayerData *player, - const StringName &p_name); +void queue(struct AnimationPlayerData *player, const StringName &p_name); PoolVector get_queue(struct AnimationPlayerData *player); void clear_queue(struct AnimationPlayerData *player); -void stop(struct AnimationPlayerData *player, - bool p_reset = true); +void stop(struct AnimationPlayerData *player, bool p_reset = true); bool is_playing(struct AnimationPlayerData *player); String get_current_animation(struct AnimationPlayerData *player); -void set_current_animation(struct AnimationPlayerData *player, - const String &p_anim); +void set_current_animation( + struct AnimationPlayerData *player, const String &p_anim); String get_assigned_animation(struct AnimationPlayerData *player); -void set_assigned_animation(struct AnimationPlayerData *player, - const String &p_anim); -void set_active(struct AnimationPlayerData *player, - bool p_active); +void set_assigned_animation( + struct AnimationPlayerData *player, const String &p_anim); +void set_active(struct AnimationPlayerData *player, bool p_active); bool is_active(struct AnimationPlayerData *player); bool is_valid(struct AnimationPlayerData *player); -void set_speed_scale(struct AnimationPlayerData *player, - float p_speed); +void set_speed_scale(struct AnimationPlayerData *player, float p_speed); float get_speed_scale(struct AnimationPlayerData *player); float get_playing_speed(struct AnimationPlayerData *player); -void set_autoplay(struct AnimationPlayerData *player, - const String &p_name); +void set_autoplay(struct AnimationPlayerData *player, const String &p_name); String get_autoplay(struct AnimationPlayerData *player); -void set_reset_on_save_enabled(struct AnimationPlayerData *player, - bool p_enabled); +void set_reset_on_save_enabled( + struct AnimationPlayerData *player, bool p_enabled); bool is_reset_on_save_enabled(struct AnimationPlayerData *player); -void set_animation_process_mode(struct AnimationPlayerData *player, - AnimationProcessMode p_mode); -AnimationProcessMode get_animation_process_mode(struct AnimationPlayerData *player); -void set_method_call_mode(struct AnimationPlayerData *player, - AnimationMethodCallMode p_mode); -AnimationMethodCallMode get_method_call_mode(struct AnimationPlayerData *player); +void set_animation_process_mode( + struct AnimationPlayerData *player, AnimationProcessMode p_mode); +AnimationProcessMode get_animation_process_mode( + struct AnimationPlayerData *player); +void set_method_call_mode( + struct AnimationPlayerData *player, AnimationMethodCallMode p_mode); +AnimationMethodCallMode get_method_call_mode( + struct AnimationPlayerData *player); -void seek(struct AnimationPlayerData *player, - float p_time, bool p_update = false); -void seek_delta(struct AnimationPlayerData *player, - float p_time, float p_delta); +void seek(struct AnimationPlayerData *player, float p_time, + bool p_update = false); +void seek_delta( + struct AnimationPlayerData *player, float p_time, float p_delta); float get_current_animation_position(struct AnimationPlayerData *player); float get_current_animation_length(struct AnimationPlayerData *player); void advance(struct AnimationPlayerData *player, float p_time);