Massive rewrite to AnimationTree. Many APIs changed in order to:

-Reuse resources
-Expose properties in AnimationTree
This commit is contained in:
Juan Linietsky 2018-08-20 13:38:18 -03:00
parent 1b66b08fdb
commit c7e4527a88
34 changed files with 3856 additions and 2937 deletions

View file

@ -1476,8 +1476,13 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str
Signal::Target target(p_to_object->get_instance_id(), p_to_method);
if (s->slot_map.has(target)) {
ERR_EXPLAIN("Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object.");
ERR_FAIL_COND_V(s->slot_map.has(target), ERR_INVALID_PARAMETER);
if (p_flags & CONNECT_REFERENCE_COUNTED) {
s->slot_map[target].reference_count++;
return OK;
} else {
ERR_EXPLAIN("Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object.");
ERR_FAIL_COND_V(s->slot_map.has(target), ERR_INVALID_PARAMETER);
}
}
Signal::Slot slot;
@ -1491,6 +1496,10 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str
conn.binds = p_binds;
slot.conn = conn;
slot.cE = p_to_object->connections.push_back(conn);
if (p_flags & CONNECT_REFERENCE_COUNTED) {
slot.reference_count = 1;
}
s->slot_map[target] = slot;
return OK;
@ -1539,7 +1548,14 @@ void Object::disconnect(const StringName &p_signal, Object *p_to_object, const S
ERR_FAIL();
}
p_to_object->connections.erase(s->slot_map[target].cE);
Signal::Slot *slot = &s->slot_map[target];
slot->reference_count--; // by default is zero, if it was not referenced it will go below it
if (slot->reference_count >= 0) {
return;
}
p_to_object->connections.erase(slot->cE);
s->slot_map.erase(target);
if (s->slot_map.empty() && ClassDB::has_signal(get_class_name(), p_signal)) {
@ -1761,6 +1777,7 @@ void Object::_bind_methods() {
BIND_ENUM_CONSTANT(CONNECT_DEFERRED);
BIND_ENUM_CONSTANT(CONNECT_PERSIST);
BIND_ENUM_CONSTANT(CONNECT_ONESHOT);
BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
}
void Object::call_deferred(const StringName &p_method, VARIANT_ARG_DECLARE) {

View file

@ -392,7 +392,8 @@ public:
CONNECT_DEFERRED = 1,
CONNECT_PERSIST = 2, // hint for scene to save this connection
CONNECT_ONESHOT = 4
CONNECT_ONESHOT = 4,
CONNECT_REFERENCE_COUNTED = 8,
};
struct Connection {
@ -443,8 +444,10 @@ private:
struct Slot {
int reference_count;
Connection conn;
List<Connection>::Element *cE;
Slot() { reference_count = 0; }
};
MethodInfo user;

View file

@ -1533,9 +1533,10 @@ void EditorInspector::update_tree() {
if (capitalize_paths)
path_name = path_name.capitalize();
Color c = sscolor;
c.a /= level;
section->setup(path_name, acc_path, object, c, use_folding);
section->setup(path_name, path_name, object, c, use_folding);
item_path[acc_path] = section->get_vbox();
}

View file

@ -74,6 +74,7 @@
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/animation_state_machine_editor.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/plugins/animation_tree_player_editor_plugin.h"
#include "editor/plugins/asset_library_editor_plugin.h"
#include "editor/plugins/audio_stream_editor_plugin.h"
#include "editor/plugins/baked_lightmap_editor_plugin.h"
@ -5589,16 +5590,13 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(ShaderEditorPlugin(this)));
add_editor_plugin(memnew(VisualShaderEditorPlugin(this)));
add_editor_plugin(memnew(AnimationNodeBlendTreeEditorPlugin(this)));
add_editor_plugin(memnew(AnimationNodeBlendSpace1DEditorPlugin(this)));
add_editor_plugin(memnew(AnimationNodeBlendSpace2DEditorPlugin(this)));
add_editor_plugin(memnew(AnimationNodeStateMachineEditorPlugin(this)));
add_editor_plugin(memnew(CameraEditorPlugin(this)));
add_editor_plugin(memnew(ThemeEditorPlugin(this)));
add_editor_plugin(memnew(MultiMeshEditorPlugin(this)));
add_editor_plugin(memnew(MeshInstanceEditorPlugin(this)));
add_editor_plugin(memnew(AnimationTreeEditorPlugin(this)));
add_editor_plugin(memnew(AnimationTreePlayerEditorPlugin(this)));
add_editor_plugin(memnew(MeshLibraryEditorPlugin(this)));
add_editor_plugin(memnew(StyleBoxEditorPlugin(this)));
add_editor_plugin(memnew(SpriteEditorPlugin(this)));

View file

@ -36,6 +36,16 @@
void InspectorDock::_menu_option(int p_option) {
switch (p_option) {
case RESOURCE_MAKE_BUILT_IN: {
_unref_resource();
} break;
case RESOURCE_COPY: {
_copy_resource();
} break;
case RESOURCE_EDIT_CLIPBOARD: {
_paste_resource();
} break;
case RESOURCE_SAVE: {
_save_resource(false);
} break;
@ -400,10 +410,11 @@ void InspectorDock::update(Object *p_object) {
p->add_shortcut(ED_SHORTCUT("property_editor/copy_params", TTR("Copy Params")), OBJECT_COPY_PARAMS);
p->add_shortcut(ED_SHORTCUT("property_editor/paste_params", TTR("Paste Params")), OBJECT_PASTE_PARAMS);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("property_editor/paste_resource", TTR("Paste Resource")), RESOURCE_PASTE);
p->add_shortcut(ED_SHORTCUT("property_editor/paste_resource", TTR("Edit Resource Clipboard")), RESOURCE_EDIT_CLIPBOARD);
if (is_resource) {
p->add_shortcut(ED_SHORTCUT("property_editor/copy_resource", TTR("Copy Resource")), RESOURCE_COPY);
p->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Built-In")), RESOURCE_UNREF);
p->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Built-In")), RESOURCE_MAKE_BUILT_IN);
}
if (is_resource || is_node) {

View file

@ -51,13 +51,12 @@ class InspectorDock : public VBoxContainer {
GDCLASS(InspectorDock, VBoxContainer);
enum MenuOptions {
RESOURCE_NEW,
RESOURCE_LOAD,
RESOURCE_SAVE,
RESOURCE_SAVE_AS,
RESOURCE_UNREF,
RESOURCE_MAKE_BUILT_IN,
RESOURCE_COPY,
RESOURCE_PASTE,
RESOURCE_EDIT_CLIPBOARD,
OBJECT_COPY_PARAMS,
OBJECT_PASTE_PARAMS,
OBJECT_UNIQUE_RESOURCES,

View file

@ -3,41 +3,11 @@
#include "os/keyboard.h"
#include "scene/animation/animation_blend_tree.h"
void AnimationNodeBlendSpace1DEditorPlugin::edit(Object *p_object) {
anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendSpace1D>(p_object));
StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {
StringName path = AnimationTreeEditor::get_singleton()->get_base_path()+"blend_position";
return path;
}
bool AnimationNodeBlendSpace1DEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("AnimationNodeBlendSpace1D");
}
void AnimationNodeBlendSpace1DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
button->show();
editor->make_bottom_panel_item_visible(anim_tree_editor);
anim_tree_editor->set_process(true);
} else {
if (anim_tree_editor->is_visible_in_tree()) {
editor->hide_bottom_panel();
}
button->hide();
anim_tree_editor->set_process(false);
}
}
AnimationNodeBlendSpace1DEditorPlugin::AnimationNodeBlendSpace1DEditorPlugin(EditorNode *p_node) {
editor = p_node;
anim_tree_editor = memnew(AnimationNodeBlendSpace1DEditor);
anim_tree_editor->set_custom_minimum_size(Size2(0, 150 * EDSCALE));
button = editor->add_bottom_panel_item(TTR("BlendSpace1D"), anim_tree_editor);
button->hide();
}
AnimationNodeBlendSpace1DEditorPlugin::~AnimationNodeBlendSpace1DEditorPlugin() {
}
void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
@ -62,7 +32,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
menu->add_submenu_item(TTR("Add Animation"), "animations");
AnimationTree *gp = blend_space->get_tree();
AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
ERR_FAIL_COND(!gp);
if (gp->has_node(gp->get_animation_player())) {
@ -85,10 +55,18 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
continue;
int idx = menu->get_item_count();
menu->add_item(vformat("Add %s", name));
menu->add_item(vformat("Add %s", name),idx);
menu->set_item_metadata(idx, E->get());
}
Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
if (clipb.is_valid()) {
menu->add_separator();
menu->add_item(TTR("Paste"), MENU_PASTE);
}
menu->add_separator();
menu->add_item(TTR("Load.."), MENU_LOAD_FILE);
menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position()));
menu->popup();
@ -158,7 +136,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
blend_space->set_blend_pos(blend_pos);
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos);
blend_space_draw->update();
}
@ -181,7 +159,8 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
blend_space->set_blend_pos(blend_pos);
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos);
blend_space_draw->update();
}
}
@ -277,7 +256,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
color.a *= 0.5;
}
float point = blend_space->get_blend_pos();
float point = AnimationTreeEditor::get_singleton()->get_tree()->get(get_blend_position_path());
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
point *= s.width;
@ -299,12 +280,6 @@ void AnimationNodeBlendSpace1DEditor::_update_space() {
updating = true;
if (blend_space->get_parent().is_valid()) {
goto_parent_hb->show();
} else {
goto_parent_hb->hide();
}
max_value->set_value(blend_space->get_max_space());
min_value->set_value(blend_space->get_min_space());
@ -355,15 +330,47 @@ void AnimationNodeBlendSpace1DEditor::_snap_toggled() {
blend_space_draw->update();
}
void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) {
file_loaded = ResourceLoader::load(p_file);
if (file_loaded.is_valid()) {
_add_menu_type(MENU_LOAD_FILE_CONFIRM);
}
}
void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
String type = menu->get_item_metadata(p_index);
Ref<AnimationRootNode> node;
if (p_index == MENU_LOAD_FILE) {
Object *obj = ClassDB::instance(type);
ERR_FAIL_COND(!obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
ERR_FAIL_COND(!an);
open_file->clear_filters();
List<String> filters;
ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters);
for (List<String>::Element *E = filters.front(); E; E = E->next()) {
open_file->add_filter("*." + E->get());
}
open_file->popup_centered_ratio();
return;
} else if (p_index == MENU_LOAD_FILE_CONFIRM) {
node = file_loaded;
file_loaded.unref();
} else if (p_index == MENU_PASTE) {
Ref<AnimationNode> node(an);
node = EditorSettings::get_singleton()->get_resource_clipboard();
} else {
String type = menu->get_item_metadata(p_index);
Object *obj = ClassDB::instance(type);
ERR_FAIL_COND(!obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
ERR_FAIL_COND(!an);
node = Ref<AnimationNode>(an);
}
if (!node.is_valid()) {
EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed."));
return;
}
updating = true;
undo_redo->create_action("Add Node Point");
@ -438,7 +445,7 @@ void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
if (point_valid) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
if (EditorNode::get_singleton()->item_has_editor(an.ptr())) {
if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
open_editor->show();
} else {
open_editor->hide();
@ -490,17 +497,11 @@ void AnimationNodeBlendSpace1DEditor::_open_editor() {
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
ERR_FAIL_COND(an.is_null());
EditorNode::get_singleton()->edit_item(an.ptr());
AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point));
}
}
void AnimationNodeBlendSpace1DEditor::_goto_parent() {
EditorNode::get_singleton()->edit_item(blend_space->get_parent().ptr());
}
void AnimationNodeBlendSpace1DEditor::_removed_from_graph() {
EditorNode::get_singleton()->edit_item(NULL);
}
void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
@ -513,18 +514,16 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
tool_erase->set_icon(get_icon("Remove", "EditorIcons"));
snap->set_icon(get_icon("SnapGrid", "EditorIcons"));
open_editor->set_icon(get_icon("Edit", "EditorIcons"));
goto_parent->set_icon(get_icon("MoveUp", "EditorIcons"));
}
if (p_what == NOTIFICATION_PROCESS) {
String error;
if (!blend_space->get_tree()) {
error = TTR("BlendSpace1D does not belong to an AnimationTree node.");
} else if (!blend_space->get_tree()->is_active()) {
if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
} else if (blend_space->get_tree()->is_state_invalid()) {
error = blend_space->get_tree()->get_invalid_state_reason();
} else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
}
if (error != error_label->get_text()) {
@ -536,6 +535,10 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
}
}
}
if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
set_process(is_visible_in_tree());
}
}
void AnimationNodeBlendSpace1DEditor::_bind_methods() {
@ -556,28 +559,26 @@ void AnimationNodeBlendSpace1DEditor::_bind_methods() {
ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace1DEditor::_update_edited_point_pos);
ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace1DEditor::_open_editor);
ClassDB::bind_method("_goto_parent", &AnimationNodeBlendSpace1DEditor::_goto_parent);
ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace1DEditor::_removed_from_graph);
ClassDB::bind_method("_file_opened", &AnimationNodeBlendSpace1DEditor::_file_opened);
}
void AnimationNodeBlendSpace1DEditor::edit(AnimationNodeBlendSpace1D *p_blend_space) {
bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node) {
if (blend_space.is_valid()) {
blend_space->disconnect("removed_from_graph", this, "_removed_from_graph");
}
Ref<AnimationNodeBlendSpace1D> b1d=p_node;
return b1d.is_valid();
}
if (p_blend_space) {
blend_space = Ref<AnimationNodeBlendSpace1D>(p_blend_space);
} else {
blend_space.unref();
}
void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
if (blend_space.is_null()) {
hide();
} else {
blend_space->connect("removed_from_graph", this, "_removed_from_graph");
blend_space=p_node;
if (!blend_space.is_null()) {
_update_space();
}
}
@ -594,14 +595,6 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
Ref<ButtonGroup> bg;
bg.instance();
goto_parent_hb = memnew(HBoxContainer);
top_hb->add_child(goto_parent_hb);
goto_parent = memnew(ToolButton);
goto_parent->connect("pressed", this, "_goto_parent", varray(), CONNECT_DEFERRED);
goto_parent_hb->add_child(goto_parent);
goto_parent_hb->add_child(memnew(VSeparator));
goto_parent_hb->hide();
tool_blend = memnew(ToolButton);
tool_blend->set_toggle_mode(true);
@ -726,13 +719,20 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
menu = memnew(PopupMenu);
add_child(menu);
menu->connect("index_pressed", this, "_add_menu_type");
menu->connect("id_pressed", this, "_add_menu_type");
animations_menu = memnew(PopupMenu);
menu->add_child(animations_menu);
animations_menu->set_name("animations");
animations_menu->connect("index_pressed", this, "_add_animation_type");
open_file = memnew(EditorFileDialog);
add_child(open_file);
open_file->set_title(TTR("Open Animation Node"));
open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
open_file->connect("file_selected", this, "_file_opened");
undo_redo = EditorNode::get_singleton()->get_undo_redo();
selected_point = -1;
dragging_selected = false;
dragging_selected_attempt = false;

View file

