Merge pull request #48332 from TokageItLab/implement-ping-pong
This commit is contained in:
commit
9ed4f8367b
29 changed files with 852 additions and 362 deletions
|
|
@ -1323,8 +1323,20 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
|
|||
|
||||
void AnimationTimelineEdit::_anim_loop_pressed() {
|
||||
undo_redo->create_action(TTR("Change Animation Loop"));
|
||||
undo_redo->add_do_method(animation.ptr(), "set_loop", loop->is_pressed());
|
||||
undo_redo->add_undo_method(animation.ptr(), "set_loop", animation->has_loop());
|
||||
switch (animation->get_loop_mode()) {
|
||||
case Animation::LoopMode::LOOP_NONE: {
|
||||
undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::LOOP_LINEAR);
|
||||
} break;
|
||||
case Animation::LoopMode::LOOP_LINEAR: {
|
||||
undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::LOOP_PINGPONG);
|
||||
} break;
|
||||
case Animation::LoopMode::LOOP_PINGPONG: {
|
||||
undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::LOOP_NONE);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode());
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
|
|
@ -1607,7 +1619,24 @@ void AnimationTimelineEdit::update_values() {
|
|||
length->set_tooltip(TTR("Animation length (seconds)"));
|
||||
time_icon->set_tooltip(TTR("Animation length (seconds)"));
|
||||
}
|
||||
loop->set_pressed(animation->has_loop());
|
||||
|
||||
switch (animation->get_loop_mode()) {
|
||||
case Animation::LoopMode::LOOP_NONE: {
|
||||
loop->set_icon(get_theme_icon("Loop", "EditorIcons"));
|
||||
loop->set_pressed(false);
|
||||
} break;
|
||||
case Animation::LoopMode::LOOP_LINEAR: {
|
||||
loop->set_icon(get_theme_icon("Loop", "EditorIcons"));
|
||||
loop->set_pressed(true);
|
||||
} break;
|
||||
case Animation::LoopMode::LOOP_PINGPONG: {
|
||||
loop->set_icon(get_theme_icon("PingPongLoop", "EditorIcons"));
|
||||
loop->set_pressed(true);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
editing = false;
|
||||
}
|
||||
|
||||
|
|
@ -2050,25 +2079,25 @@ void AnimationTrackEdit::_notification(int p_what) {
|
|||
|
||||
Ref<Texture2D> icon = wrap_icon[loop_wrap ? 1 : 0];
|
||||
|
||||
loop_mode_rect.position.x = ofs;
|
||||
loop_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2;
|
||||
loop_mode_rect.size = icon->get_size();
|
||||
loop_wrap_rect.position.x = ofs;
|
||||
loop_wrap_rect.position.y = int(get_size().height - icon->get_height()) / 2;
|
||||
loop_wrap_rect.size = icon->get_size();
|
||||
|
||||
if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) {
|
||||
draw_texture(icon, loop_mode_rect.position);
|
||||
draw_texture(icon, loop_wrap_rect.position);
|
||||
}
|
||||
|
||||
loop_mode_rect.position.y = 0;
|
||||
loop_mode_rect.size.y = get_size().height;
|
||||
loop_wrap_rect.position.y = 0;
|
||||
loop_wrap_rect.size.y = get_size().height;
|
||||
|
||||
ofs += icon->get_width() + hsep;
|
||||
loop_mode_rect.size.x += hsep;
|
||||
loop_wrap_rect.size.x += hsep;
|
||||
|
||||
if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) {
|
||||
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
|
||||
loop_mode_rect.size.x += down_icon->get_width();
|
||||
loop_wrap_rect.size.x += down_icon->get_width();
|
||||
} else {
|
||||
loop_mode_rect = Rect2();
|
||||
loop_wrap_rect = Rect2();
|
||||
}
|
||||
|
||||
ofs += down_icon->get_width();
|
||||
|
|
@ -2415,7 +2444,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
|
|||
return TTR("Interpolation Mode");
|
||||
}
|
||||
|
||||
if (loop_mode_rect.has_point(p_pos)) {
|
||||
if (loop_wrap_rect.has_point(p_pos)) {
|
||||
return TTR("Loop Wrap Mode (Interpolate end with beginning on loop)");
|
||||
}
|
||||
|
||||
|
|
@ -2614,7 +2643,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
accept_event();
|
||||
}
|
||||
|
||||
if (loop_mode_rect.has_point(pos)) {
|
||||
if (loop_wrap_rect.has_point(pos)) {
|
||||
if (!menu) {
|
||||
menu = memnew(PopupMenu);
|
||||
add_child(menu);
|
||||
|
|
@ -2625,7 +2654,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
menu->add_icon_item(get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP);
|
||||
menu->set_as_minsize();
|
||||
|
||||
Vector2 popup_pos = get_screen_position() + loop_mode_rect.position + Vector2(0, loop_mode_rect.size.height);
|
||||
Vector2 popup_pos = get_screen_position() + loop_wrap_rect.position + Vector2(0, loop_wrap_rect.size.height);
|
||||
menu->set_position(popup_pos);
|
||||
menu->popup();
|
||||
accept_event();
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ class AnimationTrackEdit : public Control {
|
|||
|
||||
Rect2 update_mode_rect;
|
||||
Rect2 interp_mode_rect;
|
||||
Rect2 loop_mode_rect;
|
||||
Rect2 loop_wrap_rect;
|
||||
Rect2 remove_rect;
|
||||
Rect2 bezier_edit_rect;
|
||||
|
||||
|
|
@ -466,6 +466,7 @@ class AnimationTrackEditor : public VBoxContainer {
|
|||
Animation::TrackType track_type = Animation::TrackType::TYPE_ANIMATION;
|
||||
Animation::InterpolationType interp_type = Animation::InterpolationType::INTERPOLATION_CUBIC;
|
||||
Animation::UpdateMode update_mode = Animation::UpdateMode::UPDATE_CAPTURE;
|
||||
Animation::LoopMode loop_mode = Animation::LoopMode::LOOP_LINEAR;
|
||||
bool loop_wrap = false;
|
||||
bool enabled = false;
|
||||
|
||||
|
|
|
|||
1
editor/icons/PingPongLoop.svg
Normal file
1
editor/icons/PingPongLoop.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".9961"><path d="m10 7h-4v-2l-4 3 4 3v-2h4v2l4-3-4-3z"/><path d="m0 1v14h2v-7-7z"/><path d="m14 1v7 7h2v-14z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 270 B |
|
|
@ -317,10 +317,10 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I
|
|||
|
||||
String animname = E;
|
||||
const int loop_string_count = 3;
|
||||
static const char *loop_strings[loop_string_count] = { "loops", "loop", "cycle" };
|
||||
static const char *loop_strings[loop_string_count] = { "loop_mode", "loop", "cycle" };
|
||||
for (int i = 0; i < loop_string_count; i++) {
|
||||
if (_teststr(animname, loop_strings[i])) {
|
||||
anim->set_loop(true);
|
||||
anim->set_loop_mode(Animation::LoopMode::LOOP_LINEAR);
|
||||
animname = _fixstr(animname, loop_strings[i]);
|
||||
ap->rename_animation(E, animname);
|
||||
}
|
||||
|
|
@ -732,7 +732,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
|
|||
String name = node_settings["clip_" + itos(i + 1) + "/name"];
|
||||
int from_frame = node_settings["clip_" + itos(i + 1) + "/start_frame"];
|
||||
int end_frame = node_settings["clip_" + itos(i + 1) + "/end_frame"];
|
||||
bool loop = node_settings["clip_" + itos(i + 1) + "/loops"];
|
||||
Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)node_settings["clip_" + itos(i + 1) + "/loop_mode"]);
|
||||
bool save_to_file = node_settings["clip_" + itos(i + 1) + "/save_to_file/enabled"];
|
||||
bool save_to_path = node_settings["clip_" + itos(i + 1) + "/save_to_file/path"];
|
||||
bool save_to_file_keep_custom = node_settings["clip_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"];
|
||||
|
|
@ -740,7 +740,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
|
|||
animation_clips.push_back(name);
|
||||
animation_clips.push_back(from_frame / p_animation_fps);
|
||||
animation_clips.push_back(end_frame / p_animation_fps);
|
||||
animation_clips.push_back(loop);
|
||||
animation_clips.push_back(loop_mode);
|
||||
animation_clips.push_back(save_to_file);
|
||||
animation_clips.push_back(save_to_path);
|
||||
animation_clips.push_back(save_to_file_keep_custom);
|
||||
|
|
@ -767,7 +767,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
|
|||
}
|
||||
}
|
||||
|
||||
anim->set_loop(anim_settings["settings/loops"]);
|
||||
anim->set_loop_mode(static_cast<Animation::LoopMode>((int)anim_settings["settings/loop_mode"]));
|
||||
bool save = anim_settings["save_to_file/enabled"];
|
||||
String path = anim_settings["save_to_file/path"];
|
||||
bool keep_custom = anim_settings["save_to_file/keep_custom_tracks"];
|
||||
|
|
@ -799,7 +799,7 @@ Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> ani
|
|||
old_anim->copy_track(i, anim);
|
||||
}
|
||||
}
|
||||
anim->set_loop(old_anim->has_loop());
|
||||
anim->set_loop_mode(old_anim->get_loop_mode());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -827,7 +827,7 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
|
|||
String name = p_clips[i];
|
||||
float from = p_clips[i + 1];
|
||||
float to = p_clips[i + 2];
|
||||
bool loop = p_clips[i + 3];
|
||||
Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)p_clips[i + 3]);
|
||||
bool save_to_file = p_clips[i + 4];
|
||||
String save_to_path = p_clips[i + 5];
|
||||
bool keep_current = p_clips[i + 6];
|
||||
|
|
@ -915,7 +915,7 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
|
|||
}
|
||||
}
|
||||
|
||||
new_anim->set_loop(loop);
|
||||
new_anim->set_loop_mode(loop_mode);
|
||||
new_anim->set_length(to - from);
|
||||
anim->add_animation(name, new_anim);
|
||||
|
||||
|
|
@ -989,7 +989,7 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
|
|||
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "use_external/path", PROPERTY_HINT_FILE, "*.material,*.res,*.tres"), ""));
|
||||
} break;
|
||||
case INTERNAL_IMPORT_CATEGORY_ANIMATION: {
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "settings/loops"), false));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "settings/loop_mode"), 0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.tres"), ""));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/keep_custom_tracks"), ""));
|
||||
|
|
@ -1006,7 +1006,7 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
|
|||
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/name"), ""));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/start_frame"), 0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/end_frame"), 0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/loops"), false));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/loop_mode"), 0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/save_to_file/path", PROPERTY_HINT_SAVE_FILE, ".res,*.tres"), ""));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"), false));
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
|
|||
if (loop_type == 0x00) {
|
||||
loop = AudioStreamSample::LOOP_FORWARD;
|
||||
} else if (loop_type == 0x01) {
|
||||
loop = AudioStreamSample::LOOP_PING_PONG;
|
||||
loop = AudioStreamSample::LOOP_PINGPONG;
|
||||
} else if (loop_type == 0x02) {
|
||||
loop = AudioStreamSample::LOOP_BACKWARD;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "editor/plugins/canvas_item_editor_plugin.h" // For onion skinning.
|
||||
#include "editor/plugins/node_3d_editor_plugin.h" // For onion skinning.
|
||||
#include "scene/main/window.h"
|
||||
#include "scene/resources/animation.h"
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
void AnimationPlayerEditor::_node_removed(Node *p_node) {
|
||||
|
|
@ -72,7 +73,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
|
|||
if (player->has_animation(animname)) {
|
||||
Ref<Animation> anim = player->get_animation(animname);
|
||||
if (!anim.is_null()) {
|
||||
frame->set_max(anim->get_length());
|
||||
frame->set_max((double)anim->get_length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -289,7 +290,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
|
|||
track_editor->set_root(root);
|
||||
}
|
||||
}
|
||||
frame->set_max(anim->get_length());
|
||||
frame->set_max((double)anim->get_length());
|
||||
|
||||
} else {
|
||||
track_editor->set_animation(Ref<Animation>());
|
||||
|
|
@ -1014,7 +1015,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set, bool
|
|||
Ref<Animation> anim;
|
||||
anim = player->get_animation(current);
|
||||
|
||||
float pos = CLAMP(anim->get_length() * (p_value / frame->get_max()), 0, anim->get_length());
|
||||
float pos = CLAMP((double)anim->get_length() * (p_value / frame->get_max()), 0, (double)anim->get_length());
|
||||
if (track_editor->is_snap_enabled()) {
|
||||
pos = Math::snapped(pos, _get_editor_step());
|
||||
}
|
||||
|
|
@ -1424,7 +1425,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
|
|||
|
||||
float pos = cpos + step_off * anim->get_step();
|
||||
|
||||
bool valid = anim->has_loop() || (pos >= 0 && pos <= anim->get_length());
|
||||
bool valid = anim->get_loop_mode() != Animation::LoopMode::LOOP_NONE || (pos >= 0 && pos <= anim->get_length());
|
||||
onion.captures_valid.write[cidx] = valid;
|
||||
if (valid) {
|
||||
player->seek(pos, true);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue