Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 61 additions & 7 deletions editor/animation/animation_track_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3892,7 +3892,14 @@ void AnimationTrackEditGroup::_notification(int p_what) {
draw_line(Point2(get_size().width - timeline->get_buttons_width(), 0), Point2(get_size().width - timeline->get_buttons_width(), get_size().height), v_line_color, Math::round(EDSCALE));

int ofs = stylebox_header->get_margin(SIDE_LEFT);
bool is_group_folded = editor->get_current_animation()->editor_is_group_folded(node_name);
Ref<Texture2D> fold_icon = get_theme_icon(is_group_folded ? SNAME("arrow_collapsed") : SNAME("arrow"), SNAME("Tree"));
Size2 fold_icon_size = fold_icon->get_size();
draw_texture_rect(fold_icon, Rect2(Point2(ofs, (get_size().height - fold_icon_size.y) / 2 + v_margin_offset).round(), fold_icon_size));

ofs += h_separation + fold_icon_size.x;
draw_texture_rect(icon, Rect2(Point2(ofs, (get_size().height - icon_size.y) / 2 + v_margin_offset).round(), icon_size));

ofs += h_separation + icon_size.x;
draw_string(font, Point2(ofs, (get_size().height - font->get_height(font_size)) / 2 + font->get_ascent(font_size) + v_margin_offset).round(), node_name, HORIZONTAL_ALIGNMENT_LEFT, timeline->get_name_limit() - ofs, font_size, color);

Expand All @@ -3919,14 +3926,41 @@ void AnimationTrackEditGroup::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
Point2 pos = mb->get_position();
Rect2 node_name_rect = Rect2(0, 0, timeline->get_name_limit(), get_size().height);

if (node_name_rect.has_point(pos)) {
EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
editor_selection->clear();
Node *n = root->get_node_or_null(node);
if (n) {
editor_selection->add_node(n);
int left_ofs = get_theme_stylebox(SNAME("header"), SNAME("AnimationTrackEditGroup"))->get_margin(SIDE_LEFT);
bool is_group_folded = editor->get_current_animation()->editor_is_group_folded(node_name);
Ref<Texture2D> fold_icon = get_theme_icon(is_group_folded ? SNAME("arrow_collapsed") : SNAME("arrow"), SNAME("Tree"));
int fold_icon_width = fold_icon->get_size().width;
Rect2 fold_area_rect = Rect2(0, 0, left_ofs + fold_icon_width, get_size().height);

if (fold_area_rect.has_point(pos)) {
bool current_group_folded = !editor->get_current_animation()->editor_is_group_folded(node_name);
editor->get_current_animation()->editor_set_group_folded(node_name, current_group_folded);

if (!editor->get_current_animation()->get_path().is_resource_file()) {
EditorNode::get_editor_folding().save_scene_folding(
EditorNode::get_singleton()->get_edited_scene(),
EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path());
} else {
EditorNode::get_editor_folding().save_resource_folding(
editor->get_current_animation(),
editor->get_current_animation()->get_path());
}

for (AnimationTrackEdit *i : track_edits) {
i->set_visible(!current_group_folded);
}

queue_redraw();
} else {
Rect2 node_name_rect = Rect2(0, 0, timeline->get_name_limit(), get_size().height);
if (node_name_rect.has_point(pos)) {
EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
editor_selection->clear();
Node *n = root->get_node_or_null(node);
if (n) {
editor_selection->add_node(n);
}
}
}
}
Expand Down Expand Up @@ -4060,6 +4094,12 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re
}
}
}