@ -9,10 +9,11 @@
#include "scene/gui/graph_edit.h"
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
class AnimationNodeBlendSpace1DEditor : public VBoxContainer {
class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace1DEditor, VBoxContainer)
GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin)
Ref<AnimationNodeBlendSpace1D> blend_space;
@ -81,7 +82,17 @@ class AnimationNodeBlendSpace1DEditor : public VBoxContainer {
void _goto_parent();
void _removed_from_graph();
EditorFileDialog *open_file;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
enum {
MENU_LOAD_FILE = 1000,
MENU_PASTE = 1001,
MENU_LOAD_FILE_CONFIRM = 1002
};
StringName get_blend_position_path() const;
protected:
void _notification(int p_what);
@ -89,29 +100,9 @@ protected:
public:
static AnimationNodeBlendSpace1DEditor *get_singleton() { return singleton; }
void edit(AnimationNodeBlendSpace1D *p_blend_space);
virtual bool can_edit(const Ref<AnimationNode> &p_node);
virtual void edit(const Ref<AnimationNode> &p_node);
AnimationNodeBlendSpace1DEditor();
};
class AnimationNodeBlendSpace1DEditorPlugin : public EditorPlugin {
GDCLASS(AnimationNodeBlendSpace1DEditorPlugin, EditorPlugin)
AnimationNodeBlendSpace1DEditor *anim_tree_editor;
EditorNode *editor;
Button *button;
public:
virtual String get_name() const { return "BlendSpace1D"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
virtual bool handles(Object *p_object) const;
virtual void make_visible(bool p_visible);
AnimationNodeBlendSpace1DEditorPlugin(EditorNode *p_node);
~AnimationNodeBlendSpace1DEditorPlugin();
};
#endif // ANIMATION_BLEND_SPACE_1D_EDITOR_H

View file

@ -11,27 +11,26 @@
#include "scene/gui/panel.h"
#include "scene/main/viewport.h"
void AnimationNodeBlendSpace2DEditor::edit(AnimationNodeBlendSpace2D *p_blend_space) {
bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node) {
if (blend_space.is_valid()) {
blend_space->disconnect("removed_from_graph", this, "_removed_from_graph");
}
Ref<AnimationNodeBlendSpace2D> bs2d=p_node;
return bs2d.is_valid();
}
if (p_blend_space) {
blend_space = Ref<AnimationNodeBlendSpace2D>(p_blend_space);
} else {
blend_space.unref();
}
void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) {
if (blend_space.is_null()) {
hide();
} else {
blend_space->connect("removed_from_graph", this, "_removed_from_graph");
blend_space = p_node;
if (!blend_space.is_null()) {
_update_space();
}
}
StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const {
StringName path = AnimationTreeEditor::get_singleton()->get_base_path()+"blend_position";
return path;
}
void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
@ -54,7 +53,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
menu->add_submenu_item(TTR("Add Animation"), "animations");
AnimationTree *gp = blend_space->get_tree();
AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
ERR_FAIL_COND(!gp);
if (gp && gp->has_node(gp->get_animation_player())) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
@ -74,10 +73,19 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
if (name == "Animation")
continue; // nope
int idx = menu->get_item_count();
menu->add_item(vformat("Add %s", name));
menu->add_item(vformat("Add %s", name),idx);
menu->set_item_metadata(idx, E->get());
}
Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
if (clipb.is_valid()) {
menu->add_separator();
menu->add_item(TTR("Paste"), MENU_PASTE);
}
menu->add_separator();
menu->add_item(TTR("Load.."), MENU_LOAD_FILE);
menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position()));
menu->popup();
add_point_pos = (mb->get_position() / blend_space_draw->get_size());
@ -203,7 +211,8 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
blend_pos += blend_space->get_min_space();
blend_space->set_blend_position(blend_pos);
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos);
blend_space_draw->update();
}
@ -237,21 +246,54 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
blend_pos += blend_space->get_min_space();
blend_space->set_blend_position(blend_pos);
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos);
blend_space_draw->update();
}
}
void AnimationNodeBlendSpace2DEditor::_file_opened(const String &p_file) {
file_loaded = ResourceLoader::load(p_file);
if (file_loaded.is_valid()) {
_add_menu_type(MENU_LOAD_FILE_CONFIRM);
}
}
void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
String type = menu->get_item_metadata(p_index);
Ref<AnimationRootNode> node;
if (p_index == MENU_LOAD_FILE) {
Object *obj = ClassDB::instance(type);
ERR_FAIL_COND(!obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
ERR_FAIL_COND(!an);
open_file->clear_filters();
List<String> filters;
ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters);
for (List<String>::Element *E = filters.front(); E; E = E->next()) {
open_file->add_filter("*." + E->get());
}
open_file->popup_centered_ratio();
return;
} else if (p_index == MENU_LOAD_FILE_CONFIRM) {
node = file_loaded;
file_loaded.unref();
} else if (p_index == MENU_PASTE) {
Ref<AnimationNode> node(an);
node = EditorSettings::get_singleton()->get_resource_clipboard();
} else {
String type = menu->get_item_metadata(p_index);
Object *obj = ClassDB::instance(type);
ERR_FAIL_COND(!obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
ERR_FAIL_COND(!an);
node = Ref<AnimationNode>(an);
}
if (!node.is_valid()) {
EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed."));
return;
}
updating = true;
undo_redo->create_action("Add Node Point");
@ -288,7 +330,7 @@ void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
tool_erase->set_disabled(!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count()));
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
if (EditorNode::get_singleton()->item_has_editor(an.ptr())) {
if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
open_editor->show();
} else {
open_editor->hide();
@ -490,13 +532,15 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
color.a *= 0.5;
}
Vector2 point = blend_space->get_blend_position();
Vector2 blend_pos = AnimationTreeEditor::get_singleton()->get_tree()->get(get_blend_position_path());
Vector2 point = blend_pos;
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
point *= s;
point.y = s.height - point.y;
if (blend_space->get_triangle_count()) {
Vector2 closest = blend_space->get_closest_point(blend_space->get_blend_position());
Vector2 closest = blend_space->get_closest_point(blend_pos);
closest = (closest - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
closest *= s;
closest.y = s.height - closest.y;
@ -527,12 +571,6 @@ void AnimationNodeBlendSpace2DEditor::_update_space() {
updating = true;
if (blend_space->get_parent().is_valid()) {
goto_parent_hb->show();
} else {
goto_parent_hb->hide();
}
if (blend_space->get_auto_triangles()) {
tool_triangle->hide();
} else {
@ -685,7 +723,6 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
tool_erase->set_icon(get_icon("Remove", "EditorIcons"));
snap->set_icon(get_icon("SnapGrid", "EditorIcons"));
open_editor->set_icon(get_icon("Edit", "EditorIcons"));
goto_parent->set_icon(get_icon("MoveUp", "EditorIcons"));
auto_triangles->set_icon(get_icon("AutoTriangle", "EditorIcons"));
}
@ -693,12 +730,12 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
String error;
if (!blend_space->get_tree()) {
if (!AnimationTreeEditor::get_singleton()->get_tree()) {
error = TTR("BlendSpace2D does not belong to an AnimationTree node.");
} else if (!blend_space->get_tree()->is_active()) {
} else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
} else if (blend_space->get_tree()->is_state_invalid()) {
error = blend_space->get_tree()->get_invalid_state_reason();
} else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
} else if (blend_space->get_triangle_count() == 0) {
error = TTR("No triangles exist, so no blending can take place.");
}
@ -712,22 +749,22 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
}
}
}
if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
set_process(is_visible_in_tree());
}
}
void AnimationNodeBlendSpace2DEditor::_open_editor() {
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
ERR_FAIL_COND(!an.is_valid());
EditorNode::get_singleton()->edit_item(an.ptr());
ERR_FAIL_COND(an.is_null());
AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point));
}
}
void AnimationNodeBlendSpace2DEditor::_goto_parent() {
EditorNode::get_singleton()->edit_item(blend_space->get_parent().ptr());
}
void AnimationNodeBlendSpace2DEditor::_removed_from_graph() {
EditorNode::get_singleton()->edit_item(NULL);
}
@ -761,11 +798,13 @@ void AnimationNodeBlendSpace2DEditor::_bind_methods() {
ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace2DEditor::_update_edited_point_pos);
ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace2DEditor::_open_editor);
ClassDB::bind_method("_goto_parent", &AnimationNodeBlendSpace2DEditor::_goto_parent);
ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace2DEditor::_removed_from_graph);
ClassDB::bind_method("_auto_triangles_toggled", &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled);
ClassDB::bind_method("_file_opened", &AnimationNodeBlendSpace2DEditor::_file_opened);
}
AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = NULL;
@ -781,14 +820,6 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
Ref<ButtonGroup> bg;
bg.instance();
goto_parent_hb = memnew(HBoxContainer);
top_hb->add_child(goto_parent_hb);
goto_parent = memnew(ToolButton);
goto_parent->connect("pressed", this, "_goto_parent", varray(), CONNECT_DEFERRED);
goto_parent_hb->add_child(goto_parent);
goto_parent_hb->add_child(memnew(VSeparator));
goto_parent_hb->hide();
tool_blend = memnew(ToolButton);
tool_blend->set_toggle_mode(true);
tool_blend->set_button_group(bg);
@ -968,13 +999,20 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
menu = memnew(PopupMenu);
add_child(menu);
menu->connect("index_pressed", this, "_add_menu_type");
menu->connect("id_pressed", this, "_add_menu_type");
animations_menu = memnew(PopupMenu);
menu->add_child(animations_menu);
animations_menu->set_name("animations");
animations_menu->connect("index_pressed", this, "_add_animation_type");
open_file = memnew(EditorFileDialog);
add_child(open_file);
open_file->set_title(TTR("Open Animation Node"));
open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
open_file->connect("file_selected", this, "_file_opened");
undo_redo = EditorNode::get_singleton()->get_undo_redo();
selected_point = -1;
selected_triangle = -1;
@ -982,42 +1020,3 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
dragging_selected_attempt = false;
}
void AnimationNodeBlendSpace2DEditorPlugin::edit(Object *p_object) {
anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendSpace2D>(p_object));
}
bool AnimationNodeBlendSpace2DEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("AnimationNodeBlendSpace2D");
}
void AnimationNodeBlendSpace2DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
//editor->hide_animation_player_editors();
//editor->animation_panel_make_visible(true);
button->show();
editor->make_bottom_panel_item_visible(anim_tree_editor);
anim_tree_editor->set_process(true);
} else {
if (anim_tree_editor->is_visible_in_tree())
editor->hide_bottom_panel();
button->hide();
anim_tree_editor->set_process(false);
}
}
AnimationNodeBlendSpace2DEditorPlugin::AnimationNodeBlendSpace2DEditorPlugin(EditorNode *p_node) {
editor = p_node;
anim_tree_editor = memnew(AnimationNodeBlendSpace2DEditor);
anim_tree_editor->set_custom_minimum_size(Size2(0, 300));
button = editor->add_bottom_panel_item(TTR("BlendSpace2D"), anim_tree_editor);
button->hide();
}
AnimationNodeBlendSpace2DEditorPlugin::~AnimationNodeBlendSpace2DEditorPlugin() {
}

View file

@ -9,18 +9,17 @@
#include "scene/gui/graph_edit.h"
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class AnimationNodeBlendSpace2DEditor : public VBoxContainer {
class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace2DEditor, VBoxContainer);
GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace2D> blend_space;
HBoxContainer *goto_parent_hb;
ToolButton *goto_parent;
PanelContainer *panel;
ToolButton *tool_blend;
@ -93,38 +92,32 @@ class AnimationNodeBlendSpace2DEditor : public VBoxContainer {
void _edit_point_pos(double);
void _open_editor();
void _goto_parent();
void _removed_from_graph();
void _auto_triangles_toggled();
StringName get_blend_position_path() const;
EditorFileDialog *open_file;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
enum {
MENU_LOAD_FILE = 1000,
MENU_PASTE = 1001,
MENU_LOAD_FILE_CONFIRM = 1002
};
protected:
void _notification(int p_what);
static void _bind_methods();
public:
static AnimationNodeBlendSpace2DEditor *get_singleton() { return singleton; }
void edit(AnimationNodeBlendSpace2D *p_blend_space);
virtual bool can_edit(const Ref<AnimationNode> &p_node);
virtual void edit(const Ref<AnimationNode> &p_node);
AnimationNodeBlendSpace2DEditor();
};
class AnimationNodeBlendSpace2DEditorPlugin : public EditorPlugin {
GDCLASS(AnimationNodeBlendSpace2DEditorPlugin, EditorPlugin);
AnimationNodeBlendSpace2DEditor *anim_tree_editor;
EditorNode *editor;
Button *button;
public:
virtual String get_name() const { return "BlendSpace2D"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
virtual bool handles(Object *p_object) const;
virtual void make_visible(bool p_visible);
AnimationNodeBlendSpace2DEditorPlugin(EditorNode *p_node);
~AnimationNodeBlendSpace2DEditorPlugin();
};
#endif // ANIMATION_BLEND_SPACE_2D_EDITOR_H

View file

@ -2,6 +2,7 @@
#include "core/io/resource_loader.h"
#include "core/project_settings.h"
#include "editor/editor_inspector.h"
#include "os/input.h"
#include "os/keyboard.h"
#include "scene/animation/animation_player.h"
@ -9,27 +10,6 @@
#include "scene/gui/panel.h"
#include "scene/main/viewport.h"
void AnimationNodeBlendTreeEditor::edit(AnimationNodeBlendTree *p_blend_tree) {
if (blend_tree.is_valid()) {
blend_tree->disconnect("removed_from_graph", this, "_removed_from_graph");
}
if (p_blend_tree) {
blend_tree = Ref<AnimationNodeBlendTree>(p_blend_tree);
} else {
blend_tree.unref();
}
if (blend_tree.is_null()) {
hide();
} else {
blend_tree->connect("removed_from_graph", this, "_removed_from_graph");
_update_graph();
}
}
void AnimationNodeBlendTreeEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script) {
for (int i = 0; i < add_options.size(); i++) {
@ -58,10 +38,19 @@ void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_scrip
void AnimationNodeBlendTreeEditor::_update_options_menu() {
print_line("update options");
add_node->get_popup()->clear();
for (int i = 0; i < add_options.size(); i++) {
add_node->get_popup()->add_item(add_options[i].name);
add_node->get_popup()->add_item(add_options[i].name, i);
}
Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
if (clipb.is_valid()) {
add_node->get_popup()->add_separator();
add_node->get_popup()->add_item(TTR("Paste"), MENU_PASTE);
}
add_node->get_popup()->add_separator();
add_node->get_popup()->add_item(TTR("Load.."), MENU_LOAD_FILE);
}
Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const {
@ -69,18 +58,28 @@ Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const {
return Size2(10, 200);
}
void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_property, const Variant &p_value) {
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_tree();
updating = true;
undo_redo->create_action("Parameter Changed: " + String(p_property), UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(tree, p_property, p_value);
undo_redo->add_undo_property(tree, p_property, tree->get(p_property));
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
updating = false;
}
void AnimationNodeBlendTreeEditor::_update_graph() {
if (updating)
return;
visible_properties.clear();
graph->set_scroll_ofs(blend_tree->get_graph_offset() * EDSCALE);
if (blend_tree->get_parent().is_valid()) {
goto_parent->show();
} else {
goto_parent->hide();
}
graph->clear_connections();
//erase all nodes
for (int i = 0; i < graph->get_child_count(); i++) {
@ -107,7 +106,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
agnode->connect("changed", this, "_node_changed", varray(agnode->get_instance_id()), CONNECT_DEFERRED);
}
node->set_offset(agnode->get_position() * EDSCALE);
node->set_offset(blend_tree->get_node_position(E->get()) * EDSCALE);
node->set_title(agnode->get_caption());
node->set_name(E->get());
@ -133,9 +132,28 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
node->set_slot(base + i, true, 0, get_color("font_color", "Label"), false, 0, Color());
}
node->connect("dragged", this, "_node_dragged", varray(agnode));
List<PropertyInfo> pinfo;
agnode->get_parameter_list(&pinfo);
for (List<PropertyInfo>::Element *F = pinfo.front(); F; F = F->next()) {
if (EditorNode::get_singleton()->item_has_editor(agnode.ptr())) {
if (!(F->get().usage & PROPERTY_USAGE_EDITOR)) {
continue;
}
String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E->get()) + "/" + F->get().name;
EditorProperty *prop = EditorInspector::instantiate_property_editor(AnimationTreeEditor::get_singleton()->get_tree(), F->get().type, base_path, F->get().hint, F->get().hint_string, F->get().usage);
if (prop) {
prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_tree(), base_path);
prop->update_property();
prop->set_name_split_ratio(0);
prop->connect("property_changed", this, "_property_changed");
node->add_child(prop);
visible_properties.push_back(prop);
}
}
node->connect("dragged", this, "_node_dragged", varray(E->get()));
if (AnimationTreeEditor::get_singleton()->can_edit(agnode)) {
node->add_child(memnew(HSeparator));
Button *open_in_editor = memnew(Button);
open_in_editor->set_text(TTR("Open Editor"));
@ -169,7 +187,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
ProgressBar *pb = memnew(ProgressBar);
AnimationTree *player = anim->get_tree();
AnimationTree *player = AnimationTreeEditor::get_singleton()->get_tree();
if (player->has_node(player->get_animation_player())) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(player->get_node(player->get_animation_player()));
if (ap) {
@ -194,6 +212,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
mb->get_popup()->connect("index_pressed", this, "_anim_selected", varray(options, E->get()), CONNECT_DEFERRED);
}
/* should be no longer necesary, as the boolean works
Ref<AnimationNodeOneShot> oneshot = agnode;
if (oneshot.is_valid()) {
@ -209,7 +228,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
play_stop->add_child(stop);
play_stop->add_spacer();
node->add_child(play_stop);
}
} */
}
List<AnimationNodeBlendTree::NodeConnection> connections;
@ -225,16 +244,44 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
}
}
void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
void AnimationNodeBlendTreeEditor::_file_opened(const String &p_file) {
ERR_FAIL_INDEX(p_idx, add_options.size());
file_loaded = ResourceLoader::load(p_file);
if (file_loaded.is_valid()) {
_add_node(MENU_LOAD_FILE_CONFIRM);
}
}
void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
Ref<AnimationNode> anode;
if (add_options[p_idx].type != String()) {
String base_name;
if (p_idx == MENU_LOAD_FILE) {
open_file->clear_filters();
List<String> filters;
ResourceLoader::get_recognized_extensions_for_type("AnimationNode", &filters);
for (List<String>::Element *E = filters.front(); E; E = E->next()) {
open_file->add_filter("*." + E->get());
}
open_file->popup_centered_ratio();
return;
} else if (p_idx == MENU_LOAD_FILE_CONFIRM) {
anode = file_loaded;
file_loaded.unref();
base_name = anode->get_class();
} else if (p_idx == MENU_PASTE) {
anode = EditorSettings::get_singleton()->get_resource_clipboard();
ERR_FAIL_COND(!anode.is_valid());
base_name = anode->get_class();
} else if (add_options[p_idx].type != String()) {
AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instance(add_options[p_idx].type));
ERR_FAIL_COND(!an);
anode = Ref<AnimationNode>(an);
base_name = add_options[p_idx].name;
} else {
ERR_FAIL_COND(add_options[p_idx].script.is_null());
String base_type = add_options[p_idx].script->get_instance_base_type();
@ -242,13 +289,16 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
ERR_FAIL_COND(!an);
anode = Ref<AnimationNode>(an);
anode->set_script(add_options[p_idx].script.get_ref_ptr());
base_name = add_options[p_idx].name;
}
Ref<AnimationNodeOutput> out = anode;
if (out.is_valid()) {
EditorNode::get_singleton()->show_warning(TTR("Output node can't be added to the blend tree."));
return;
}
Point2 instance_pos = graph->get_scroll_ofs() + graph->get_size() * 0.5;
anode->set_position(instance_pos / EDSCALE);
String base_name = add_options[p_idx].name;
int base = 1;
String name = base_name;
while (blend_tree->has_node(name)) {
@ -257,19 +307,19 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
}
undo_redo->create_action("Add Node to BlendTree");
undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode);
undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode, instance_pos / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "remove_node", name);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
}
void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, Ref<AnimationNode> p_node) {
void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which) {
updating = true;
undo_redo->create_action("Node Moved");
undo_redo->add_do_method(p_node.ptr(), "set_position", p_to / EDSCALE);
undo_redo->add_undo_method(p_node.ptr(), "set_position", p_from / EDSCALE);
undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "set_node_position", p_which, p_from / EDSCALE);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
@ -342,20 +392,6 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
undo_redo->commit_action();
}
void AnimationNodeBlendTreeEditor::_oneshot_start(const StringName &p_name) {
Ref<AnimationNodeOneShot> os = blend_tree->get_node(p_name);
ERR_FAIL_COND(!os.is_valid());
os->start();
}
void AnimationNodeBlendTreeEditor::_oneshot_stop(const StringName &p_name) {
Ref<AnimationNodeOneShot> os = blend_tree->get_node(p_name);
ERR_FAIL_COND(!os.is_valid());
os->stop();
}
void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
@ -373,13 +409,7 @@ void AnimationNodeBlendTreeEditor::_open_in_editor(const String &p_which) {
Ref<AnimationNode> an = blend_tree->get_node(p_which);
ERR_FAIL_COND(!an.is_valid())
EditorNode::get_singleton()->edit_item(an.ptr());
}
void AnimationNodeBlendTreeEditor::_open_parent() {
if (blend_tree->get_parent().is_valid()) {
EditorNode::get_singleton()->edit_item(blend_tree->get_parent().ptr());
}
AnimationTreeEditor::get_singleton()->enter_editor(p_which);
}
void AnimationNodeBlendTreeEditor::_filter_toggled() {
@ -417,14 +447,14 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
if (updating || _filter_edit != anode)
return false;
NodePath player_path = anode->get_tree()->get_animation_player();
NodePath player_path = AnimationTreeEditor::get_singleton()->get_tree()->get_animation_player();
if (!anode->get_tree()->has_node(player_path)) {
if (!AnimationTreeEditor::get_singleton()->get_tree()->has_node(player_path)) {
EditorNode::get_singleton()->show_warning(TTR("No animation player set, so unable to retrieve track names."));
return false;
}
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(anode->get_tree()->get_node(player_path));
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(AnimationTreeEditor::get_singleton()->get_tree()->get_node(player_path));
if (!player) {
EditorNode::get_singleton()->show_warning(TTR("Player path set is invalid, so unable to retrieve track names."));
return false;
@ -593,8 +623,6 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
goto_parent->set_icon(get_icon("MoveUp", "EditorIcons"));
error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
error_label->add_color_override("font_color", get_color("error_color", "Editor"));
}
@ -603,12 +631,10 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
String error;
if (!blend_tree->get_tree()) {
error = TTR("BlendTree does not belong to an AnimationTree node.");
} else if (!blend_tree->get_tree()->is_active()) {
if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
} else if (blend_tree->get_tree()->is_state_invalid()) {
error = blend_tree->get_tree()->get_invalid_state_reason();
} else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
}
if (error != error_label->get_text()) {
@ -624,13 +650,13 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
blend_tree->get_node_connections(&conns);
for (List<AnimationNodeBlendTree::NodeConnection>::Element *E = conns.front(); E; E = E->next()) {
float activity = 0;
if (blend_tree->get_tree() && !blend_tree->get_tree()->is_state_invalid()) {
if (AnimationTreeEditor::get_singleton()->get_tree() && !AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
activity = blend_tree->get_connection_activity(E->get().input_node, E->get().input_index);
}
graph->set_connection_activity(E->get().output_node, 0, E->get().input_node, E->get().input_index, activity);
}
AnimationTree *graph_player = blend_tree->get_tree();
AnimationTree *graph_player = AnimationTreeEditor::get_singleton()->get_tree();
AnimationPlayer *player = NULL;
if (graph_player->has_node(graph_player->get_animation_player())) {
player = Object::cast_to<AnimationPlayer>(graph_player->get_node(graph_player->get_animation_player()));
@ -650,6 +676,14 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
}
}
}
for (int i = 0; i < visible_properties.size(); i++) {
visible_properties[i]->update_property();
}
}
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
set_process(is_visible_in_tree());
}
}
@ -664,9 +698,9 @@ void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) {
void AnimationNodeBlendTreeEditor::_node_changed(ObjectID p_node) {
AnimationNode *an = Object::cast_to<AnimationNode>(ObjectDB::get_instance(p_node));
if (an && an->get_parent() == blend_tree) {
_update_graph();
}
//if (an && an->get_parent() == blend_tree) {
_update_graph();
//}
}
void AnimationNodeBlendTreeEditor::_bind_methods() {
@ -680,17 +714,17 @@ void AnimationNodeBlendTreeEditor::_bind_methods() {
ClassDB::bind_method("_disconnection_request", &AnimationNodeBlendTreeEditor::_disconnection_request);
ClassDB::bind_method("_node_selected", &AnimationNodeBlendTreeEditor::_node_selected);
ClassDB::bind_method("_open_in_editor", &AnimationNodeBlendTreeEditor::_open_in_editor);
ClassDB::bind_method("_open_parent", &AnimationNodeBlendTreeEditor::_open_parent);
ClassDB::bind_method("_scroll_changed", &AnimationNodeBlendTreeEditor::_scroll_changed);
ClassDB::bind_method("_delete_request", &AnimationNodeBlendTreeEditor::_delete_request);
ClassDB::bind_method("_edit_filters", &AnimationNodeBlendTreeEditor::_edit_filters);
ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters);
ClassDB::bind_method("_filter_edited", &AnimationNodeBlendTreeEditor::_filter_edited);
ClassDB::bind_method("_filter_toggled", &AnimationNodeBlendTreeEditor::_filter_toggled);
ClassDB::bind_method("_oneshot_start", &AnimationNodeBlendTreeEditor::_oneshot_start);
ClassDB::bind_method("_oneshot_stop", &AnimationNodeBlendTreeEditor::_oneshot_stop);
ClassDB::bind_method("_node_changed", &AnimationNodeBlendTreeEditor::_node_changed);
ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendTreeEditor::_removed_from_graph);
ClassDB::bind_method("_property_changed", &AnimationNodeBlendTreeEditor::_property_changed);
ClassDB::bind_method("_file_opened", &AnimationNodeBlendTreeEditor::_file_opened);
ClassDB::bind_method("_update_options_menu", &AnimationNodeBlendTreeEditor::_update_options_menu);
ClassDB::bind_method("_anim_selected", &AnimationNodeBlendTreeEditor::_anim_selected);
}
@ -708,7 +742,9 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
ERR_FAIL_COND(new_name == "" || new_name.find(".") != -1 || new_name.find("/") != -1)
ERR_FAIL_COND(new_name == prev_name);
if (new_name == prev_name) {
return; //nothing to do
}
String base_name = new_name;
int base = 1;
@ -718,22 +754,61 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
name = base_name + " " + itos(base);
}
String base_path = AnimationTreeEditor::get_singleton()->get_base_path();
updating = true;
undo_redo->create_action("Node Renamed");
undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name);
undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name);
undo_redo->add_do_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + prev_name, base_path + name);
undo_redo->add_undo_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + name, base_path + prev_name);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
updating = false;
gn->set_name(new_name);
gn->set_size(gn->get_minimum_size());
//change editors accordingly
for (int i = 0; i < visible_properties.size(); i++) {
String pname = visible_properties[i]->get_edited_property().operator String();
if (pname.begins_with(base_path + prev_name)) {
String new_name = pname.replace_first(base_path + prev_name, base_path + name);
visible_properties[i]->set_object_and_property(visible_properties[i]->get_edited_object(), new_name);
}
}
}
void AnimationNodeBlendTreeEditor::_node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node) {
_node_renamed(le->call("get_text"), p_node);
}
bool AnimationNodeBlendTreeEditor::can_edit(const Ref<AnimationNode> &p_node) {
Ref<AnimationNodeBlendTree> bt = p_node;
return bt.is_valid();
}
void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
if (blend_tree.is_valid()) {
blend_tree->disconnect("removed_from_graph", this, "_removed_from_graph");
}
if (p_node.is_valid()) {
blend_tree = p_node;
} else {
blend_tree.unref();
}
if (blend_tree.is_null()) {
hide();
} else {
blend_tree->connect("removed_from_graph", this, "_removed_from_graph");
_update_graph();
}
}
AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
singleton = this;
@ -757,13 +832,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->get_zoom_hbox()->add_child(add_node);
add_node->set_text(TTR("Add Node.."));
graph->get_zoom_hbox()->move_child(add_node, 0);
add_node->get_popup()->connect("index_pressed", this, "_add_node");
goto_parent = memnew(Button);
graph->get_zoom_hbox()->add_child(goto_parent);
graph->get_zoom_hbox()->move_child(goto_parent, 0);
goto_parent->hide();
goto_parent->connect("pressed", this, "_open_parent");
add_node->get_popup()->connect("id_pressed", this, "_add_node");
add_node->connect("about_to_show", this, "_update_options_menu");
add_options.push_back(AddOption("Animation", "AnimationNodeAnimation"));
add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot"));
@ -804,45 +874,10 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
filters->set_hide_root(true);
filters->connect("item_edited", this, "_filter_edited");
open_file = memnew(EditorFileDialog);
add_child(open_file);
open_file->set_title(TTR("Open Animation Node"));
open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
open_file->connect("file_selected", this, "_file_opened");
undo_redo = EditorNode::get_singleton()->get_undo_redo();
}
void AnimationNodeBlendTreeEditorPlugin::edit(Object *p_object) {
anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendTree>(p_object));
}
bool AnimationNodeBlendTreeEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("AnimationNodeBlendTree");
}
void AnimationNodeBlendTreeEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
//editor->hide_animation_player_editors();
//editor->animation_panel_make_visible(true);
button->show();
editor->make_bottom_panel_item_visible(anim_tree_editor);
anim_tree_editor->set_process(true);
} else {
if (anim_tree_editor->is_visible_in_tree())
editor->hide_bottom_panel();
button->hide();
anim_tree_editor->set_process(false);
}
}
AnimationNodeBlendTreeEditorPlugin::AnimationNodeBlendTreeEditorPlugin(EditorNode *p_node) {
editor = p_node;
anim_tree_editor = memnew(AnimationNodeBlendTreeEditor);
anim_tree_editor->set_custom_minimum_size(Size2(0, 300));
button = editor->add_bottom_panel_item(TTR("BlendTree"), anim_tree_editor);
button->hide();
}
AnimationNodeBlendTreeEditorPlugin::~AnimationNodeBlendTreeEditorPlugin() {
}

