void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float p_time, float p_delta, float p_interp, bool p_allow_discrete) { if (p_anim->node_cache.size() != p_anim->animation->get_track_count()) { // animation hasn't been "node-cached" _generate_node_caches(p_anim); } ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count()); Animation *a = p_anim->animation.operator->(); bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint(); for (int i = 0; i < a->get_track_count(); i++) { TrackNodeCache *nc = p_anim->node_cache[i]; if (!nc) // no node cache for this track, skip it continue; if (a->track_get_key_count(i) == 0) continue; // do nothing if track is empty switch (a->track_get_type(i)) { case Animation::TYPE_TRANSFORM: { if (!nc->spatial) continue; Vector3 loc; 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 if (err != OK) continue; if (nc->accum_pass != accum_pass) { ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX); cache_update[cache_update_size++] = nc; nc->accum_pass = 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); } } break; case Animation::TYPE_VALUE: { if (!nc->node) continue; //StringName property=a->track_get_path(i).get_property(); Map<StringName, TrackNodeCache::PropertyAnim>::Element *E = nc->property_anim.find(a->track_get_path(i).get_property()); ERR_CONTINUE(!E); //should it continue, or create a new one? TrackNodeCache::PropertyAnim *pa = &E->get(); if (a->value_track_get_update_mode(i) == Animation::UPDATE_CONTINUOUS || (p_delta == 0 && a->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE)) { //delta == 0 means seek Variant value = a->value_track_interpolate(i, p_time); if (value == Variant()) continue; //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 (pa->accum_pass != accum_pass) { ERR_CONTINUE(cache_update_prop_size >= NODE_CACHE_UPDATE_MAX); cache_update_prop[cache_update_prop_size++] = pa; pa->value_accum = value; pa->accum_pass = accum_pass; } else { Variant::interpolate(pa->value_accum, value, p_interp, pa->value_accum); } } else if (p_allow_discrete && p_delta != 0) { List<int> indices; a->value_track_get_key_indices(i, p_time, p_delta, &indices); for (List<int>::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(pa->prop, value, &valid); //you are not speshul #ifdef DEBUG_ENABLED if (!valid) { ERR_PRINTS("Failed setting track value '" + String(pa->owner->path) + "'. Check if property exists or the type of key is valid. Animation '" + a->get_name() + "' at node '" + get_path() + "'."); } #endif } break; case SP_NODE2D_POS: { #ifdef DEBUG_ENABLED if (value.get_type() != Variant::VECTOR2) { ERR_PRINTS("Position key at time " + rtos(p_time) + " in Animation Track '" + String(pa->owner->path) + "' not of type Vector2(). Animation '" + a->get_name() + "' at node '" + get_path() + "'."); } #endif static_cast<Node2D *>(pa->object)->set_position(value); } break; case SP_NODE2D_ROT: { #ifdef DEBUG_ENABLED if (value.is_num()) { ERR_PRINTS("Rotation key at time " + rtos(p_time) + " in Animation Track '" + String(pa->owner->path) + "' not numerical. Animation '" + a->get_name() + "' at node '" + get_path() + "'."); } #endif static_cast<Node2D *>(pa->object)->set_rotation(Math::deg2rad((double)value)); } break; case SP_NODE2D_SCALE: { #ifdef DEBUG_ENABLED if (value.get_type() != Variant::VECTOR2) { ERR_PRINTS("Scale key at time " + rtos(p_time) + " in Animation Track '" + String(pa->owner->path) + "' not of type Vector2()." + a->get_name() + "' at node '" + get_path() + "'."); } #endif static_cast<Node2D *>(pa->object)->set_scale(value); } break; } } } } break; case Animation::TYPE_METHOD: { if (!nc->node) continue; if (p_delta == 0) continue; if (!p_allow_discrete) break; List<int> indices; a->method_track_get_key_indices(i, p_time, p_delta, &indices); for (List<int>::Element *E = indices.front(); E; E = E->next()) { StringName method = a->method_track_get_name(i, E->get()); Vector<Variant> params = a->method_track_get_params(i, E->get()); int s = params.size(); ERR_CONTINUE(s > VARIANT_ARG_MAX); if (can_call) { MessageQueue::get_singleton()->push_call( nc->node, method, s >= 1 ? params[0] : Variant(), s >= 2 ? params[1] : Variant(), s >= 3 ? params[2] : Variant(), s >= 4 ? params[3] : Variant(), s >= 5 ? params[4] : Variant()); } } } break; } } }
void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p_time, float p_delta,float p_interp, bool p_allow_discrete) { if (p_anim->node_cache.size() != p_anim->animation->get_track_count()) { // animation hasn't been "node-cached" _generate_node_caches(p_anim); } ERR_FAIL_COND( p_anim->node_cache.size() != p_anim->animation->get_track_count() ); Animation *a=p_anim->animation.operator->(); bool can_call = is_inside_tree() && !get_tree()->is_editor_hint(); for (int i=0;i<a->get_track_count();i++) { TrackNodeCache *nc=p_anim->node_cache[i]; if (!nc) // no node cache for this track, skip it continue; if (a->track_get_key_count(i)==0) continue; // do nothing if track is empty switch(a->track_get_type(i)) { case Animation::TYPE_TRANSFORM: { if (!nc->spatial) continue; Vector3 loc; 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 if (err!=OK) continue; if (nc->accum_pass!=accum_pass) { ERR_CONTINUE( cache_update_size >= NODE_CACHE_UPDATE_MAX ); cache_update[cache_update_size++]=nc; nc->accum_pass=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); } } break; case Animation::TYPE_VALUE: { if (!nc->node) continue; //StringName property=a->track_get_path(i).get_property(); Map<StringName,TrackNodeCache::PropertyAnim>::Element *E=nc->property_anim.find(a->track_get_path(i).get_property()); ERR_CONTINUE(!E); //should it continue, or create a new one? TrackNodeCache::PropertyAnim *pa = &E->get(); if (a->value_track_is_continuous(i) || p_delta==0) { Variant value=a->value_track_interpolate(i,p_time); if (p_delta==0 && value.get_type()==Variant::STRING) continue; // doing this with strings is messy, should find another way if (pa->accum_pass!=accum_pass) { ERR_CONTINUE( cache_update_prop_size >= NODE_CACHE_UPDATE_MAX ); cache_update_prop[cache_update_prop_size++]=pa; pa->value_accum=value; pa->accum_pass=accum_pass; } else { Variant::interpolate(pa->value_accum,value,p_interp,pa->value_accum); } } else if (p_allow_discrete) { List<int> indices; a->value_track_get_key_indices(i,p_time,p_delta,&indices); for(List<int>::Element *F=indices.front();F;F=F->next()) { Variant value=a->track_get_key_value(i,F->get()); switch(pa->special) { case SP_NONE: pa->object->set(pa->prop,value); break; //you are not speshul case SP_NODE2D_POS: static_cast<Node2D*>(pa->object)->set_pos(value); break; case SP_NODE2D_ROT: static_cast<Node2D*>(pa->object)->set_rot(Math::deg2rad(value)); break; case SP_NODE2D_SCALE: static_cast<Node2D*>(pa->object)->set_scale(value); break; } } } } break; case Animation::TYPE_METHOD: { if (!nc->node) continue; if (p_delta==0) continue; if (!p_allow_discrete) break; List<int> indices; a->method_track_get_key_indices(i,p_time,p_delta,&indices); for(List<int>::Element *E=indices.front();E;E=E->next()) { StringName method=a->method_track_get_name(i,E->get()); Vector<Variant> params=a->method_track_get_params(i,E->get()); int s=params.size(); ERR_CONTINUE( s > VARIANT_ARG_MAX ); if (can_call) { MessageQueue::get_singleton()->push_call( nc->node, method, s>=1 ? params[0] : Variant(), s>=2 ? params[1] : Variant(), s>=3 ? params[2] : Variant(), s>=4 ? params[3] : Variant(), s>=5 ? params[4] : Variant() ); } } } break; } } }