if (animation->get_path().is_resource_file()) {
EditorNode::get_editor_folding().load_resource_folding(
animation,
animation->get_path());
}
} else {
hscroll->hide();
edit->set_disabled(true);
Expand Down Expand Up @@ -5286,6 +5326,10 @@ void AnimationTrackEditor::_update_tracks() {
track_edit->set_in_group(true);
group_sort[base_path]->add_child(track_edit);

AnimationTrackEditGroup *g = Object::cast_to<AnimationTrackEditGroup>(group_sort[base_path]->get_child(0));
ERR_FAIL_NULL_MSG(g, "The first child of this group's VBoxContainer isn't an AnimationTrackEditGroup. Collapsing this animation group may not work.");
g->track_edits.push_back(track_edit);

} else {
track_edit->set_in_group(false);
}
Expand Down Expand Up @@ -5334,6 +5378,13 @@ void AnimationTrackEditor::_update_tracks() {

for (VBoxContainer *vb : group_containers) {
track_vbox->add_child(vb);

AnimationTrackEditGroup *g = Object::cast_to<AnimationTrackEditGroup>(vb->get_child(0));
if (g) {
for (AnimationTrackEdit *i : g->track_edits) {
i->set_visible(!animation->editor_is_group_folded(g->node_name));
}
}
}

} else {
Expand Down Expand Up @@ -6380,6 +6431,9 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
if (box_selection->is_visible_in_tree()) {
// Only if moved.
for (int i = 0; i < track_edits.size(); i++) {
if (!track_edits[i]->is_visible_in_tree()) {
continue; // Skip collapsed track edits.
}
Rect2 local_rect = box_select_rect;
local_rect.position -= track_edits[i]->get_global_position();
track_edits[i]->append_to_selection(local_rect, mb->is_command_or_control_pressed());
Expand Down
4 changes: 3 additions & 1 deletion editor/animation/animation_track_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ class AnimationMultiTrackKeyEdit;
class AnimationBezierTrackEdit;

class AnimationTrackEditGroup : public Control {
friend class AnimationTrackEditor;

GDCLASS(AnimationTrackEditGroup, Control);
Ref<Texture2D> icon;
Vector2 icon_size;
Expand All @@ -578,7 +580,7 @@ class AnimationTrackEditGroup : public Control {
AnimationTrackEditor *editor = nullptr;

bool hovered = false;

LocalVector<AnimationTrackEdit *> track_edits;
void _zoom_changed();

protected:
Expand Down
26 changes: 26 additions & 0 deletions editor/docks/scene_tree_dock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2316,6 +2316,32 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
}
}
}

// key.get_path() of p_renames is like:
// /root/@EditorNode@18033/@Panel@14/.../Scene/TheOldName
// value of p_renames is like:
// /root/@EditorNode@18033/@Panel@14/.../Scene/TheNewName
for (const KeyValue<Node *, NodePath> &rename : *p_renames) {
NodePath old_path = rename.key->get_path();
NodePath new_path = rename.value;
Vector<StringName> rel_path = old_path.rel_path_to(new_path).get_names();

StringName old_node_name = rename.key->get_name();
StringName new_node_name = rel_path[rel_path.size() - 1];

anim->editor_set_group_folded(new_node_name, anim->editor_is_group_folded(old_node_name));
anim->editor_set_group_folded(old_node_name, false);
}

if (!anim->get_path().is_resource_file()) {
EditorNode::get_editor_folding().save_scene_folding(
EditorNode::get_singleton()->get_edited_scene(),
EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path());
} else {
EditorNode::get_editor_folding().save_resource_folding(
anim,
anim->get_path());
}
}
}
}
Expand Down
75 changes: 72 additions & 3 deletions editor/settings/editor_folding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#include "core/io/file_access.h"
#include "editor/file_system/editor_paths.h"
#include "editor/inspector/editor_inspector.h"
#include "scene/animation/animation_mixer.h"
#include "scene/resources/animation.h"