View file

@ -3,6 +3,7 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/property_editor.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/gui/button.h"
@ -13,14 +14,13 @@
@author Juan Linietsky <reduzio@gmail.com>
*/
class AnimationNodeBlendTreeEditor : public VBoxContainer {
class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendTreeEditor, VBoxContainer);
GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendTree> blend_tree;
GraphEdit *graph;
MenuButton *add_node;
Button *goto_parent;
PanelContainer *error_panel;
Label *error_label;
@ -32,6 +32,7 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer {
CheckBox *filter_enabled;
Map<StringName, ProgressBar *> animations;
Vector<EditorProperty *> visible_properties;
void _update_graph();
@ -52,7 +53,7 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer {
static AnimationNodeBlendTreeEditor *singleton;
void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, Ref<AnimationNode> p_node);
void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which);
void _node_renamed(const String &p_text, Ref<AnimationNode> p_node);
void _node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node);
@ -64,11 +65,8 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer {
void _scroll_changed(const Vector2 &p_scroll);
void _node_selected(Object *p_node);
void _open_in_editor(const String &p_which);
void _open_parent();
void _anim_selected(int p_index, Array p_options, const String &p_node);
void _delete_request(const String &p_which);
void _oneshot_start(const StringName &p_name);
void _oneshot_stop(const StringName &p_name);
bool _update_filters(const Ref<AnimationNode> &anode);
void _edit_filters(const String &p_which);
@ -78,8 +76,19 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer {
void _node_changed(ObjectID p_node);
void _property_changed(const StringName &p_property, const Variant &p_value);
void _removed_from_graph();
EditorFileDialog *open_file;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
enum {
MENU_LOAD_FILE = 1000,
MENU_PASTE = 1001,
MENU_LOAD_FILE_CONFIRM = 1002
};
protected:
void _notification(int p_what);
static void _bind_methods();
@ -91,27 +100,11 @@ public:
void remove_custom_type(const Ref<Script> &p_script);
virtual Size2 get_minimum_size() const;
void edit(AnimationNodeBlendTree *p_blend_tree);
virtual bool can_edit(const Ref<AnimationNode> &p_node);
virtual void edit(const Ref<AnimationNode> &p_node);
AnimationNodeBlendTreeEditor();
};
class AnimationNodeBlendTreeEditorPlugin : public EditorPlugin {
GDCLASS(AnimationNodeBlendTreeEditorPlugin, EditorPlugin);
AnimationNodeBlendTreeEditor *anim_tree_editor;
EditorNode *editor;
Button *button;
public:
virtual String get_name() const { return "BlendTree"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
virtual bool handles(Object *p_object) const;
virtual void make_visible(bool p_visible);
AnimationNodeBlendTreeEditorPlugin(EditorNode *p_node);
~AnimationNodeBlendTreeEditorPlugin();
};
#endif // ANIMATION_BLEND_TREE_EDITOR_PLUGIN_H

View file

@ -11,22 +11,17 @@
#include "scene/gui/panel.h"
#include "scene/main/viewport.h"
void AnimationNodeStateMachineEditor::edit(AnimationNodeStateMachine *p_state_machine) {
bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node) {
Ref<AnimationNodeStateMachine> ansm = p_node;
return ansm.is_valid();
}
void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
state_machine = p_node;
if (state_machine.is_valid()) {
state_machine->disconnect("removed_from_graph", this, "_removed_from_graph");
}
if (p_state_machine) {
state_machine = Ref<AnimationNodeStateMachine>(p_state_machine);
} else {
state_machine.unref();
}
if (state_machine.is_null()) {
hide();
} else {
state_machine->connect("removed_from_graph", this, "_removed_from_graph");
selected_transition_from = StringName();
selected_transition_to = StringName();
@ -38,6 +33,10 @@ void AnimationNodeStateMachineEditor::edit(AnimationNodeStateMachine *p_state_ma
void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) {
Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
if (playback.is_null())
return;
Ref<InputEventKey> k = p_event;
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) {
if (selected_node != StringName() || selected_transition_to != StringName() || selected_transition_from != StringName()) {
@ -59,7 +58,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
menu->add_submenu_item(TTR("Add Animation"), "animations");
AnimationTree *gp = state_machine->get_tree();
AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
ERR_FAIL_COND(!gp);
if (gp && gp->has_node(gp->get_animation_player())) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
@ -79,9 +78,17 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
if (name == "Animation")
continue; // nope
int idx = menu->get_item_count();
menu->add_item(vformat("Add %s", name));
menu->add_item(vformat("Add %s", name), idx);
menu->set_item_metadata(idx, E->get());
}
Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
if (clipb.is_valid()) {
menu->add_separator();
menu->add_item(TTR("Paste"), MENU_PASTE);
}
menu->add_separator();
menu->add_item(TTR("Load.."), MENU_LOAD_FILE);
menu->set_global_position(state_machine_draw->get_global_transform().xform(mb->get_position()));
menu->popup();
@ -98,18 +105,12 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
if (node_rects[i].play.has_point(mb->get_position())) { //edit name
if (play_mode->get_selected() == 1 || !state_machine->is_playing()) {
if (play_mode->get_selected() == 1 || !playback->is_playing()) {
//start
state_machine->start(node_rects[i].node_name);
playback->start(node_rects[i].node_name);
} else {
//travel
if (!state_machine->travel(node_rects[i].node_name)) {
state_machine->start(node_rects[i].node_name);
//removing this due to usability..
//error_time = 5;
//error_text = vformat(TTR("No path found from '%s' to '%s'."), state_machine->get_current_node(), node_rects[i].node_name);
}
playback->travel(node_rects[i].node_name);
}
state_machine_draw->update();
return;
@ -196,8 +197,8 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<AnimationNode> an = state_machine->get_node(selected_node);
updating = true;
undo_redo->create_action("Move Node");
undo_redo->add_do_method(an.ptr(), "set_position", an->get_position() + drag_ofs / EDSCALE);
undo_redo->add_undo_method(an.ptr(), "set_position", an->get_position());
undo_redo->add_do_method(state_machine.ptr(), "set_node_position", selected_node, state_machine->get_node_position(selected_node) + drag_ofs / EDSCALE);
undo_redo->add_undo_method(state_machine.ptr(), "set_node_position", selected_node, state_machine->get_node_position(selected_node));
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
@ -293,7 +294,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
snap_y = StringName();
{
//snap
Vector2 cpos = state_machine->get_node(selected_node)->get_position() + drag_ofs / EDSCALE;
Vector2 cpos = state_machine->get_node_position(selected_node) + drag_ofs / EDSCALE;
List<StringName> nodes;
state_machine->get_node_list(&nodes);
@ -303,7 +304,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) {
if (E->get() == selected_node)
continue;
Vector2 npos = state_machine->get_node(E->get())->get_position();
Vector2 npos = state_machine->get_node_position(E->get());
float d_x = ABS(npos.x - cpos.x);
if (d_x < MIN(5, best_d_x)) {
@ -372,19 +373,58 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
void AnimationNodeStateMachineEditor::_file_opened(const String &p_file) {
file_loaded = ResourceLoader::load(p_file);
if (file_loaded.is_valid()) {
_add_menu_type(MENU_LOAD_FILE_CONFIRM);
}
}
void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
String type = menu->get_item_metadata(p_index);
String base_name;
Ref<AnimationRootNode> node;
Object *obj = ClassDB::instance(type);
ERR_FAIL_COND(!obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
ERR_FAIL_COND(!an);
if (p_index == MENU_LOAD_FILE) {
Ref<AnimationNode> node(an);
node->set_position(add_node_pos);
open_file->clear_filters();
List<String> filters;
ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters);
for (List<String>::Element *E = filters.front(); E; E = E->next()) {
open_file->add_filter("*." + E->get());
}
open_file->popup_centered_ratio();
return;
} else if (p_index == MENU_LOAD_FILE_CONFIRM) {
node = file_loaded;
file_loaded.unref();
} else if (p_index == MENU_PASTE) {
node = EditorSettings::get_singleton()->get_resource_clipboard();
} else {
String type = menu->get_item_metadata(p_index);
Object *obj = ClassDB::instance(type);
ERR_FAIL_COND(!obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
ERR_FAIL_COND(!an);
node = Ref<AnimationNode>(an);
base_name = type.replace_first("AnimationNode", "");
}
if (!node.is_valid()) {
EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed."));
return;
}
if (base_name == String()) {
base_name = node->get_class().replace_first("AnimationNode", "");
}
String base_name = type.replace_first("AnimationNode", "");
int base = 1;
String name = base_name;
while (state_machine->has_node(name)) {
@ -394,7 +434,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
updating = true;
undo_redo->create_action("Add Node");
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node);
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node, add_node_pos);
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
@ -419,11 +459,9 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
name = base_name + " " + itos(base);
}
anim->set_position(add_node_pos);
updating = true;
undo_redo->create_action("Add Node");
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim);
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim, add_node_pos);
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
@ -502,6 +540,8 @@ void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(Vector2 &r_from, Ve
void AnimationNodeStateMachineEditor::_state_machine_draw() {
Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
Ref<StyleBox> style = get_stylebox("frame", "GraphNode");
Ref<StyleBox> style_selected = get_stylebox("selectedframe", "GraphNode");
@ -515,10 +555,17 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
linecolor.a *= 0.3;
Ref<StyleBox> playing_overlay = get_stylebox("position", "GraphNode");
bool playing = state_machine->is_playing();
StringName current = state_machine->get_current_node();
StringName blend_from = state_machine->get_blend_from_node();
Vector<StringName> travel_path = state_machine->get_travel_path();
bool playing = false;
StringName current;
StringName blend_from;
Vector<StringName> travel_path;
if (playback.is_valid()) {
playing = playback->is_playing();
current = playback->get_current_node();
blend_from = playback->get_blend_from_node();
travel_path = playback->get_travel_path();
}
if (state_machine_draw->has_focus()) {
state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), accent, false);
@ -534,13 +581,13 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
//snap lines
if (dragging_selected) {
Vector2 from = (state_machine->get_node(selected_node)->get_position() * EDSCALE) + drag_ofs - state_machine->get_graph_offset() * EDSCALE;
Vector2 from = (state_machine->get_node_position(selected_node) * EDSCALE) + drag_ofs - state_machine->get_graph_offset() * EDSCALE;
if (snap_x != StringName()) {
Vector2 to = (state_machine->get_node(snap_x)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
Vector2 to = (state_machine->get_node_position(snap_x) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
state_machine_draw->draw_line(from, to, linecolor, 2);
}
if (snap_y != StringName()) {
Vector2 to = (state_machine->get_node(snap_y)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
Vector2 to = (state_machine->get_node_position(snap_y) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
state_machine_draw->draw_line(from, to, linecolor, 2);
}
}
@ -563,7 +610,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
}
Vector2 offset;
offset += anode->get_position() * EDSCALE;
offset += state_machine->get_node_position(E->get()) * EDSCALE;
if (selected_node == E->get() && dragging_selected) {
offset += drag_ofs;
}
@ -588,10 +635,10 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
//draw conecting line for potential new transition
if (connecting) {
Vector2 from = (state_machine->get_node(connecting_from)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
Vector2 from = (state_machine->get_node_position(connecting_from) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
Vector2 to;
if (connecting_to_node != StringName()) {
to = (state_machine->get_node(connecting_to_node)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
to = (state_machine->get_node_position(connecting_to_node) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
} else {
to = connecting_to;
}
@ -617,15 +664,17 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
TransitionLine tl;
tl.from_node = state_machine->get_transition_from(i);
Vector2 ofs_from = (dragging_selected && tl.from_node == selected_node) ? drag_ofs : Vector2();
tl.from = (state_machine->get_node(tl.from_node)->get_position() * EDSCALE) + ofs_from - state_machine->get_graph_offset() * EDSCALE;
tl.from = (state_machine->get_node_position(tl.from_node) * EDSCALE) + ofs_from - state_machine->get_graph_offset() * EDSCALE;
tl.to_node = state_machine->get_transition_to(i);
Vector2 ofs_to = (dragging_selected && tl.to_node == selected_node) ? drag_ofs : Vector2();
tl.to = (state_machine->get_node(tl.to_node)->get_position() * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE;
tl.to = (state_machine->get_node_position(tl.to_node) * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE;
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i);
tl.disabled = tr->is_disabled();
tl.auto_advance = tr->has_auto_advance();
tl.advance_condition_name = tr->get_advance_condition_name();
tl.advance_condition_state = false;
tl.mode = tr->get_switch_mode();
tl.width = tr_bidi_offset;
@ -665,7 +714,14 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
}
}
}
_connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, selected, travel, tl.auto_advance);
bool auto_advance = tl.auto_advance;
StringName fullpath = AnimationTreeEditor::get_singleton()->get_base_path() + String(tl.advance_condition_name);
if (tl.advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(fullpath))) {
tl.advance_condition_state = true;
auto_advance = true;
}
_connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, selected, travel, auto_advance);
transition_lines.push_back(tl);
}
@ -675,7 +731,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
String name = node_rects[i].node_name;
Ref<AnimationNode> anode = state_machine->get_node(name);
bool needs_editor = EditorNode::get_singleton()->item_has_editor(anode.ptr());
bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode);
Ref<StyleBox> sb = name == selected_node ? style_selected : style;
int strsize = font->get_string_size(name).width;
@ -757,12 +813,14 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
if (!state_machine->is_playing())
Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
if (!playback.is_valid() || !playback->is_playing())
return;
int idx = -1;
for (int i = 0; node_rects.size(); i++) {
if (node_rects[i].node_name == state_machine->get_current_node()) {
if (node_rects[i].node_name == playback->get_current_node()) {
idx = i;
break;
}
@ -785,9 +843,9 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
}
to.y = from.y;
float len = MAX(0.0001, state_machine->get_current_length());
float len = MAX(0.0001, playback->get_current_length());
float pos = CLAMP(state_machine->get_current_play_pos(), 0, len);
float pos = CLAMP(playback->get_current_play_pos(), 0, len);
float c = pos / len;
Color fg = get_color("font_color", "Label");
Color bg = fg;
@ -807,12 +865,6 @@ void AnimationNodeStateMachineEditor::_update_graph() {
updating = true;
if (state_machine->get_parent().is_valid()) {
goto_parent_hbox->show();
} else {
goto_parent_hbox->hide();
}
state_machine_draw->update();
updating = false;
@ -824,7 +876,6 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
error_label->add_color_override("font_color", get_color("error_color", "Editor"));
panel->add_style_override("panel", get_stylebox("bg", "Tree"));
goto_parent->set_icon(get_icon("MoveUp", "EditorIcons"));
tool_select->set_icon(get_icon("ToolSelect", "EditorIcons"));
tool_create->set_icon(get_icon("ToolAddNode", "EditorIcons"));
@ -856,19 +907,21 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
String error;
Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
if (error_time > 0) {
error = error_text;
error_time -= get_process_delta_time();
} else if (!state_machine->get_tree()) {
error = TTR("StateMachine does not belong to an AnimationTree node.");
} else if (!state_machine->get_tree()->is_active()) {
} else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
} else if (state_machine->get_tree()->is_state_invalid()) {
error = state_machine->get_tree()->get_invalid_state_reason();
} else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) {
} else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
/*} else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) {
if (state_machine->get_start_node() == StringName() || state_machine->get_end_node() == StringName()) {
error = TTR("Start and end nodes are needed for a sub-transition.");
}
}*/
} else if (playback.is_null()) {
error = vformat(TTR("No playback resource set at path: %s."), AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
}
if (error != error_label->get_text()) {
@ -904,14 +957,38 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
break;
}
if (transition_lines[i].advance_condition_name != state_machine->get_transition(tidx)->get_advance_condition_name()) {
state_machine_draw->update();
break;
}
if (transition_lines[i].mode != state_machine->get_transition(tidx)->get_switch_mode()) {
state_machine_draw->update();
break;
}
bool acstate = transition_lines[i].advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + String(transition_lines[i].advance_condition_name)));
if (transition_lines[i].advance_condition_state != acstate) {
state_machine_draw->update();
break;
}
}
bool same_travel_path = true;
Vector<StringName> tp = state_machine->get_travel_path();
Vector<StringName> tp;
bool is_playing = false;
StringName current_node;
StringName blend_from_node;
float play_pos = 0;
if (playback.is_valid()) {
tp = playback->get_travel_path();
is_playing = playback->is_playing();
current_node = playback->get_current_node();
blend_from_node = playback->get_blend_from_node();
play_pos = playback->get_current_play_pos();
}
{
@ -928,37 +1005,32 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
}
//update if travel state changed
if (!same_travel_path || last_active != state_machine->is_playing() || last_current_node != state_machine->get_current_node() || last_blend_from_node != state_machine->get_blend_from_node()) {
if (!same_travel_path || last_active != is_playing || last_current_node != current_node || last_blend_from_node != blend_from_node) {
state_machine_draw->update();
last_travel_path = tp;
last_current_node = state_machine->get_current_node();
last_active = state_machine->is_playing();
last_blend_from_node = state_machine->get_blend_from_node();
last_current_node = current_node;
last_active = is_playing;
last_blend_from_node = blend_from_node;
state_machine_play_pos->update();
}
if (last_play_pos != state_machine->get_current_play_pos()) {
if (last_play_pos != play_pos) {
last_play_pos = state_machine->get_current_play_pos();
last_play_pos = play_pos;
state_machine_play_pos->update();
}
}
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
over_node = StringName();
set_process(is_visible_in_tree());
}
}
void AnimationNodeStateMachineEditor::_open_editor(const String &p_name) {
Ref<AnimationNode> an = state_machine->get_node(p_name);
ERR_FAIL_COND(!an.is_valid());
EditorNode::get_singleton()->edit_item(an.ptr());
}
void AnimationNodeStateMachineEditor::_goto_parent() {
EditorNode::get_singleton()->edit_item(state_machine->get_parent().ptr());
AnimationTreeEditor::get_singleton()->enter_editor(p_name);
}
void AnimationNodeStateMachineEditor::_removed_from_graph() {
@ -1114,7 +1186,6 @@ void AnimationNodeStateMachineEditor::_bind_methods() {
ClassDB::bind_method("_name_edited", &AnimationNodeStateMachineEditor::_name_edited);
ClassDB::bind_method("_goto_parent", &AnimationNodeStateMachineEditor::_goto_parent);
ClassDB::bind_method("_removed_from_graph", &AnimationNodeStateMachineEditor::_removed_from_graph);
ClassDB::bind_method("_open_editor", &AnimationNodeStateMachineEditor::_open_editor);
@ -1124,6 +1195,7 @@ void AnimationNodeStateMachineEditor::_bind_methods() {
ClassDB::bind_method("_autoplay_selected", &AnimationNodeStateMachineEditor::_autoplay_selected);
ClassDB::bind_method("_end_selected", &AnimationNodeStateMachineEditor::_end_selected);
ClassDB::bind_method("_update_mode", &AnimationNodeStateMachineEditor::_update_mode);
ClassDB::bind_method("_file_opened", &AnimationNodeStateMachineEditor::_file_opened);
}
AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = NULL;
@ -1136,13 +1208,6 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
HBoxContainer *top_hb = memnew(HBoxContainer);
add_child(top_hb);
goto_parent_hbox = memnew(HBoxContainer);
goto_parent = memnew(ToolButton);
goto_parent->connect("pressed", this, "_goto_parent", varray(), CONNECT_DEFERRED);
goto_parent_hbox->add_child(goto_parent);
goto_parent_hbox->add_child(memnew(VSeparator));
top_hb->add_child(goto_parent_hbox);
Ref<ButtonGroup> bg;
bg.instance();
@ -1248,7 +1313,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
menu = memnew(PopupMenu);
add_child(menu);
menu->connect("index_pressed", this, "_add_menu_type");
menu->connect("id_pressed", this, "_add_menu_type");
animations_menu = memnew(PopupMenu);
menu->add_child(animations_menu);
@ -1261,6 +1326,13 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
name_edit->connect("text_entered", this, "_name_edited");
name_edit->set_as_toplevel(true);
open_file = memnew(EditorFileDialog);
add_child(open_file);
open_file->set_title(TTR("Open Animation Node"));
open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
open_file->connect("file_selected", this, "_file_opened");
undo_redo = EditorNode::get_singleton()->get_undo_redo();
over_text = false;
over_node_what = -1;
@ -1271,43 +1343,3 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
error_time = 0;
}
void AnimationNodeStateMachineEditorPlugin::edit(Object *p_object) {
anim_tree_editor->edit(Object::cast_to<AnimationNodeStateMachine>(p_object));
}
bool AnimationNodeStateMachineEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("AnimationNodeStateMachine");
}
void AnimationNodeStateMachineEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
//editor->hide_animation_player_editors();
//editor->animation_panel_make_visible(true);
button->show();
editor->make_bottom_panel_item_visible(anim_tree_editor);
anim_tree_editor->set_process(true);
} else {
if (anim_tree_editor->is_visible_in_tree())
editor->hide_bottom_panel();
button->hide();
anim_tree_editor->set_process(false);
}
}
AnimationNodeStateMachineEditorPlugin::AnimationNodeStateMachineEditorPlugin(EditorNode *p_node) {
editor = p_node;
anim_tree_editor = memnew(AnimationNodeStateMachineEditor);
anim_tree_editor->set_custom_minimum_size(Size2(0, 300));
button = editor->add_bottom_panel_item(TTR("StateMachine"), anim_tree_editor);
button->hide();
}
AnimationNodeStateMachineEditorPlugin::~AnimationNodeStateMachineEditorPlugin() {
}

View file

@ -3,6 +3,7 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/property_editor.h"
#include "scene/animation/animation_node_state_machine.h"
#include "scene/gui/button.h"
@ -10,9 +11,9 @@
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
class AnimationNodeStateMachineEditor : public VBoxContainer {
class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeStateMachineEditor, VBoxContainer);
GDCLASS(AnimationNodeStateMachineEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeStateMachine> state_machine;
@ -29,9 +30,6 @@ class AnimationNodeStateMachineEditor : public VBoxContainer {
OptionButton *transition_mode;
OptionButton *play_mode;
HBoxContainer *goto_parent_hbox;
ToolButton *goto_parent;
PanelContainer *panel;
StringName selected_node;
@ -79,8 +77,6 @@ class AnimationNodeStateMachineEditor : public VBoxContainer {
void _add_menu_type(int p_index);
void _add_animation_type(int p_index);
void _goto_parent();
void _removed_from_graph();
struct NodeRect {
@ -99,6 +95,8 @@ class AnimationNodeStateMachineEditor : public VBoxContainer {
Vector2 from;
Vector2 to;
AnimationNodeStateMachineTransition::SwitchMode mode;
StringName advance_condition_name;
bool advance_condition_state;
bool disabled;
bool auto_advance;
float width;
@ -135,33 +133,25 @@ class AnimationNodeStateMachineEditor : public VBoxContainer {
float error_time;
String error_text;
EditorFileDialog *open_file;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
enum {
MENU_LOAD_FILE = 1000,
MENU_PASTE = 1001,
MENU_LOAD_FILE_CONFIRM = 1002
};
protected:
void _notification(int p_what);
static void _bind_methods();
public:
static AnimationNodeStateMachineEditor *get_singleton() { return singleton; }
void edit(AnimationNodeStateMachine *p_state_machine);
virtual bool can_edit(const Ref<AnimationNode> &p_node);
virtual void edit(const Ref<AnimationNode> &p_node);
AnimationNodeStateMachineEditor();
};
class AnimationNodeStateMachineEditorPlugin : public EditorPlugin {
GDCLASS(AnimationNodeStateMachineEditorPlugin, EditorPlugin);
AnimationNodeStateMachineEditor *anim_tree_editor;
EditorNode *editor;
Button *button;
public:
virtual String get_name() const { return "StateMachine"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
virtual bool handles(Object *p_object) const;
virtual void make_visible(bool p_visible);
AnimationNodeStateMachineEditorPlugin(EditorNode *p_node);
~AnimationNodeStateMachineEditorPlugin();
};
#endif // ANIMATION_STATE_MACHINE_EDITOR_H

File diff suppressed because it is too large Load diff

View file

@ -1,167 +1,65 @@
/*************************************************************************/
/* animation_tree_editor_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef ANIMATION_TREE_EDITOR_PLUGIN_H
#define ANIMATION_TREE_EDITOR_PLUGIN_H
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/property_editor.h"
#include "scene/animation/animation_tree_player.h"
#include "scene/animation/animation_tree.h"
#include "scene/gui/button.h"
#include "scene/gui/graph_edit.h"
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class AnimationTreeEditor : public Control {
class AnimationTreeNodeEditorPlugin : public VBoxContainer {
GDCLASS(AnimationTreeNodeEditorPlugin, VBoxContainer)
public:
virtual bool can_edit(const Ref<AnimationNode> &p_node) = 0;
virtual void edit(const Ref<AnimationNode> &p_node) = 0;
};
GDCLASS(AnimationTreeEditor, Control);
class AnimationTreeEditor : public VBoxContainer {
static const char *_node_type_names[];
GDCLASS(AnimationTreeEditor, VBoxContainer);
enum ClickType {
CLICK_NONE,
CLICK_NAME,
CLICK_NODE,
CLICK_INPUT_SLOT,
CLICK_OUTPUT_SLOT,
CLICK_PARAMETER
};
ScrollContainer *path_edit;
HBoxContainer *path_hb;
enum {
AnimationTree *tree;
PanelContainer *editor_base;
MENU_GRAPH_CLEAR = 100,
MENU_IMPORT_ANIMATIONS = 101,
NODE_DISCONNECT,
NODE_RENAME,
NODE_ERASE,
NODE_ADD_INPUT,
NODE_DELETE_INPUT,
NODE_SET_AUTOADVANCE,
NODE_CLEAR_AUTOADVANCE
};
Vector<String> button_path;
Vector<String> edited_path;
Vector<AnimationTreeNodeEditorPlugin *> editors;
bool renaming_edit;
StringName edited_node;
bool updating_edit;
Popup *edit_dialog;
HSlider *edit_scroll[2];
LineEdit *edit_line[4];
OptionButton *edit_option;
Label *edit_label[4];
Button *edit_button;
Button *filter_button;
CheckButton *edit_check;
EditorFileDialog *file_dialog;
int file_op;
void _update_path();
void _about_to_show_root();
ObjectID current_root;
void _popup_edit_dialog();
void _path_button_pressed(int p_path);
void _setup_edit_dialog(const StringName &p_node);
PopupMenu *master_anim_popup;
PopupMenu *node_popup;
PopupMenu *add_popup;
HScrollBar *h_scroll;
VScrollBar *v_scroll;
MenuButton *add_menu;
CustomPropertyEditor *property_editor;
AnimationTreePlayer *anim_tree;
List<StringName> order;
Set<StringName> active_nodes;
int last_x, last_y;
Point2 offset;
ClickType click_type;
Point2 click_pos;
StringName click_node;
int click_slot;
Point2 click_motion;
ClickType rclick_type;
StringName rclick_node;
int rclick_slot;
Button *play_button;
Size2 _get_maximum_size();
Size2 get_node_size(const StringName &p_node) const;
void _draw_node(const StringName &p_node);
AcceptDialog *filter_dialog;
Tree *filter;
void _draw_cos_line(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color);
void _update_scrollbars();
void _scroll_moved(float);
void _play_toggled();
/*
void _node_param_changed();
void _node_add_callback();
void _node_add(VisualServer::AnimationTreeNodeType p_type);
void _node_edit_property(const StringName& p_node);
*/
void _master_anim_menu_item(int p_item);
void _node_menu_item(int p_item);
void _add_menu_item(int p_item);
void _filter_edited();
void _find_paths_for_filter(const StringName &p_node, Set<String> &paths);
void _edit_filters();
void _edit_oneshot_start();
void _edit_dialog_animation_changed();
void _edit_dialog_edit_animation();
void _edit_dialog_changeds(String);
void _edit_dialog_changede(String);
void _edit_dialog_changedf(float);
void _edit_dialog_changed();
void _dialog_changed() const;
ClickType _locate_click(const Point2 &p_click, StringName *p_node_id, int *p_slot_index) const;
Point2 _get_slot_pos(const StringName &p_node_id, bool p_input, int p_slot);
StringName _add_node(int p_item);
void _file_dialog_selected(String p_path);
static Vector<String> get_animation_list();
protected:
void _notification(int p_what);
void _gui_input(Ref<InputEvent> p_event);
static void _bind_methods();
static AnimationTreeEditor *singleton;
public:
virtual Size2 get_minimum_size() const;
void edit(AnimationTreePlayer *p_anim_tree);
AnimationTree *get_tree() { return tree; }
void add_plugin(AnimationTreeNodeEditorPlugin *p_editor);
void remove_plugin(AnimationTreeNodeEditorPlugin *p_editor);
String get_base_path();
bool can_edit(const Ref<AnimationNode> &p_node) const;
void edit_path(const Vector<String> &p_path);
Vector<String> get_edited_path() const;
void enter_editor(const String &p_path = "");
static AnimationTreeEditor *get_singleton() { return singleton; }
void edit(AnimationTree *p_tree);
AnimationTreeEditor();
};
@ -174,7 +72,7 @@ class AnimationTreeEditorPlugin : public EditorPlugin {
Button *button;
public:
virtual String get_name() const { return "AnimTree"; }
virtual String get_name() const { return "AnimationTree"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
virtual bool handles(Object *p_object) const;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,187 @@
/*************************************************************************/
/* animation_tree_editor_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef ANIMATION_TREE_PLAYER_EDITOR_PLUGIN_H
#define ANIMATION_TREE_PLAYER_EDITOR_PLUGIN_H
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/property_editor.h"
#include "scene/animation/animation_tree_player.h"
#include "scene/gui/button.h"
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class AnimationTreePlayerEditor : public Control {
GDCLASS(AnimationTreePlayerEditor, Control);
static const char *_node_type_names[];
enum ClickType {
CLICK_NONE,
CLICK_NAME,
CLICK_NODE,
CLICK_INPUT_SLOT,
CLICK_OUTPUT_SLOT,
CLICK_PARAMETER
};
enum {
MENU_GRAPH_CLEAR = 100,
MENU_IMPORT_ANIMATIONS = 101,
NODE_DISCONNECT,
NODE_RENAME,
NODE_ERASE,
NODE_ADD_INPUT,
NODE_DELETE_INPUT,
NODE_SET_AUTOADVANCE,
NODE_CLEAR_AUTOADVANCE
};
bool renaming_edit;
StringName edited_node;
bool updating_edit;
Popup *edit_dialog;
HSlider *edit_scroll[2];
LineEdit *edit_line[4];
OptionButton *edit_option;
Label *edit_label[4];
Button *edit_button;
Button *filter_button;
CheckButton *edit_check;
EditorFileDialog *file_dialog;
int file_op;
void _popup_edit_dialog();
void _setup_edit_dialog(const StringName &p_node);
PopupMenu *master_anim_popup;
PopupMenu *node_popup;
PopupMenu *add_popup;
HScrollBar *h_scroll;
VScrollBar *v_scroll;
MenuButton *add_menu;
CustomPropertyEditor *property_editor;
AnimationTreePlayer *anim_tree;
List<StringName> order;
Set<StringName> active_nodes;
int last_x, last_y;
Point2 offset;
ClickType click_type;
Point2 click_pos;
StringName click_node;
int click_slot;
Point2 click_motion;
ClickType rclick_type;
StringName rclick_node;
int rclick_slot;
Button *play_button;
Size2 _get_maximum_size();
Size2 get_node_size(const StringName &p_node) const;
void _draw_node(const StringName &p_node);
AcceptDialog *filter_dialog;
Tree *filter;
void _draw_cos_line(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color);
void _update_scrollbars();
void _scroll_moved(float);
void _play_toggled();
/*
void _node_param_changed();
void _node_add_callback();
void _node_add(VisualServer::AnimationTreeNodeType p_type);
void _node_edit_property(const StringName& p_node);
*/
void _master_anim_menu_item(int p_item);
void _node_menu_item(int p_item);
void _add_menu_item(int p_item);
void _filter_edited();
void _find_paths_for_filter(const StringName &p_node, Set<String> &paths);
void _edit_filters();
void _edit_oneshot_start();
void _edit_dialog_animation_changed();
void _edit_dialog_edit_animation();
void _edit_dialog_changeds(String);
void _edit_dialog_changede(String);
void _edit_dialog_changedf(float);
void _edit_dialog_changed();
void _dialog_changed() const;
ClickType _locate_click(const Point2 &p_click, StringName *p_node_id, int *p_slot_index) const;
Point2 _get_slot_pos(const StringName &p_node_id, bool p_input, int p_slot);
StringName _add_node(int p_item);
void _file_dialog_selected(String p_path);
protected:
void _notification(int p_what);
void _gui_input(Ref<InputEvent> p_event);
static void _bind_methods();
public:
virtual Size2 get_minimum_size() const;
void edit(AnimationTreePlayer *p_anim_tree);
AnimationTreePlayerEditor();
};
class AnimationTreePlayerEditorPlugin : public EditorPlugin {
GDCLASS(AnimationTreePlayerEditorPlugin, EditorPlugin);
AnimationTreePlayerEditor *anim_tree_editor;
EditorNode *editor;
Button *button;
public:
virtual String get_name() const { return "AnimTree"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
virtual bool handles(Object *p_object) const;
virtual void make_visible(bool p_visible);
AnimationTreePlayerEditorPlugin(EditorNode *p_node);
~AnimationTreePlayerEditorPlugin();
};
#endif // ANIMATION_TREE_EDITOR_PLUGIN_H

View file

@ -1394,13 +1394,9 @@ void KinematicBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody::get_slide_count);
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody::_get_slide_collision);
ADD_GROUP("Axis Lock", "axis_lock_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_X);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Y);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Z);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_x", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_y", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_z", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
}

View file

@ -1,12 +1,15 @@
#include "animation_blend_space_1d.h"
void AnimationNodeBlendSpace1D::set_tree(AnimationTree *p_player) {
AnimationRootNode::set_tree(p_player);
void AnimationNodeBlendSpace1D::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::REAL,blend_position));
}
Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName &p_parameter) const {
return 0;
}
for (int i = 0; i < blend_points_used; i++) {
blend_points[i].node->set_tree(p_player);
}
Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) {
return get_blend_point_node(p_name.operator String().to_int());
}
void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const {
@ -20,6 +23,10 @@ void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const
AnimationRootNode::_validate_property(property);
}
void AnimationNodeBlendSpace1D::_tree_changed() {
emit_signal("tree_changed");
}
void AnimationNodeBlendSpace1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace1D::add_blend_point, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace1D::set_blend_point_position);
@ -38,30 +45,37 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace1D::set_snap);
ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace1D::get_snap);
ClassDB::bind_method(D_METHOD("set_blend_pos", "pos"), &AnimationNodeBlendSpace1D::set_blend_pos);
ClassDB::bind_method(D_METHOD("get_blend_pos"), &AnimationNodeBlendSpace1D::get_blend_pos);
ClassDB::bind_method(D_METHOD("set_value_label", "text"), &AnimationNodeBlendSpace1D::set_value_label);
ClassDB::bind_method(D_METHOD("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label);
ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace1D::_add_blend_point);
ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace1D::_tree_changed);
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "_add_blend_point", "get_blend_point_node", i);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_add_blend_point", "get_blend_point_node", i);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i);
}
ADD_PROPERTY(PropertyInfo(Variant::REAL, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_min_space", "get_min_space");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_space", "get_max_space");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "blend_pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_blend_pos", "get_blend_pos");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_value_label", "get_value_label");
}
void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
for(int i=0;i<blend_points_used;i++) {
ChildNode cn;
cn.name=itos(i);
cn.node=blend_points[i].node;
r_child_nodes->push_back(cn);
}
}
void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index) {
ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS);
ERR_FAIL_COND(p_node.is_null());
ERR_FAIL_COND(p_node->get_parent().is_valid());
ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used);
if (p_at_index == -1 || p_at_index == blend_points_used) {
@ -75,10 +89,12 @@ void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_
blend_points[p_at_index].node = p_node;
blend_points[p_at_index].position = p_position;
blend_points[p_at_index].node->set_parent(this);
blend_points[p_at_index].node->set_tree(get_tree());
blend_points[p_at_index].node->connect("tree_changed",this,"_tree_changed",varray(),CONNECT_REFERENCE_COUNTED);
blend_points_used++;
emit_signal("tree_changed");
}
void AnimationNodeBlendSpace1D::set_blend_point_position(int p_point, float p_position) {
@ -92,13 +108,14 @@ void AnimationNodeBlendSpace1D::set_blend_point_node(int p_point, const Ref<Anim
ERR_FAIL_COND(p_node.is_null());
if (blend_points[p_point].node.is_valid()) {
blend_points[p_point].node->set_parent(NULL);
blend_points[p_point].node->set_tree(NULL);
blend_points[p_point].node->disconnect("tree_changed",this,"_tree_changed");
}
blend_points[p_point].node = p_node;
blend_points[p_point].node->set_parent(this);
blend_points[p_point].node->set_tree(get_tree());
blend_points[p_point].node->connect("tree_changed",this,"_tree_changed",varray(),CONNECT_REFERENCE_COUNTED);
emit_signal("tree_changed");
}
float AnimationNodeBlendSpace1D::get_blend_point_position(int p_point) const {
@ -114,14 +131,16 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace1D::get_blend_point_node(int p_poi
void AnimationNodeBlendSpace1D::remove_blend_point(int p_point) {
ERR_FAIL_INDEX(p_point, blend_points_used);
blend_points[p_point].node->set_parent(NULL);
blend_points[p_point].node->set_tree(NULL);
blend_points[p_point].node->disconnect("tree_changed",this,"_tree_changed");
for (int i = p_point; i < blend_points_used - 1; i++) {
blend_points[i] = blend_points[i + 1];
}
blend_points_used--;
emit_signal("tree_changed");
}
int AnimationNodeBlendSpace1D::get_blend_point_count() const {
@ -161,13 +180,6 @@ float AnimationNodeBlendSpace1D::get_snap() const {
return snap;
}
void AnimationNodeBlendSpace1D::set_blend_pos(float p_pos) {
blend_pos = p_pos;
}
float AnimationNodeBlendSpace1D::get_blend_pos() const {
return blend_pos;
}
void AnimationNodeBlendSpace1D::set_value_label(const String &p_label) {
value_label = p_label;
@ -191,11 +203,14 @@ float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) {
return 0.0;
}
if (blend_points_used == 1) {
// only one point available, just play that animation
return blend_node(blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false);
return blend_node(blend_points[0].name,blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false);
}
float blend_pos = get_parameter(blend_position);
float weights[MAX_BLEND_POINTS] = {};
int point_lower = -1;
@ -262,7 +277,7 @@ float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) {
float max_time_remaining = 0.0;
for (int i = 0; i < blend_points_used; i++) {
float remaining = blend_node(blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false);
float remaining = blend_node(blend_points[i].name,blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false);
max_time_remaining = MAX(max_time_remaining, remaining);
}
@ -276,18 +291,19 @@ String AnimationNodeBlendSpace1D::get_caption() const {
AnimationNodeBlendSpace1D::AnimationNodeBlendSpace1D() {
for(int i=0;i<MAX_BLEND_POINTS;i++) {
blend_points[i].name=itos(i);
}
blend_points_used = 0;
max_space = 1;
min_space = -1;
snap = 0.1;
value_label = "value";
blend_position="blend_position";
}
AnimationNodeBlendSpace1D::~AnimationNodeBlendSpace1D() {
for (int i = 0; i < blend_points_used; i++) {
blend_points[i].node->set_parent(this);
blend_points[i].node->set_tree(get_tree());
}
}

View file

@ -11,6 +11,7 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
};
struct BlendPoint {
StringName name;
Ref<AnimationRootNode> node;
float position;
};
@ -18,8 +19,6 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
BlendPoint blend_points[MAX_BLEND_POINTS];
int blend_points_used;
float blend_pos;
float max_space;
float min_space;
@ -29,12 +28,21 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node);
void _tree_changed();
StringName blend_position;
protected:
virtual void _validate_property(PropertyInfo &property) const;
static void _bind_methods();
public:
virtual void set_tree(AnimationTree *p_player);
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
void add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index = -1);
void set_blend_point_position(int p_point, float p_position);
@ -54,15 +62,14 @@ public:
void set_snap(float p_snap);
float get_snap() const;
void set_blend_pos(float p_pos);
float get_blend_pos() const;
void set_value_label(const String &p_label);
String get_value_label() const;
float process(float p_time, bool p_seek);
String get_caption() const;
Ref<AnimationNode> get_child_by_name(const StringName &p_name);
AnimationNodeBlendSpace1D();
~AnimationNodeBlendSpace1D();
};

View file

@ -1,18 +1,27 @@
#include "animation_blend_space_2d.h"
#include "math/delaunay.h"
void AnimationNodeBlendSpace2D::set_tree(AnimationTree *p_player) {
AnimationRootNode::set_tree(p_player);
for (int i = 0; i < blend_points_used; i++) {
blend_points[i].node->set_tree(p_player);
void AnimationNodeBlendSpace2D::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::VECTOR2,blend_position));
}
Variant AnimationNodeBlendSpace2D::get_parameter_default_value(const StringName &p_parameter) const {
return Vector2();
}
void AnimationNodeBlendSpace2D::get_child_nodes(List<ChildNode> *r_child_nodes) {
for(int i=0;i<blend_points_used;i++) {
ChildNode cn;
cn.name=itos(i);
cn.node=blend_points[i].node;
r_child_nodes->push_back(cn);
}
}
void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index) {
ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS);
ERR_FAIL_COND(p_node.is_null());
ERR_FAIL_COND(p_node->get_parent().is_valid());
ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used);
if (p_at_index == -1 || p_at_index == blend_points_used) {
@ -32,13 +41,15 @@ void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_
blend_points[p_at_index].node = p_node;
blend_points[p_at_index].position = p_position;
blend_points[p_at_index].node->set_parent(this);
blend_points[p_at_index].node->set_tree(get_tree());
blend_points[p_at_index].node->connect("tree_changed",this,"_tree_changed",varray(),CONNECT_REFERENCE_COUNTED);
blend_points_used++;
if (auto_triangles) {
trianges_dirty = true;
}
emit_signal("tree_changed");
}
void AnimationNodeBlendSpace2D::set_blend_point_position(int p_point, const Vector2 &p_position) {
@ -53,12 +64,13 @@ void AnimationNodeBlendSpace2D::set_blend_point_node(int p_point, const Ref<Anim
ERR_FAIL_COND(p_node.is_null());
if (blend_points[p_point].node.is_valid()) {
blend_points[p_point].node->set_parent(NULL);
blend_points[p_point].node->set_tree(NULL);
blend_points[p_point].node->disconnect("tree_changed",this,"_tree_changed");
}
blend_points[p_point].node = p_node;
blend_points[p_point].node->set_parent(this);
blend_points[p_point].node->set_tree(get_tree());
blend_points[p_point].node->connect("tree_changed",this,"_tree_changed",varray(),CONNECT_REFERENCE_COUNTED);
emit_signal("tree_changed");
}
Vector2 AnimationNodeBlendSpace2D::get_blend_point_position(int p_point) const {
ERR_FAIL_INDEX_V(p_point, blend_points_used, Vector2());
@ -71,8 +83,7 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace2D::get_blend_point_node(int p_poi
void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
ERR_FAIL_INDEX(p_point, blend_points_used);
blend_points[p_point].node->set_parent(NULL);
blend_points[p_point].node->set_tree(NULL);
blend_points[p_point].node->disconnect("tree_changed",this,"_tree_changed");
for (int i = 0; i < triangles.size(); i++) {
bool erase = false;
@ -95,6 +106,8 @@ void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
blend_points[i] = blend_points[i + 1];
}
blend_points_used--;
emit_signal("tree_changed");
}
int AnimationNodeBlendSpace2D::get_blend_point_count() const {
@ -217,13 +230,6 @@ Vector2 AnimationNodeBlendSpace2D::get_snap() const {
return snap;
}
void AnimationNodeBlendSpace2D::set_blend_position(const Vector2 &p_pos) {
blend_pos = p_pos;
}
Vector2 AnimationNodeBlendSpace2D::get_blend_position() const {
return blend_pos;
}
void AnimationNodeBlendSpace2D::set_x_label(const String &p_label) {
x_label = p_label;
}
@ -381,6 +387,8 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
_update_triangles();
Vector2 blend_pos = get_parameter(blend_position);
if (triangles.size() == 0)
return 0;
@ -443,7 +451,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
for (int j = 0; j < 3; j++) {
if (i == triangle_points[j]) {
//blend with the given weight
float t = blend_node(blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false);
float t = blend_node(blend_points[i].name,blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false);
if (first || t < mind) {
mind = t;
first = false;
@ -455,7 +463,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
if (!found) {
//ignore
blend_node(blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false);
blend_node(blend_points[i].name,blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false);
}
}
return mind;
@ -483,10 +491,19 @@ void AnimationNodeBlendSpace2D::set_auto_triangles(bool p_enable) {
}
}
bool AnimationNodeBlendSpace2D::get_auto_triangles() const {
return auto_triangles;
}
Ref<AnimationNode> AnimationNodeBlendSpace2D::get_child_by_name(const StringName &p_name) {
return get_blend_point_node(p_name.operator String().to_int());
}
void AnimationNodeBlendSpace2D::_tree_changed() {
emit_signal("tree_changed");
}
void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1));
@ -511,9 +528,6 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace2D::set_snap);
ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace2D::get_snap);
ClassDB::bind_method(D_METHOD("set_blend_position", "pos"), &AnimationNodeBlendSpace2D::set_blend_position);
ClassDB::bind_method(D_METHOD("get_blend_position"), &AnimationNodeBlendSpace2D::get_blend_position);
ClassDB::bind_method(D_METHOD("set_x_label", "text"), &AnimationNodeBlendSpace2D::set_x_label);
ClassDB::bind_method(D_METHOD("get_x_label"), &AnimationNodeBlendSpace2D::get_x_label);
@ -528,10 +542,12 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_auto_triangles", "enable"), &AnimationNodeBlendSpace2D::set_auto_triangles);
ClassDB::bind_method(D_METHOD("get_auto_triangles"), &AnimationNodeBlendSpace2D::get_auto_triangles);
ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace2D::_tree_changed);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_auto_triangles", "get_auto_triangles");
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "_add_blend_point", "get_blend_point_node", i);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_add_blend_point", "get_blend_point_node", i);
ADD_PROPERTYI(PropertyInfo(Variant::VECTOR2, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i);
}
@ -540,13 +556,15 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_min_space", "get_min_space");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_space", "get_max_space");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "blend_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_blend_position", "get_blend_position");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "x_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_x_label", "get_x_label");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_y_label", "get_y_label");
}
AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() {
for(int i=0;i<MAX_BLEND_POINTS;i++) {
blend_points[i].name=itos(i);
}
auto_triangles = true;
blend_points_used = 0;
max_space = Vector2(1, 1);
@ -555,12 +573,10 @@ AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() {
x_label = "x";
y_label = "y";
trianges_dirty = false;
blend_position = "blend_position";
}
AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() {
for (int i = 0; i < blend_points_used; i++) {
blend_points[i].node->set_parent(this);
blend_points[i].node->set_tree(get_tree());
}
}

View file

@ -11,6 +11,7 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode {
};
struct BlendPoint {
StringName name;
Ref<AnimationRootNode> node;
Vector2 position;
};
@ -24,7 +25,7 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode {
Vector<BlendTriangle> triangles;
Vector2 blend_pos;
StringName blend_position;
Vector2 max_space;
Vector2 min_space;
Vector2 snap;
@ -42,12 +43,19 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode {
void _update_triangles();
void _tree_changed();
protected:
virtual void _validate_property(PropertyInfo &property) const;
static void _bind_methods();
public:
virtual void set_tree(AnimationTree *p_player);
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
void add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index = -1);
void set_blend_point_position(int p_point, const Vector2 &p_position);
@ -72,9 +80,6 @@ public:
void set_snap(const Vector2 &p_snap);
Vector2 get_snap() const;
void set_blend_position(const Vector2 &p_pos);
Vector2 get_blend_position() const;
void set_x_label(const String &p_label);
String get_x_label() const;
@ -89,6 +94,8 @@ public:
void set_auto_triangles(bool p_enable);
bool get_auto_triangles() const;
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
AnimationNodeBlendSpace2D();
~AnimationNodeBlendSpace2D();
};

View file

@ -3,6 +3,7 @@
void AnimationNodeAnimation::set_animation(const StringName &p_name) {
animation = p_name;
_change_notify("animation");
}
StringName AnimationNodeAnimation::get_animation() const {
@ -13,43 +14,36 @@ float AnimationNodeAnimation::get_playback_time() const {
return time;
}
Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = NULL;
void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const {
if (property.name == "animation") {
AnimationTree *gp = get_tree();
if (gp && gp->has_node(gp->get_animation_player())) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
if (ap) {
List<StringName> names;
ap->get_animation_list(&names);
String anims;
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
if (E != names.front()) {
anims += ",";
}
anims += String(E->get());
}
if (anims != String()) {
property.hint = PROPERTY_HINT_ENUM;
property.hint_string = anims;
}
if (property.name == "animation" && get_editable_animation_list) {
Vector<String> names = get_editable_animation_list();
String anims;
for (int i = 0; i < names.size(); i++) {
if (i > 0) {
anims += ",";
}
anims += String(names[i]);
}
if (anims != String()) {
property.hint = PROPERTY_HINT_ENUM;
property.hint_string = anims;
}
}
AnimationRootNode::_validate_property(property);
}
float AnimationNodeAnimation::process(float p_time, bool p_seek) {
AnimationPlayer *ap = get_player();
AnimationPlayer *ap = state->player;
ERR_FAIL_COND_V(!ap, 0);
Ref<Animation> anim = ap->get_animation(animation);
if (!anim.is_valid()) {
if (!ap->has_animation(animation)) {
Ref<AnimationNodeBlendTree> tree = get_parent();
if (tree.is_valid()) {
AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent);
if (tree) {
String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
make_invalid(vformat(RTR("On BlendTree node '%s', animation not found: '%s'"), name, animation));
@ -60,6 +54,8 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) {
return 0;
}
Ref<Animation> anim = ap->get_animation(animation);
if (p_seek) {
time = p_time;
step = 0;
@ -108,6 +104,20 @@ AnimationNodeAnimation::AnimationNodeAnimation() {
////////////////////////////////////////////////////////
void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::BOOL, active));
r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", 0));
r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0));
r_list->push_back(PropertyInfo(Variant::REAL, remaining, PROPERTY_HINT_NONE, "", 0));
}
Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const {
if (p_parameter == active || p_parameter == prev_active) {
return false;
} else {
return 0.0;
}
}
void AnimationNodeOneShot::set_fadein_time(float p_time) {
fade_in = p_time;
@ -162,18 +172,6 @@ AnimationNodeOneShot::MixMode AnimationNodeOneShot::get_mix_mode() const {
return mix;
}
void AnimationNodeOneShot::start() {
active = true;
do_start = true;
}
void AnimationNodeOneShot::stop() {
active = false;
}
bool AnimationNodeOneShot::is_active() const {
return active;
}
String AnimationNodeOneShot::get_caption() const {
return "OneShot";
}
@ -184,8 +182,16 @@ bool AnimationNodeOneShot::has_filter() const {
float AnimationNodeOneShot::process(float p_time, bool p_seek) {
bool active = get_parameter(this->active);
bool prev_active = get_parameter(this->prev_active);
float time = get_parameter(this->time);
float remaining = get_parameter(this->remaining);
if (!active) {
//make it as if this node doesn't exist, pass input 0 by.
if (prev_active) {
set_parameter(this->prev_active, false);
}
return blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
}
@ -193,9 +199,12 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) {
if (p_seek)
time = p_time;
bool do_start = !prev_active;
if (do_start) {
time = 0;
os_seek = true;
set_parameter(this->prev_active, true);
}
float blend;
@ -233,10 +242,15 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) {
if (!p_seek) {
time += p_time;
remaining = os_rem;
if (remaining <= 0)
active = false;
if (remaining <= 0) {
set_parameter(this->active, false);
set_parameter(this->prev_active, false);
}
}
set_parameter(this->time, time);
set_parameter(this->remaining, remaining);
return MAX(main_rem, remaining);
}
void AnimationNodeOneShot::set_use_sync(bool p_sync) {
@ -269,10 +283,6 @@ void AnimationNodeOneShot::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mix_mode", "mode"), &AnimationNodeOneShot::set_mix_mode);
ClassDB::bind_method(D_METHOD("get_mix_mode"), &AnimationNodeOneShot::get_mix_mode);
ClassDB::bind_method(D_METHOD("start"), &AnimationNodeOneShot::start);
ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeOneShot::stop);
ClassDB::bind_method(D_METHOD("is_active"), &AnimationNodeOneShot::is_active);
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeOneShot::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeOneShot::is_using_sync);
@ -297,26 +307,22 @@ AnimationNodeOneShot::AnimationNodeOneShot() {
add_input("in");
add_input("shot");
time = 0;
fade_in = 0.1;
fade_out = 0.1;
autorestart = false;
autorestart_delay = 1;
autorestart_remaining = 0;
mix = MIX_MODE_BLEND;
active = false;
do_start = false;
sync = false;
}
////////////////////////////////////////////////
void AnimationNodeAdd2::set_amount(float p_amount) {
amount = p_amount;
void AnimationNodeAdd2::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::REAL, add_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
}
float AnimationNodeAdd2::get_amount() const {
return amount;
Variant AnimationNodeAdd2::get_parameter_default_value(const StringName &p_parameter) const {
return 0;
}
String AnimationNodeAdd2::get_caption() const {
@ -339,6 +345,7 @@ bool AnimationNodeAdd2::has_filter() const {
float AnimationNodeAdd2::process(float p_time, bool p_seek) {
float amount = get_parameter(add_amount);
float rem0 = blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync);
@ -347,32 +354,27 @@ float AnimationNodeAdd2::process(float p_time, bool p_seek) {
void AnimationNodeAdd2::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeAdd2::set_amount);
ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeAdd2::get_amount);
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd2::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd2::is_using_sync);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeAdd2::AnimationNodeAdd2() {
add_amount = "add_amount";
add_input("in");
add_input("add");
amount = 0;
sync = false;
}
////////////////////////////////////////////////
void AnimationNodeAdd3::set_amount(float p_amount) {
amount = p_amount;
void AnimationNodeAdd3::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::REAL, add_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
}
float AnimationNodeAdd3::get_amount() const {
return amount;
Variant AnimationNodeAdd3::get_parameter_default_value(const StringName &p_parameter) const {
return 0;
}
String AnimationNodeAdd3::get_caption() const {
@ -395,6 +397,7 @@ bool AnimationNodeAdd3::has_filter() const {
float AnimationNodeAdd3::process(float p_time, bool p_seek) {
float amount = get_parameter(add_amount);
blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_PASS, !sync);
float rem0 = blend_input(1, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_PASS, !sync);
@ -404,39 +407,37 @@ float AnimationNodeAdd3::process(float p_time, bool p_seek) {
void AnimationNodeAdd3::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeAdd3::set_amount);
ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeAdd3::get_amount);
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd3::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd3::is_using_sync);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeAdd3::AnimationNodeAdd3() {
add_amount = "add_amount";
add_input("-add");
add_input("in");
add_input("+add");
amount = 0;
sync = false;
}
/////////////////////////////////////////////
void AnimationNodeBlend2::set_amount(float p_amount) {
amount = p_amount;
void AnimationNodeBlend2::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::REAL, blend_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
}
Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const {
return 0; //for blend amount
}
float AnimationNodeBlend2::get_amount() const {
return amount;
}
String AnimationNodeBlend2::get_caption() const {
return "Blend2";
}
float AnimationNodeBlend2::process(float p_time, bool p_seek) {
float amount = get_parameter(blend_amount);
float rem0 = blend_input(0, p_time, p_seek, 1.0 - amount, FILTER_BLEND, !sync);
float rem1 = blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync);
@ -459,31 +460,25 @@ bool AnimationNodeBlend2::has_filter() const {
}
void AnimationNodeBlend2::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeBlend2::set_amount);
ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeBlend2::get_amount);
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend2::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend2::is_using_sync);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeBlend2::AnimationNodeBlend2() {
blend_amount = "blend_amount";
add_input("in");
add_input("blend");
sync = false;
amount = 0;
}
//////////////////////////////////////
void AnimationNodeBlend3::set_amount(float p_amount) {
amount = p_amount;
void AnimationNodeBlend3::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::REAL, blend_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
}
float AnimationNodeBlend3::get_amount() const {
return amount;
Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const {
return 0; //for blend amount
}
String AnimationNodeBlend3::get_caption() const {
@ -502,6 +497,7 @@ bool AnimationNodeBlend3::is_using_sync() const {
float AnimationNodeBlend3::process(float p_time, bool p_seek) {
float amount = get_parameter(blend_amount);
float rem0 = blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_IGNORE, !sync);
float rem1 = blend_input(1, p_time, p_seek, 1.0 - ABS(amount), FILTER_IGNORE, !sync);
float rem2 = blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_IGNORE, !sync);
@ -511,31 +507,26 @@ float AnimationNodeBlend3::process(float p_time, bool p_seek) {
void AnimationNodeBlend3::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeBlend3::set_amount);
ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeBlend3::get_amount);
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend3::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend3::is_using_sync);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeBlend3::AnimationNodeBlend3() {
blend_amount = "blend_amount";
add_input("-blend");
add_input("in");
add_input("+blend");
sync = false;
amount = 0;
}
/////////////////////////////////
void AnimationNodeTimeScale::set_scale(float p_scale) {
scale = p_scale;
void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::REAL, scale, PROPERTY_HINT_RANGE, "0,32,0.01,or_greater"));
}
float AnimationNodeTimeScale::get_scale() const {
return scale;
Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const {
return 1.0; //initial timescale
}
String AnimationNodeTimeScale::get_caption() const {
@ -544,6 +535,7 @@ String AnimationNodeTimeScale::get_caption() const {
float AnimationNodeTimeScale::process(float p_time, bool p_seek) {
float scale = get_parameter(this->scale);
if (p_seek) {
return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false);
} else {
@ -552,25 +544,19 @@ float AnimationNodeTimeScale::process(float p_time, bool p_seek) {
}
void AnimationNodeTimeScale::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_scale", "scale"), &AnimationNodeTimeScale::set_scale);
ClassDB::bind_method(D_METHOD("get_scale"), &AnimationNodeTimeScale::get_scale);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,32,0.01,or_greater"), "set_scale", "get_scale");
}
AnimationNodeTimeScale::AnimationNodeTimeScale() {
scale = "scale";
add_input("in");
scale = 1.0;
}
////////////////////////////////////
void AnimationNodeTimeSeek::set_seek_pos(float p_seek_pos) {
seek_pos = p_seek_pos;
void AnimationNodeTimeSeek::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::REAL, seek_pos, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater"));
}
float AnimationNodeTimeSeek::get_seek_pos() const {
return seek_pos;
Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const {
return 1.0; //initial timescale
}
String AnimationNodeTimeSeek::get_caption() const {
@ -579,11 +565,12 @@ String AnimationNodeTimeSeek::get_caption() const {
float AnimationNodeTimeSeek::process(float p_time, bool p_seek) {
float seek_pos = get_parameter(this->seek_pos);
if (p_seek) {
return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false);
} else if (seek_pos >= 0) {
float ret = blend_input(0, seek_pos, true, 1.0, FILTER_IGNORE, false);
seek_pos = -1;
set_parameter(this->seek_pos, -1.0); //reset
_change_notify("seek_pos");
return ret;
} else {
@ -592,19 +579,41 @@ float AnimationNodeTimeSeek::process(float p_time, bool p_seek) {
}
void AnimationNodeTimeSeek::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_seek_pos", "seek_pos"), &AnimationNodeTimeSeek::set_seek_pos);
ClassDB::bind_method(D_METHOD("get_seek_pos"), &AnimationNodeTimeSeek::get_seek_pos);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "seek_pos", PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater"), "set_seek_pos", "get_seek_pos");
}
AnimationNodeTimeSeek::AnimationNodeTimeSeek() {
add_input("in");
seek_pos = -1;
seek_pos = "seek_position";
}
/////////////////////////////////////////////////
void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) const {
String anims;
for (int i = 0; i < enabled_inputs; i++) {
if (i > 0) {
anims += ",";
}
anims += inputs[i].name;
}
r_list->push_back(PropertyInfo(Variant::INT, current, PROPERTY_HINT_ENUM, anims));
r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", 0));
r_list->push_back(PropertyInfo(Variant::INT, prev, PROPERTY_HINT_NONE, "", 0));
r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0));
r_list->push_back(PropertyInfo(Variant::REAL, prev_xfading, PROPERTY_HINT_NONE, "", 0));
}
Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
if (p_parameter == time || p_parameter == prev_xfading) {
return 0.0;
} else if (p_parameter == prev || p_parameter == prev_current) {
return -1;
} else {
return 0;
}
}
String AnimationNodeTransition::get_caption() const {
return "Transition";
}
@ -650,18 +659,12 @@ String AnimationNodeTransition::get_input_caption(int p_input) const {
return inputs[p_input].name;
}
void AnimationNodeTransition::set_current(int p_current) {
if (current == p_current)
return;
ERR_FAIL_INDEX(p_current, enabled_inputs);
#if 0
Ref<AnimationNodeBlendTree> tree = get_parent();
if (tree.is_valid() && current >= 0) {
prev = current;
prev_xfading = xfade;
prev_time = time;
prev_xfading = xfade;
time = 0;
current = p_current;
switched = true;
@ -669,11 +672,8 @@ void AnimationNodeTransition::set_current(int p_current) {
} else {
current = p_current;
}
}
#endif
int AnimationNodeTransition::get_current() const {
return current;
}
void AnimationNodeTransition::set_cross_fade_time(float p_fade) {
xfade = p_fade;
}
@ -684,9 +684,34 @@ float AnimationNodeTransition::get_cross_fade_time() const {
float AnimationNodeTransition::process(float p_time, bool p_seek) {
int current = get_parameter(this->current);
int prev = get_parameter(this->prev);
int prev_current = get_parameter(this->prev_current);
float time = get_parameter(this->time);
float prev_xfading = get_parameter(this->prev_xfading);
bool switched = current != prev_current;
if (switched) {
set_parameter(this->prev_current, current);
set_parameter(this->prev, prev_current);
prev = prev_current;
prev_xfading = xfade;
time = 0;
switched = true;
}
if (current < 0 || current >= enabled_inputs || prev >= enabled_inputs) {
return 0;
}
float rem = 0;
if (prev < 0) { // process current animation, check for transition
float rem = blend_input(current, p_time, p_seek, 1.0, FILTER_IGNORE, false);
rem = blend_input(current, p_time, p_seek, 1.0, FILTER_IGNORE, false);
if (p_seek)
time = p_time;
@ -695,16 +720,13 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) {
if (inputs[current].auto_advance && rem <= xfade) {
set_current((current + 1) % enabled_inputs);
set_parameter(this->current, (current + 1) % enabled_inputs);
}
return rem;
} else { // cross-fading from prev to current
float blend = xfade ? (prev_xfading / xfade) : 1;
float rem;
if (!p_seek && switched) { //just switched, seek to start of current
rem = blend_input(current, 0, true, 1.0 - blend, FILTER_IGNORE, false);
@ -723,28 +745,19 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) {
time += p_time;
prev_xfading -= p_time;
if (prev_xfading < 0) {
prev = -1;
set_parameter(this->prev, -1);
}
}
return rem;
}
set_parameter(this->time, time);
set_parameter(this->prev_xfading, prev_xfading);
return rem;
}
void AnimationNodeTransition::_validate_property(PropertyInfo &property) const {
if (property.name == "current" && enabled_inputs > 0) {
property.hint = PROPERTY_HINT_ENUM;
String anims;
for (int i = 0; i < enabled_inputs; i++) {
if (i > 0) {
anims += ",";
}
anims += inputs[i].name;
}
property.hint_string = anims;
}
if (property.name.begins_with("input_")) {
String n = property.name.get_slicec('/', 0).get_slicec('_', 1);
if (n != "count") {
@ -769,14 +782,10 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
ClassDB::bind_method(D_METHOD("set_current", "index"), &AnimationNodeTransition::set_current);
ClassDB::bind_method(D_METHOD("get_current"), &AnimationNodeTransition::get_current);
ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time);
ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time);
ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
ADD_PROPERTY(PropertyInfo(Variant::INT, "current", PROPERTY_HINT_RANGE, "0,64,1"), "set_current", "get_current");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01"), "set_cross_fade_time", "get_cross_fade_time");
for (int i = 0; i < MAX_INPUTS; i++) {
@ -786,13 +795,15 @@ void AnimationNodeTransition::_bind_methods() {
}
AnimationNodeTransition::AnimationNodeTransition() {
prev_xfading = "prev_xfading";
prev = "prev";
time = "time";
current = "current";
prev_current = "prev_current";
;
enabled_inputs = 0;
xfade = 0;
current = -1;
prev = -1;
prev_time = 0;
prev_xfading = 0;
switched = false;
for (int i = 0; i < MAX_INPUTS; i++) {
inputs[i].auto_advance = false;
inputs[i].name = itos(i + 1);
@ -814,69 +825,102 @@ AnimationNodeOutput::AnimationNodeOutput() {
}
///////////////////////////////////////////////////////
void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node) {
void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position) {
ERR_FAIL_COND(nodes.has(p_name));
ERR_FAIL_COND(p_node.is_null());
ERR_FAIL_COND(p_node->get_parent().is_valid());
ERR_FAIL_COND(p_node->get_tree() != NULL);
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output);
ERR_FAIL_COND(String(p_name).find("/") != -1);
nodes[p_name] = p_node;
p_node->set_parent(this);
p_node->set_tree(get_tree());
Node n;
n.node = p_node;
n.position = p_position;
n.connections.resize(n.node->get_input_count());
nodes[p_name] = n;
emit_changed();
emit_signal("tree_changed");
p_node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
p_node->connect("changed", this, "_node_changed", varray(p_name), CONNECT_REFERENCE_COUNTED);
}
Ref<AnimationNode> AnimationNodeBlendTree::get_node(const StringName &p_name) const {
ERR_FAIL_COND_V(!nodes.has(p_name), Ref<AnimationNode>());
return nodes[p_name];
return nodes[p_name].node;
}
StringName AnimationNodeBlendTree::get_node_name(const Ref<AnimationNode> &p_node) const {
for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
if (E->get() == p_node) {
for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
if (E->get().node == p_node) {
return E->key();
}
}
ERR_FAIL_V(StringName());
}
void AnimationNodeBlendTree::set_node_position(const StringName &p_node, const Vector2 &p_position) {
ERR_FAIL_COND(!nodes.has(p_node));
nodes[p_node].position = p_position;
}
Vector2 AnimationNodeBlendTree::get_node_position(const StringName &p_node) const {
ERR_FAIL_COND_V(!nodes.has(p_node), Vector2());
return nodes[p_node].position;
}
void AnimationNodeBlendTree::get_child_nodes(List<ChildNode> *r_child_nodes) {
Vector<StringName> ns;
for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
ns.push_back(E->key());
}
ns.sort_custom<StringName::AlphCompare>();
for (int i = 0; i < ns.size(); i++) {
ChildNode cn;
cn.name = ns[i];
cn.node = nodes[cn.name].node;
r_child_nodes->push_back(cn);
}
}
bool AnimationNodeBlendTree::has_node(const StringName &p_name) const {
return nodes.has(p_name);
}
Vector<StringName> AnimationNodeBlendTree::get_node_connection_array(const StringName &p_name) const {
ERR_FAIL_COND_V(!nodes.has(p_name), Vector<StringName>());
return nodes[p_name].connections;
}
void AnimationNodeBlendTree::remove_node(const StringName &p_name) {
ERR_FAIL_COND(!nodes.has(p_name));
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); //can't delete output
{
//erase node connections
Ref<AnimationNode> node = nodes[p_name];
for (int i = 0; i < node->get_input_count(); i++) {
node->set_input_connection(i, StringName());
}
node->set_parent(NULL);
node->set_tree(NULL);
Ref<AnimationNode> node = nodes[p_name].node;
node->disconnect("tree_changed", this, "_tree_changed");
node->disconnect("changed", this, "_node_changed");
}
nodes.erase(p_name);
//erase connections to name
for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
Ref<AnimationNode> node = E->get();
for (int i = 0; i < node->get_input_count(); i++) {
if (node->get_input_connection(i) == p_name) {
node->set_input_connection(i, StringName());
for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
for (int i = 0; i < E->get().connections.size(); i++) {
if (E->get().connections[i] == p_name) {
E->get().connections.write[i] = StringName();
}
}
}
emit_changed();
emit_signal("tree_changed");
}
void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringName &p_new_name) {
@ -886,18 +930,24 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output);
ERR_FAIL_COND(p_new_name == SceneStringNames::get_singleton()->output);
nodes[p_name].node->disconnect("changed", this, "_node_changed");
nodes[p_new_name] = nodes[p_name];
nodes.erase(p_name);
//rename connections
for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
Ref<AnimationNode> node = E->get();
for (int i = 0; i < node->get_input_count(); i++) {
if (node->get_input_connection(i) == p_name) {
node->set_input_connection(i, p_new_name);
for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
for (int i = 0; i < E->get().connections.size(); i++) {
if (E->get().connections[i] == p_name) {
E->get().connections.write[i] = p_new_name;
}
}
}
//connection must be done with new name
nodes[p_new_name].node->connect("changed", this, "_node_changed", varray(p_new_name), CONNECT_REFERENCE_COUNTED);
emit_signal("tree_changed");
}
void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) {
@ -907,18 +957,18 @@ void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_
ERR_FAIL_COND(p_output_node == SceneStringNames::get_singleton()->output);
ERR_FAIL_COND(p_input_node == p_output_node);
Ref<AnimationNode> input = nodes[p_input_node];
ERR_FAIL_INDEX(p_input_index, input->get_input_count());
Ref<AnimationNode> input = nodes[p_input_node].node;
ERR_FAIL_INDEX(p_input_index, nodes[p_input_node].connections.size());
for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
Ref<AnimationNode> node = E->get();
for (int i = 0; i < node->get_input_count(); i++) {
StringName output = node->get_input_connection(i);
for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
for (int i = 0; i < E->get().connections.size(); i++) {
StringName output = E->get().connections[i];
ERR_FAIL_COND(output == p_output_node);
}
}
input->set_input_connection(p_input_index, p_output_node);
nodes[p_input_node].connections.write[p_input_index] = p_output_node;
emit_changed();
}
@ -926,20 +976,21 @@ void AnimationNodeBlendTree::disconnect_node(const StringName &p_node, int p_inp
ERR_FAIL_COND(!nodes.has(p_node));
Ref<AnimationNode> input = nodes[p_node];
ERR_FAIL_INDEX(p_input_index, input->get_input_count());
Ref<AnimationNode> input = nodes[p_node].node;
ERR_FAIL_INDEX(p_input_index, nodes[p_node].connections.size());
input->set_input_connection(p_input_index, StringName());
nodes[p_node].connections.write[p_input_index] = StringName();
}
float AnimationNodeBlendTree::get_connection_activity(const StringName &p_input_node, int p_input_index) const {
ERR_FAIL_COND_V(!nodes.has(p_input_node), 0);
Ref<AnimationNode> input = nodes[p_input_node];
ERR_FAIL_INDEX_V(p_input_index, input->get_input_count(), 0);
Ref<AnimationNode> input = nodes[p_input_node].node;
ERR_FAIL_INDEX_V(p_input_index, nodes[p_input_node].connections.size(), 0);
return input->get_input_activity(p_input_index);
//return input->get_input_activity(p_input_index);
return 0;
}
AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) const {
@ -956,20 +1007,19 @@ AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node
return CONNECTION_ERROR_SAME_NODE;
}
Ref<AnimationNode> input = nodes[p_input_node];
Ref<AnimationNode> input = nodes[p_input_node].node;
if (p_input_index < 0 || p_input_index >= input->get_input_count()) {
if (p_input_index < 0 || p_input_index >= nodes[p_input_node].connections.size()) {
return CONNECTION_ERROR_NO_INPUT_INDEX;
}
if (input->get_input_connection(p_input_index) != StringName()) {
if (nodes[p_input_node].connections[p_input_index] != StringName()) {
return CONNECTION_ERROR_CONNECTION_EXISTS;
}
for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
Ref<AnimationNode> node = E->get();
for (int i = 0; i < node->get_input_count(); i++) {
StringName output = node->get_input_connection(i);
for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
for (int i = 0; i < E->get().connections.size(); i++) {
StringName output = E->get().connections[i];
if (output == p_output_node) {
return CONNECTION_ERROR_CONNECTION_EXISTS;
}
@ -980,10 +1030,9 @@ AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node
void AnimationNodeBlendTree::get_node_connections(List<NodeConnection> *r_connections) const {
for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
Ref<AnimationNode> node = E->get();
for (int i = 0; i < node->get_input_count(); i++) {
StringName output = node->get_input_connection(i);
for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
for (int i = 0; i < E->get().connections.size(); i++) {
StringName output = E->get().connections[i];
if (output != StringName()) {
NodeConnection nc;
nc.input_node = E->key();
@ -1001,13 +1050,13 @@ String AnimationNodeBlendTree::get_caption() const {
float AnimationNodeBlendTree::process(float p_time, bool p_seek) {
Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output];
return blend_node(output, p_time, p_seek, 1.0);
Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, 1.0);
}
void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {
for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
r_list->push_back(E->key());
}
}
@ -1022,14 +1071,8 @@ Vector2 AnimationNodeBlendTree::get_graph_offset() const {
return graph_offset;
}
void AnimationNodeBlendTree::set_tree(AnimationTree *p_player) {
AnimationNode::set_tree(p_player);
for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
Ref<AnimationNode> node = E->get();
node->set_tree(p_player);
}
Ref<AnimationNode> AnimationNodeBlendTree::get_child_by_name(const StringName &p_name) {
return get_node(p_name);
}
bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) {
@ -1051,7 +1094,7 @@ bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_val
if (what == "position") {
if (nodes.has(node_name)) {
nodes[node_name]->set_position(p_value);
nodes[node_name].position = p_value;
}
return true;
}
@ -1078,7 +1121,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons
if (what == "node") {
if (nodes.has(node_name)) {
r_ret = nodes[node_name];
r_ret = nodes[node_name].node;
return true;
}
}
@ -1086,7 +1129,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons
if (what == "position") {
if (nodes.has(node_name)) {
r_ret = nodes[node_name]->get_position();
r_ret = nodes[node_name].position;
return true;
}
}
@ -1113,7 +1156,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons
void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const {
List<StringName> names;
for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
names.push_back(E->key());
}
names.sort_custom<StringName::AlphCompare>();
@ -1121,7 +1164,7 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
String name = E->get();
if (name != "output") {
p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR));
}
p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
@ -1129,9 +1172,19 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons
p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
void AnimationNodeBlendTree::_tree_changed() {
emit_signal("tree_changed");
}
void AnimationNodeBlendTree::_node_changed(const StringName &p_node) {
ERR_FAIL_COND(!nodes.has(p_node));
nodes[p_node].connections.resize(nodes[p_node].node->get_input_count());
}
void AnimationNodeBlendTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_node", "name", "node"), &AnimationNodeBlendTree::add_node);
ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeBlendTree::add_node, DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeBlendTree::get_node);
ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeBlendTree::remove_node);
ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeBlendTree::rename_node);
@ -1139,9 +1192,15 @@ void AnimationNodeBlendTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("connect_node", "input_node", "input_index", "output_node"), &AnimationNodeBlendTree::connect_node);
ClassDB::bind_method(D_METHOD("disconnect_node", "input_node", "input_index"), &AnimationNodeBlendTree::disconnect_node);
ClassDB::bind_method(D_METHOD("set_node_position", "name", "position"), &AnimationNodeBlendTree::set_node_position);
ClassDB::bind_method(D_METHOD("get_node_position", "name"), &AnimationNodeBlendTree::get_node_position);
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &AnimationNodeBlendTree::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeBlendTree::get_graph_offset);
ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendTree::_tree_changed);
ClassDB::bind_method(D_METHOD("_node_changed", "node"), &AnimationNodeBlendTree::_node_changed);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_graph_offset", "get_graph_offset");
BIND_CONSTANT(CONNECTION_OK);
@ -1156,15 +1215,12 @@ AnimationNodeBlendTree::AnimationNodeBlendTree() {
Ref<AnimationNodeOutput> output;
output.instance();
output->set_position(Vector2(300, 150));
output->set_parent(this);
nodes["output"] = output;
Node n;
n.node = output;
n.position = Vector2(300, 150);
n.connections.resize(1);
nodes["output"] = n;
}
AnimationNodeBlendTree::~AnimationNodeBlendTree() {
for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
E->get()->set_parent(NULL);
E->get()->set_tree(NULL);
}
}

View file

@ -20,6 +20,8 @@ protected:
static void _bind_methods();
public:
static Vector<String> (*get_editable_animation_list)();
virtual String get_caption() const;
virtual float process(float p_time, bool p_seek);
@ -41,8 +43,6 @@ public:
};
private:
bool active;
bool do_start;
float fade_in;
float fade_out;
@ -51,15 +51,25 @@ private:
float autorestart_random_delay;
MixMode mix;
float time;
float remaining;
float autorestart_remaining;
bool sync;
/* bool active;
bool do_start;
float time;
float remaining;*/
StringName active;
StringName prev_active;
StringName time;
StringName remaining;
protected:
static void _bind_methods();
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
virtual String get_caption() const;
void set_fadein_time(float p_time);
@ -79,10 +89,6 @@ public:
void set_mix_mode(MixMode p_mix);
MixMode get_mix_mode() const;
void start();
void stop();
bool is_active() const;
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@ -97,17 +103,17 @@ VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode)
class AnimationNodeAdd2 : public AnimationNode {
GDCLASS(AnimationNodeAdd2, AnimationNode);
float amount;
StringName add_amount;
bool sync;
protected:
static void _bind_methods();
public:
virtual String get_caption() const;
void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
void set_amount(float p_amount);
float get_amount() const;
virtual String get_caption() const;
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@ -121,17 +127,17 @@ public:
class AnimationNodeAdd3 : public AnimationNode {
GDCLASS(AnimationNodeAdd3, AnimationNode);
float amount;
StringName add_amount;
bool sync;
protected:
static void _bind_methods();
public:
virtual String get_caption() const;
void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
void set_amount(float p_amount);
float get_amount() const;
virtual String get_caption() const;
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@ -145,19 +151,19 @@ public:
class AnimationNodeBlend2 : public AnimationNode {
GDCLASS(AnimationNodeBlend2, AnimationNode);
float amount;
StringName blend_amount;
bool sync;
protected:
static void _bind_methods();
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
virtual String get_caption() const;
virtual float process(float p_time, bool p_seek);
void set_amount(float p_amount);
float get_amount() const;
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@ -168,17 +174,17 @@ public:
class AnimationNodeBlend3 : public AnimationNode {
GDCLASS(AnimationNodeBlend3, AnimationNode);
float amount;
StringName blend_amount;
bool sync;
protected:
static void _bind_methods();
public:
virtual String get_caption() const;
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
void set_amount(float p_amount);
float get_amount() const;
virtual String get_caption() const;
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@ -190,16 +196,16 @@ public:
class AnimationNodeTimeScale : public AnimationNode {
GDCLASS(AnimationNodeTimeScale, AnimationNode);
float scale;
StringName scale;
protected:
static void _bind_methods();
public:
virtual String get_caption() const;
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
void set_scale(float p_scale);
float get_scale() const;
virtual String get_caption() const;
float process(float p_time, bool p_seek);
@ -209,16 +215,16 @@ public:
class AnimationNodeTimeSeek : public AnimationNode {
GDCLASS(AnimationNodeTimeSeek, AnimationNode);
float seek_pos;
StringName seek_pos;
protected:
static void _bind_methods();
public:
virtual String get_caption() const;
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
void set_seek_pos(float p_sec);
float get_seek_pos() const;
virtual String get_caption() const;
float process(float p_time, bool p_seek);
@ -241,13 +247,18 @@ class AnimationNodeTransition : public AnimationNode {
InputData inputs[MAX_INPUTS];
int enabled_inputs;
float prev_time;
/*
float prev_xfading;
int prev;
bool switched;
float time;
int current;
int prev_current; */
StringName prev_xfading;
StringName prev;
StringName time;
StringName current;
StringName prev_current;
float xfade;
@ -258,6 +269,9 @@ protected:
void _validate_property(PropertyInfo &property) const;
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
virtual String get_caption() const;
void set_enabled_inputs(int p_inputs);
@ -269,9 +283,6 @@ public:
void set_input_caption(int p_input, const String &p_name);
String get_input_caption(int p_input) const;
void set_current(int p_current);
int get_current() const;
void set_cross_fade_time(float p_fade);
float get_cross_fade_time() const;
@ -293,10 +304,19 @@ public:
class AnimationNodeBlendTree : public AnimationRootNode {
GDCLASS(AnimationNodeBlendTree, AnimationRootNode)
Map<StringName, Ref<AnimationNode> > nodes;
struct Node {
Ref<AnimationNode> node;
Vector2 position;
Vector<StringName> connections;
};
Map<StringName, Node> nodes;
Vector2 graph_offset;
void _tree_changed();
void _node_changed(const StringName &p_node);
protected:
static void _bind_methods();
bool _set(const StringName &p_name, const Variant &p_value);
@ -314,12 +334,18 @@ public:
//no need to check for cycles due to tree topology
};
void add_node(const StringName &p_name, Ref<AnimationNode> p_node);
void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2());
Ref<AnimationNode> get_node(const StringName &p_name) const;
void remove_node(const StringName &p_name);
void rename_node(const StringName &p_name, const StringName &p_new_name);
bool has_node(const StringName &p_name) const;
StringName get_node_name(const Ref<AnimationNode> &p_node) const;
Vector<StringName> get_node_connection_array(const StringName &p_name) const;
void set_node_position(const StringName &p_node, const Vector2 &p_position);
Vector2 get_node_position(const StringName &p_node) const;
virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
void connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node);
void disconnect_node(const StringName &p_node, int p_input_index);
@ -342,7 +368,8 @@ public:
void set_graph_offset(const Vector2 &p_graph_offset);
Vector2 get_graph_offset() const;
virtual void set_tree(AnimationTree *p_player);
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
AnimationNodeBlendTree();
~AnimationNodeBlendTree();
};

File diff suppressed because it is too large Load diff

View file

@ -15,6 +15,8 @@ public:
private:
SwitchMode switch_mode;
bool auto_advance;
StringName advance_condition;
StringName advance_condition_name;
float xfade;
bool disabled;
int priority;
@ -29,6 +31,11 @@ public:
void set_auto_advance(bool p_enable);
bool has_auto_advance() const;
void set_advance_condition(const StringName &p_condition);
StringName get_advance_condition() const;
StringName get_advance_condition_name() const;
void set_xfade_time(float p_xfade);
float get_xfade_time() const;
@ -43,39 +50,24 @@ public:
VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode)
class AnimationNodeStateMachine : public AnimationRootNode {
class AnimationNodeStateMachine;
GDCLASS(AnimationNodeStateMachine, AnimationRootNode);
class AnimationNodeStateMachinePlayback : public Resource {
GDCLASS(AnimationNodeStateMachinePlayback, Resource);
private:
Map<StringName, Ref<AnimationRootNode> > states;
struct Transition {
StringName from;
StringName to;
Ref<AnimationNodeStateMachineTransition> transition;
};
friend class AnimationNodeStateMachine;
struct AStarCost {
float distance;
StringName prev;
};
Vector<Transition> transitions;
float len_total;
float len_current;
float pos_current;
int loops_current;
bool play_start;
StringName start_node;
StringName end_node;
Vector2 graph_offset;
StringName current;
StringName fading_from;
@ -85,6 +77,63 @@ private:
Vector<StringName> path;
bool playing;
StringName start_request;
bool start_request_travel;
bool stop_request;
bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel);
float process(AnimationNodeStateMachine *p_state_machine, float p_time, bool p_seek);
protected:
static void _bind_methods();
public:
void travel(const StringName &p_state);
void start(const StringName &p_state);
void stop();
bool is_playing() const;
StringName get_current_node() const;
StringName get_blend_from_node() const;
Vector<StringName> get_travel_path() const;
float get_current_play_pos() const;
float get_current_length() const;
AnimationNodeStateMachinePlayback();
};
class AnimationNodeStateMachine : public AnimationRootNode {
GDCLASS(AnimationNodeStateMachine, AnimationRootNode);
private:
friend class AnimationNodeStateMachinePlayback;
struct State {
Ref<AnimationRootNode> node;
Vector2 position;
};
Map<StringName, State> states;
struct Transition {
StringName from;
StringName to;
Ref<AnimationNodeStateMachineTransition> transition;
};
Vector<Transition> transitions;
StringName playback;
StringName start_node;
StringName end_node;
Vector2 graph_offset;
void _tree_changed();
protected:
void _notification(int p_what);
static void _bind_methods();
@ -94,7 +143,10 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const;
public:
void add_node(const StringName &p_name, Ref<AnimationNode> p_node);
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2());
Ref<AnimationNode> get_node(const StringName &p_name) const;
void remove_node(const StringName &p_name);
void rename_node(const StringName &p_name, const StringName &p_new_name);
@ -102,6 +154,11 @@ public:
StringName get_node_name(const Ref<AnimationNode> &p_node) const;
void get_node_list(List<StringName> *r_nodes) const;
void set_node_position(const StringName &p_name, const Vector2 &p_position);
Vector2 get_node_position(const StringName &p_name) const;
virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
bool has_transition(const StringName &p_from, const StringName &p_to) const;
int find_transition(const StringName &p_from, const StringName &p_to) const;
void add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition);
@ -124,17 +181,7 @@ public:
virtual float process(float p_time, bool p_seek);
virtual String get_caption() const;
bool travel(const StringName &p_state);
void start(const StringName &p_state);
void stop();
bool is_playing() const;
StringName get_current_node() const;
StringName get_blend_from_node() const;
Vector<StringName> get_travel_path() const;
float get_current_play_pos() const;
float get_current_length() const;
virtual void set_tree(AnimationTree *p_player);
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
AnimationNodeStateMachine();
};

View file

@ -5,6 +5,38 @@
#include "scene/scene_string_names.h"
#include "servers/audio/audio_stream.h"
void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
}
Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const {
return Variant();
}
void AnimationNode::set_parameter(const StringName& p_name, const Variant& p_value) {
ERR_FAIL_COND(!state);
ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path));
ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name));
StringName path = state->tree->property_parent_map[base_path][p_name];
state->tree->property_map[path]=p_value;
}
Variant AnimationNode::get_parameter(const StringName& p_name) const {
ERR_FAIL_COND_V(!state,Variant());
ERR_FAIL_COND_V(!state->tree->property_parent_map.has(base_path),Variant());
ERR_FAIL_COND_V(!state->tree->property_parent_map[base_path].has(p_name),Variant());
StringName path = state->tree->property_parent_map[base_path][p_name];
return state->tree->property_map[path];
}
void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
}
void AnimationNode::blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend) {
ERR_FAIL_COND(!state);
@ -14,8 +46,8 @@ void AnimationNode::blend_animation(const StringName &p_animation, float p_time,
if (animation.is_null()) {
Ref<AnimationNodeBlendTree> btree = get_parent();
if (btree.is_valid()) {
AnimationNodeBlendTree* btree = Object::cast_to<AnimationNodeBlendTree>(parent);
if (btree) {
String name = btree->get_node_name(Ref<AnimationNodeAnimation>(this));
make_invalid(vformat(RTR("In node '%s', invalid animation: '%s'."), name, p_animation));
} else {
@ -37,10 +69,20 @@ void AnimationNode::blend_animation(const StringName &p_animation, float p_time,
state->animation_states.push_back(anim_state);
}
float AnimationNode::_pre_process(State *p_state, float p_time, bool p_seek) {
float AnimationNode::_pre_process(const StringName& p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName>& p_connections) {
base_path = p_base_path;
parent = p_parent;
connections=p_connections;
state = p_state;
float t = process(p_time, p_seek);
state = NULL;
parent = NULL;
base_path = StringName();
connections.clear();
return t;
}
@ -56,39 +98,31 @@ void AnimationNode::make_invalid(const String &p_reason) {
float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
ERR_FAIL_COND_V(!state, 0);
ERR_FAIL_COND_V(!get_tree(), 0); //should not happen, but used to catch bugs
Ref<AnimationNodeBlendTree> tree = get_parent();
AnimationNodeBlendTree* blend_tree = Object::cast_to<AnimationNodeBlendTree>(parent);
ERR_FAIL_COND_V(!blend_tree,0);
if (!tree.is_valid() && get_tree()->get_tree_root().ptr() != this) {
make_invalid(RTR("Can't blend input because node is not in a tree"));
return 0;
}
StringName node_name = connections[p_input];
ERR_FAIL_COND_V(!tree.is_valid(), 0); //should not happen
StringName anim_name = inputs[p_input].connected_to;
Ref<AnimationNode> node = tree->get_node(anim_name);
if (node.is_null()) {
String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
if (!blend_tree->has_node(node_name)) {
String name = blend_tree->get_node_name(Ref<AnimationNode>(this));
make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), name));
return 0;
}
inputs.write[p_input].last_pass = state->last_pass;
Ref<AnimationNode> node = blend_tree->get_node(node_name);
return _blend_node(node, p_time, p_seek, p_blend, p_filter, p_optimize, &inputs.write[p_input].activity);
//inputs.write[p_input].last_pass = state->last_pass;
float activity;
return _blend_node(node_name,blend_tree->get_node_connection_array(node_name),NULL,node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity);
}
float AnimationNode::blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
float AnimationNode::blend_node(const StringName& p_sub_path,Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
return _blend_node(p_node, p_time, p_seek, p_blend, p_filter, p_optimize);
return _blend_node(p_sub_path,Vector<StringName>(),this,p_node, p_time, p_seek, p_blend, p_filter, p_optimize);
}
float AnimationNode::_blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize, float *r_max) {
float AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName>& p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize, float *r_max) {
ERR_FAIL_COND_V(!p_node.is_valid(), 0);
ERR_FAIL_COND_V(!state, 0);
@ -189,7 +223,19 @@ float AnimationNode::_blend_node(Ref<AnimationNode> p_node, float p_time, bool p
if (!p_seek && p_optimize && !any_valid) //pointless to go on, all are zero
return 0;
return p_node->_pre_process(state, p_time, p_seek);
String new_path;
AnimationNode *new_parent;
//this is the slowest part of processing, but as strings process in powers of 2, and the paths always exist, it will not result in that many allocations
if (p_new_parent) {
new_parent = p_new_parent;
new_path = String(base_path)+String(p_subpath)+"/";
} else {
ERR_FAIL_COND_V(!parent,0);
new_parent = parent;
new_path = String(parent->base_path) + String(p_subpath)+"/";
}
return p_node->_pre_process(new_path,new_parent,state, p_time, p_seek, p_connections);
}
int AnimationNode::get_input_count() const {
@ -201,28 +247,6 @@ String AnimationNode::get_input_name(int p_input) {
return inputs[p_input].name;
}
float AnimationNode::get_input_activity(int p_input) const {
ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
if (!get_tree())
return 0;
if (get_tree()->get_last_process_pass() != inputs[p_input].last_pass) {
return 0;
}
return inputs[p_input].activity;
}
StringName AnimationNode::get_input_connection(int p_input) {
ERR_FAIL_INDEX_V(p_input, inputs.size(), StringName());
return inputs[p_input].connected_to;
}
void AnimationNode::set_input_connection(int p_input, const StringName &p_connection) {
ERR_FAIL_INDEX(p_input, inputs.size());
inputs.write[p_input].connected_to = p_connection;
}
String AnimationNode::get_caption() const {
@ -239,8 +263,6 @@ void AnimationNode::add_input(const String &p_name) {
Input input;
ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1);
input.name = p_name;
input.activity = 0;
input.last_pass = 0;
inputs.push_back(input);
emit_changed();
}
@ -258,35 +280,6 @@ void AnimationNode::remove_input(int p_index) {
emit_changed();
}
void AnimationNode::_set_parent(Object *p_parent) {
set_parent(Object::cast_to<AnimationNode>(p_parent));
}
void AnimationNode::set_parent(AnimationNode *p_parent) {
parent = p_parent; //do not use ref because parent contains children
if (get_script_instance()) {
get_script_instance()->call("_parent_set", p_parent);
}
}
Ref<AnimationNode> AnimationNode::get_parent() const {
if (parent) {
return Ref<AnimationNode>(parent);
}
return Ref<AnimationNode>();
}
AnimationTree *AnimationNode::get_tree() const {
return player;
}
AnimationPlayer *AnimationNode::get_player() const {
ERR_FAIL_COND_V(!state, NULL);
return state->player;
}
float AnimationNode::process(float p_time, bool p_seek) {
if (get_script_instance()) {
@ -320,21 +313,7 @@ bool AnimationNode::has_filter() const {
return false;
}
void AnimationNode::set_position(const Vector2 &p_position) {
position = p_position;
}
Vector2 AnimationNode::get_position() const {
return position;
}
void AnimationNode::set_tree(AnimationTree *p_player) {
if (player != NULL && p_player == NULL) {
emit_signal("removed_from_graph");
}
player = p_player;
}
Array AnimationNode::_get_filters() const {
@ -361,12 +340,14 @@ void AnimationNode::_validate_property(PropertyInfo &property) const {
}
}
Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) {
return Ref<AnimationNode>();
}
void AnimationNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count);
ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name);
ClassDB::bind_method(D_METHOD("get_input_connection", "input"), &AnimationNode::get_input_connection);
ClassDB::bind_method(D_METHOD("get_input_activity", "input"), &AnimationNode::get_input_activity);
ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input);
ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input);
@ -377,19 +358,16 @@ void AnimationNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_filter_enabled", "enable"), &AnimationNode::set_filter_enabled);
ClassDB::bind_method(D_METHOD("is_filter_enabled"), &AnimationNode::is_filter_enabled);
ClassDB::bind_method(D_METHOD("set_position", "position"), &AnimationNode::set_position);
ClassDB::bind_method(D_METHOD("get_position"), &AnimationNode::get_position);
ClassDB::bind_method(D_METHOD("_set_filters", "filters"), &AnimationNode::_set_filters);
ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);
ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "blend"), &AnimationNode::blend_animation);
ClassDB::bind_method(D_METHOD("blend_node", "node", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
ClassDB::bind_method(D_METHOD("blend_node", "name","node", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
ClassDB::bind_method(D_METHOD("set_parent", "parent"), &AnimationNode::_set_parent);
ClassDB::bind_method(D_METHOD("get_parent"), &AnimationNode::get_parent);
ClassDB::bind_method(D_METHOD("get_tree"), &AnimationNode::get_tree);
ClassDB::bind_method(D_METHOD("set_parameter","name","value"), &AnimationNode::set_parameter);
ClassDB::bind_method(D_METHOD("get_parameter","name"), &AnimationNode::get_parameter);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_filter_enabled", "is_filter_enabled");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters");
@ -397,9 +375,11 @@ void AnimationNode::_bind_methods() {
BIND_VMETHOD(MethodInfo("process", PropertyInfo(Variant::REAL, "time"), PropertyInfo(Variant::BOOL, "seek")));
BIND_VMETHOD(MethodInfo(Variant::STRING, "get_caption"));
BIND_VMETHOD(MethodInfo(Variant::STRING, "has_filter"));
BIND_VMETHOD(MethodInfo("_parent_set", PropertyInfo(Variant::OBJECT, "parent")));
ADD_SIGNAL(MethodInfo("removed_from_graph"));
ADD_SIGNAL(MethodInfo("tree_changed"));
BIND_ENUM_CONSTANT(FILTER_IGNORE);
BIND_ENUM_CONSTANT(FILTER_PASS);
BIND_ENUM_CONSTANT(FILTER_STOP);
@ -410,8 +390,6 @@ AnimationNode::AnimationNode() {
state = NULL;
parent = NULL;
player = NULL;
set_local_to_scene(true);
filter_enabled = false;
}
@ -420,18 +398,17 @@ AnimationNode::AnimationNode() {
void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) {
if (root.is_valid()) {
root->set_tree(NULL);
}
if (p_root.is_valid()) {
ERR_EXPLAIN("root node already set to another player");
ERR_FAIL_COND(p_root->player);
root->disconnect("tree_changed",this,"_tree_changed");
}
root = p_root;
if (root.is_valid()) {
root->set_tree(this);
root->connect("tree_changed",this,"_tree_changed");
}
properties_dirty=true;
update_configuration_warning();
}
@ -699,7 +676,10 @@ void AnimationTree::_clear_caches() {
void AnimationTree::_process_graph(float p_delta) {
_update_properties(); //if properties need updating, update them
//check all tracks, see if they need modification
root_motion_transform = Transform();
if (!root.is_valid()) {
@ -741,6 +721,7 @@ void AnimationTree::_process_graph(float p_delta) {
state.valid = true;
state.player = player;
state.last_pass = process_pass;
state.tree = this;
// root source blends
@ -757,11 +738,11 @@ void AnimationTree::_process_graph(float p_delta) {
if (started) {
//if started, seek
root->_pre_process(&state, 0, true);
root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path,NULL,&state, 0, true,Vector<StringName>());
started = false;
}
root->_pre_process(&state, p_delta, false);
root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path,NULL,&state, p_delta, false,Vector<StringName>());
}
if (!state.valid) {
@ -1297,6 +1278,117 @@ Transform AnimationTree::get_root_motion_transform() const {
return root_motion_transform;
}
void AnimationTree::_tree_changed() {
if (properties_dirty) {
return;
}
call_deferred("_update_properties");
properties_dirty=true;
}
void AnimationTree::_update_properties_for_node(const String& p_base_path,Ref<AnimationNode> node) {
if (!property_parent_map.has(p_base_path)) {
property_parent_map[p_base_path]=HashMap<StringName, StringName>();
}
List<PropertyInfo> plist;
node->get_parameter_list(&plist);
for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
PropertyInfo pinfo = E->get();
StringName key = pinfo.name;
if (!property_map.has(p_base_path +key)) {
property_map[p_base_path + key] = node->get_parameter_default_value(key);
}
property_parent_map[p_base_path][key]=p_base_path+key;
pinfo.name = p_base_path + key;
properties.push_back(pinfo);
}
List<AnimationNode::ChildNode> children;
node->get_child_nodes(&children);
for (List<AnimationNode::ChildNode>::Element *E=children.front();E;E=E->next()) {
_update_properties_for_node(p_base_path+E->get().name+"/",E->get().node);
}
}
void AnimationTree::_update_properties() {
if (!properties_dirty) {
return;
}
properties.clear();
property_parent_map.clear();
if (root.is_valid()) {
_update_properties_for_node(SceneStringNames::get_singleton()->parameters_base_path,root);
}
properties_dirty = false;
_change_notify();
}
bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {
if (properties_dirty) {
_update_properties();
}
if (property_map.has(p_name)) {
property_map[p_name]=p_value;
#ifdef TOOLS_ENABLED
_change_notify(p_name.operator String().utf8().get_data());
#endif
return true;
}
return false;
}
bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const {
if (properties_dirty) {
const_cast<AnimationTree*>(this)->_update_properties();
}
if (property_map.has(p_name)) {
r_ret=property_map[p_name];
return true;
}
return false;
}
void AnimationTree::_get_property_list(List<PropertyInfo> *p_list) const {
if (properties_dirty) {
const_cast<AnimationTree*>(this)->_update_properties();
}
for (const List<PropertyInfo>::Element *E=properties.front();E;E=E->next()) {
p_list->push_back(E->get());
}
}
void AnimationTree::rename_parameter(const String& p_base,const String& p_new_base) {
//rename values first
for (const List<PropertyInfo>::Element *E=properties.front();E;E=E->next()) {
if (E->get().name.begins_with(p_base)) {
String new_name = E->get().name.replace_first(p_base,p_new_base);
property_map[new_name]=property_map[E->get().name];
}
}
//update tree second
properties_dirty=true;
_update_properties();
}
void AnimationTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationTree::set_active);
ClassDB::bind_method(D_METHOD("is_active"), &AnimationTree::is_active);
@ -1315,11 +1407,17 @@ void AnimationTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform);
ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationTree::_tree_changed);
ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties);
ClassDB::bind_method(D_METHOD("rename_parameter","old_name","new_name"), &AnimationTree::rename_parameter);
ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationTree::advance);
ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationTree::_node_removed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_tree_root", "get_tree_root");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_mode", "get_process_mode");
@ -1338,10 +1436,9 @@ AnimationTree::AnimationTree() {
cache_valid = false;
setup_pass = 1;
started = true;
properties_dirty = true;
}
AnimationTree::~AnimationTree() {
if (root.is_valid()) {
root->player = NULL;
}
}