Vector<String> EditorFolding::_get_unfolds(const Object *p_object) {
Vector<String> sections;
Expand All @@ -55,6 +57,12 @@ void EditorFolding::save_resource_folding(const Ref<Resource> &p_resource, const
Vector<String> unfolds = _get_unfolds(p_resource.ptr());
config->set_value("folding", "sections_unfolded", unfolds);

Ref<Animation> as_anim = p_resource;
if (as_anim.is_valid()) {
Vector<String> folded_groups = _get_animation_folds(as_anim.ptr());
config->set_value("folding", "animation_groups_folded", folded_groups);
}

String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
config->save(file);
Expand Down Expand Up @@ -86,9 +94,15 @@ void EditorFolding::load_resource_folding(Ref<Resource> p_resource, const String
unfolds = config->get_value("folding", "sections_unfolded");
}
_set_unfolds(p_resource.ptr(), unfolds);

Ref<Animation> anim = p_resource;
if (anim.is_valid() && config->has_section_key("folding", "animation_groups_folded")) {
Vector<String> folded_groups = config->get_value("folding", "animation_groups_folded");
_set_animation_folds(anim.ptr(), folded_groups);
}
}

void EditorFolding::_fill_folds(const Node *p_root, const Node *p_node, Array &p_folds, Array &resource_folds, Array &nodes_folded, HashSet<Ref<Resource>> &resources) {
void EditorFolding::_fill_folds(const Node *p_root, const Node *p_node, Array &p_folds, Array &resource_folds, Array &nodes_folded, HashSet<Ref<Resource>> &resources, HashSet<Ref<Animation>> &animations, Array &anim_groups_folded) {
if (p_root != p_node) {
if (!p_node->get_owner()) {
return; //not owned, bye
Expand All @@ -108,6 +122,21 @@ void EditorFolding::_fill_folds(const Node *p_root, const Node *p_node, Array &p
p_folds.push_back(unfolds);
}

const AnimationMixer *anim_mixer = Object::cast_to<AnimationMixer>(p_node);
if (anim_mixer) {
List<StringName> anim_names;
anim_mixer->get_animation_list(&anim_names);
for (const StringName &anim_name : anim_names) {
Ref<Animation> anim = anim_mixer->get_animation(anim_name);
if (anim.is_valid() && !animations.has(anim) && !anim->get_path().is_empty() && !anim->get_path().is_resource_file()) {
Vector<String> anim_folds = _get_animation_folds(anim.ptr());
anim_groups_folded.push_back(anim->get_path());
anim_groups_folded.push_back(anim_folds);
animations.insert(anim);
}
}
}

List<PropertyInfo> plist;
p_node->get_property_list(&plist);
for (const PropertyInfo &E : plist) {
Expand All @@ -125,7 +154,7 @@ void EditorFolding::_fill_folds(const Node *p_root, const Node *p_node, Array &p
}

for (int i = 0; i < p_node->get_child_count(); i++) {
_fill_folds(p_root, p_node->get_child(i), p_folds, resource_folds, nodes_folded, resources);
_fill_folds(p_root, p_node->get_child(i), p_folds, resource_folds, nodes_folded, resources, animations, anim_groups_folded);
}
}

Expand All @@ -143,11 +172,14 @@ void EditorFolding::save_scene_folding(const Node *p_scene, const String &p_path
Array unfolds, res_unfolds;
HashSet<Ref<Resource>> resources;
Array nodes_folded;
_fill_folds(p_scene, p_scene, unfolds, res_unfolds, nodes_folded, resources);
HashSet<Ref<Animation>> animations;
Array anim_groups_folded;
_fill_folds(p_scene, p_scene, unfolds, res_unfolds, nodes_folded, resources, animations, anim_groups_folded);

config->set_value("folding", "node_unfolds", unfolds);
config->set_value("folding", "resource_unfolds", res_unfolds);
config->set_value("folding", "nodes_folded", nodes_folded);
config->set_value("folding", "animation_groups_folded", anim_groups_folded);

String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
Expand Down Expand Up @@ -178,9 +210,14 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) {
if (config->has_section_key("folding", "nodes_folded")) {
nodes_folded = config->get_value("folding", "nodes_folded");
}
Array animation_groups_folded;
if (config->has_section_key("folding", "animation_groups_folded")) {
animation_groups_folded = config->get_value("folding", "animation_groups_folded");
}

ERR_FAIL_COND(unfolds.size() & 1);
ERR_FAIL_COND(res_unfolds.size() & 1);
ERR_FAIL_COND(animation_groups_folded.size() & 1);

for (int i = 0; i < unfolds.size(); i += 2) {
NodePath path2 = unfolds[i];
Expand Down Expand Up @@ -210,6 +247,17 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) {
node->set_display_folded(true);
}
}

for (int i = 0; i < animation_groups_folded.size(); i += 2) {
String path2 = animation_groups_folded[i];
Ref<Animation> anim = ResourceCache::get_ref(path2);
if (anim.is_null()) {
continue;
}

Vector<String> folded_groups = animation_groups_folded[i + 1];
_set_animation_folds(anim.ptr(), folded_groups);
}
}

bool EditorFolding::has_folding_data(const String &p_path) {
Expand Down Expand Up @@ -294,3 +342,24 @@ void EditorFolding::unfold_scene(Node *p_scene) {
HashSet<Ref<Resource>> resources;
_do_node_unfolds(p_scene, p_scene, resources);
}

Vector<String> EditorFolding::_get_animation_folds(const Animation *p_animation) {
Vector<String> folded_groups;
folded_groups.resize(p_animation->editor_get_folded_groups().size());
if (folded_groups.size()) {
String *w = folded_groups.ptrw();
int idx = 0;
for (const StringName &group_name : p_animation->editor_get_folded_groups()) {
w[idx++] = group_name;
}
}

return folded_groups;
}

void EditorFolding::_set_animation_folds(Animation *p_animation, const Vector<String> &p_folds) {
p_animation->editor_clear_folded_groups();
for (const String &group_name : p_folds) {
p_animation->editor_add_folded_group(group_name);
}
}
10 changes: 9 additions & 1 deletion editor/settings/editor_folding.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,30 @@

#include "scene/main/node.h"

class Animation;

class EditorFolding {
Vector<String> _get_unfolds(const Object *p_object);
void _set_unfolds(Object *p_object, const Vector<String> &p_unfolds);

void _fill_folds(const Node *p_root, const Node *p_node, Array &p_folds, Array &resource_folds, Array &nodes_folded, HashSet<Ref<Resource>> &resources);
void _fill_folds(const Node *p_root, const Node *p_node, Array &p_folds, Array &resource_folds, Array &nodes_folded, HashSet<Ref<Resource>> &resources, HashSet<Ref<Animation>> &animations, Array &anim_groups_folded);

void _do_object_unfolds(Object *p_object, HashSet<Ref<Resource>> &resources);
void _do_node_unfolds(Node *p_root, Node *p_node, HashSet<Ref<Resource>> &resources);

Vector<String> _get_animation_folds(const Animation *p_animation);
void _set_animation_folds(Animation *p_animation, const Vector<String> &p_unfolds);

public:
void save_resource_folding(const Ref<Resource> &p_resource, const String &p_path);
void load_resource_folding(Ref<Resource> p_resource, const String &p_path);

void save_scene_folding(const Node *p_scene, const String &p_path);
void load_scene_folding(Node *p_scene, const String &p_path);

void save_animation_folding(const Ref<Animation> &p_animation, const String &p_path);
void load_animation_folding(Ref<Animation> p_animation, const String &p_path);

void unfold_scene(Node *p_scene);

bool has_folding_data(const String &p_path);
Expand Down
19 changes: 19 additions & 0 deletions scene/resources/animation.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ class Animation : public Resource {

LocalVector<Track *> tracks;

#ifdef TOOLS_ENABLED
HashSet<StringName> folded_groups;
Comment thread
KoBeWi marked this conversation as resolved.
#endif // TOOLS_ENABLED

template <typename T, typename V>
int _insert(double p_time, T &p_keys, const V &p_value);

Expand Down Expand Up @@ -539,6 +543,21 @@ class Animation : public Resource {
void optimize(real_t p_allowed_velocity_err = 0.01, real_t p_allowed_angular_err = 0.01, int p_precision = 3);
void compress(uint32_t p_page_size = 8192, uint32_t p_fps = 120, float p_split_tolerance = 4.0); // 4.0 seems to be the split tolerance sweet spot from many tests.

#ifdef TOOLS_ENABLED
const HashSet<StringName> &editor_get_folded_groups() const { return folded_groups; }
void editor_clear_folded_groups() { folded_groups.clear(); }
void editor_add_folded_group(const StringName &p_group_name) { folded_groups.insert(p_group_name); }
void editor_remove_folded_group(const StringName &p_group_name) { folded_groups.erase(p_group_name); }
bool editor_is_group_folded(const StringName &p_group_name) const { return folded_groups.has(p_group_name); }
void editor_set_group_folded(const StringName &p_group_name, bool p_folded) {
if (p_folded) {
editor_add_folded_group(p_group_name);
} else {
editor_remove_folded_group(p_group_name);
}
}
#endif // TOOLS_ENABLED

// Helper functions for Rotation.
static double interpolate_via_rest(double p_from, double p_to, double p_weight, double p_rest = 0.0); // Deterministic slerp to prevent to cross the inverted rest axis.
static Quaternion interpolate_via_rest(const Quaternion &p_from, const Quaternion &p_to, real_t p_weight, const Quaternion &p_rest = Quaternion()); // Deterministic slerp to prevent to cross the inverted rest axis.
Expand Down