View file

@ -23,9 +23,6 @@ public:
struct Input {
String name;
StringName connected_to;
float activity;
uint64_t last_pass;
};
Vector<Input> inputs;
@ -51,30 +48,33 @@ public:
List<AnimationState> animation_states;
bool valid;
AnimationPlayer *player;
AnimationTree *tree;
String invalid_reasons;
uint64_t last_pass;
};
Vector<float> blends;
State *state;
float _pre_process(State *p_state, float p_time, bool p_seek);
String path;
float _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName> &p_connections);
void _pre_update_animations(HashMap<NodePath, int> *track_map);
Vector2 position;
//all this is temporary
StringName base_path;
Vector<StringName> connections;
AnimationNode *parent;
AnimationTree *player;
float _blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = NULL);
HashMap<NodePath, bool> filter;
bool filter_enabled;
Array _get_filters() const;
void _set_filters(const Array &p_filters);
friend class AnimationNodeBlendTree;
float _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = NULL);
protected:
void blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend);
float blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true);
float blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true);
float blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true);
void make_invalid(const String &p_reason);
@ -85,20 +85,24 @@ protected:
void _set_parent(Object *p_parent);
public:
void set_parent(AnimationNode *p_parent);
Ref<AnimationNode> get_parent() const;
virtual void set_tree(AnimationTree *p_player);
AnimationTree *get_tree() const;
AnimationPlayer *get_player() const;
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
void set_parameter(const StringName &p_name, const Variant &p_value);
Variant get_parameter(const StringName &p_name) const;
struct ChildNode {
StringName name;
Ref<AnimationNode> node;
};
virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
virtual float process(float p_time, bool p_seek);
virtual String get_caption() const;
int get_input_count() const;
String get_input_name(int p_input);
StringName get_input_connection(int p_input);
void set_input_connection(int p_input, const StringName &p_connection);
float get_input_activity(int p_input) const;
void add_input(const String &p_name);
void set_input_name(int p_input, const String &p_name);
@ -112,8 +116,7 @@ public:
virtual bool has_filter() const;
void set_position(const Vector2 &p_position);
Vector2 get_position() const;
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
AnimationNode();
};
@ -245,7 +248,21 @@ private:
NodePath root_motion_track;
Transform root_motion_transform;
friend class AnimationNode;
bool properties_dirty;
void _tree_changed();
void _update_properties();
List<PropertyInfo> properties;
HashMap<StringName, HashMap<StringName, StringName> > property_parent_map;
HashMap<StringName, Variant> property_map;
void _update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node);
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
void _notification(int p_what);
static void _bind_methods();
@ -274,6 +291,8 @@ public:
void advance(float p_time);
void rename_parameter(const String &p_base, const String &p_new_base);
uint64_t get_last_process_pass() const;
AnimationTree();
~AnimationTree();

View file

@ -356,14 +356,14 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
if (create_hot_zone(pos).has_point(p_point))
if (is_in_hot_zone(pos, p_point))
return true;
}
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
if (create_hot_zone(pos).has_point(p_point)) {
if (is_in_hot_zone(pos, p_point)) {
return true;
}
}
@ -388,7 +388,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
if (create_hot_zone(pos).has_point(mpos)) {
if (is_in_hot_zone(pos, mpos)) {
if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) {
//check disconnect
@ -435,7 +435,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
if (create_hot_zone(pos).has_point(mpos)) {
if (is_in_hot_zone(pos, mpos)) {
if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) {
//check disconnect
@ -502,7 +502,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
int type = gn->get_connection_output_type(j);
if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && create_hot_zone(pos).has_point(mpos)) {
if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) {
connecting_target = true;
connecting_to = pos;
@ -517,7 +517,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
int type = gn->get_connection_input_type(j);
if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && create_hot_zone(pos).has_point(mpos)) {
if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) {
connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
@ -557,8 +557,55 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
Rect2 GraphEdit::create_hot_zone(const Vector2 &pos) {
return Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2);
bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &pos) {
if (p_control->is_set_as_toplevel() || !p_control->is_visible())
return false;
if (!p_control->has_point(pos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) {
//test children
for (int i = 0; i < p_control->get_child_count(); i++) {
Control *subchild = Object::cast_to<Control>(p_control->get_child(i));
if (!subchild)
continue;
if (_check_clickable_control(subchild, pos - subchild->get_position())) {
return true;
}
}
return false;
} else {
return true;
}
}
bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos) {
if (!Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2).has_point(p_mouse_pos))
return false;
for (int i = 0; i < get_child_count(); i++) {
Control *child = Object::cast_to<Control>(get_child(i));
if (!child)
continue;
Rect2 rect = child->get_rect();
if (rect.has_point(p_mouse_pos)) {
//check sub-controls
Vector2 subpos = p_mouse_pos - rect.position;
for (int j = 0; j < child->get_child_count(); j++) {
Control *subchild = Object::cast_to<Control>(child->get_child(j));
if (!subchild)
continue;
if (_check_clickable_control(subchild, subpos - subchild->get_position())) {
return false;
}
}
}
}
return true;
}
template <class Vector2>

View file

@ -131,7 +131,7 @@ private:
GraphEditFilter *top_layer;
void _top_layer_input(const Ref<InputEvent> &p_ev);
Rect2 create_hot_zone(const Vector2 &pos);
bool is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos);
void _top_layer_draw();
void _connections_layer_draw();
@ -172,6 +172,8 @@ private:
void _snap_toggled();
void _snap_value_changed(double);
bool _check_clickable_control(Control *p_control, const Vector2 &pos);
protected:
static void _bind_methods();
virtual void add_child_notify(Node *p_child);

View file

@ -412,6 +412,8 @@ void register_scene_types() {
ClassDB::register_class<AnimationNodeBlendSpace1D>();
ClassDB::register_class<AnimationNodeBlendSpace2D>();
ClassDB::register_class<AnimationNodeStateMachine>();
ClassDB::register_class<AnimationNodeStateMachinePlayback>();
ClassDB::register_class<AnimationNodeStateMachineTransition>();
ClassDB::register_class<AnimationNodeOutput>();
ClassDB::register_class<AnimationNodeOneShot>();

View file

@ -201,4 +201,6 @@ SceneStringNames::SceneStringNames() {
}
_mesh_changed = StaticCString::create("_mesh_changed");
parameters_base_path = "parameters/";
}

View file

@ -203,6 +203,8 @@ public:
StringName output;
StringName parameters_base_path;
enum {
MAX_MATERIALS = 32
};