diff options
244 files changed, 6876 insertions, 416 deletions
diff --git a/core/method_ptrcall.h b/core/method_ptrcall.h index 2007c3def5..677e8e1fb2 100644 --- a/core/method_ptrcall.h +++ b/core/method_ptrcall.h @@ -214,6 +214,50 @@ struct PtrToArg<const T *> { } \ } +#define MAKE_VECARG_ALT(m_type, m_type_alt) \ + template <> \ + struct PtrToArg<Vector<m_type_alt> > { \ + _FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \ + const PoolVector<m_type> *dvs = reinterpret_cast<const PoolVector<m_type> *>(p_ptr); \ + Vector<m_type_alt> ret; \ + int len = dvs->size(); \ + ret.resize(len); \ + { \ + PoolVector<m_type>::Read r = dvs->read(); \ + for (int i = 0; i < len; i++) { \ + ret[i] = r[i]; \ + } \ + } \ + return ret; \ + } \ + _FORCE_INLINE_ static void encode(Vector<m_type_alt> p_vec, void *p_ptr) { \ + PoolVector<m_type> *dv = reinterpret_cast<PoolVector<m_type> *>(p_ptr); \ + int len = p_vec.size(); \ + dv->resize(len); \ + { \ + PoolVector<m_type>::Write w = dv->write(); \ + for (int i = 0; i < len; i++) { \ + w[i] = p_vec[i]; \ + } \ + } \ + } \ + }; \ + template <> \ + struct PtrToArg<const Vector<m_type_alt> &> { \ + _FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \ + const PoolVector<m_type> *dvs = reinterpret_cast<const PoolVector<m_type> *>(p_ptr); \ + Vector<m_type_alt> ret; \ + int len = dvs->size(); \ + ret.resize(len); \ + { \ + PoolVector<m_type>::Read r = dvs->read(); \ + for (int i = 0; i < len; i++) { \ + ret[i] = r[i]; \ + } \ + } \ + return ret; \ + } \ + } MAKE_VECARG(String); MAKE_VECARG(uint8_t); MAKE_VECARG(int); @@ -221,6 +265,7 @@ MAKE_VECARG(float); MAKE_VECARG(Vector2); MAKE_VECARG(Vector3); MAKE_VECARG(Color); +MAKE_VECARG_ALT(String, StringName); //for stuff that gets converted to Array vectors #define MAKE_VECARR(m_type) \ diff --git a/core/object.h b/core/object.h index 7963a43fd6..badb432885 100644 --- a/core/object.h +++ b/core/object.h @@ -85,6 +85,7 @@ enum PropertyHint { PROPERTY_HINT_PROPERTY_OF_INSTANCE, ///< a property of an instance PROPERTY_HINT_PROPERTY_OF_SCRIPT, ///< a property of a script & base PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send + PROPERTY_HINT_NODE_PATH_VALID_TYPES, PROPERTY_HINT_MAX, // When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit }; diff --git a/core/script_language.cpp b/core/script_language.cpp index 1dab58e29e..acbe3b34db 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -347,6 +347,20 @@ Variant::Type PlaceHolderScriptInstance::get_property_type(const StringName &p_n return Variant::NIL; } +void PlaceHolderScriptInstance::get_method_list(List<MethodInfo> *p_list) const { + + if (script.is_valid()) { + script->get_script_method_list(p_list); + } +} +bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const { + + if (script.is_valid()) { + return script->has_method(p_method); + } + return false; +} + void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values) { Set<StringName> new_values; diff --git a/core/script_language.h b/core/script_language.h index ad66fc5528..e7748f93e2 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -304,8 +304,8 @@ public: virtual void get_property_list(List<PropertyInfo> *p_properties) const; virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const; - virtual void get_method_list(List<MethodInfo> *p_list) const {} - virtual bool has_method(const StringName &p_method) const { return false; } + virtual void get_method_list(List<MethodInfo> *p_list) const; + virtual bool has_method(const StringName &p_method) const; virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST) { return Variant(); } virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; diff --git a/core/type_info.h b/core/type_info.h index c1af4fac69..bf497f1e5f 100644 --- a/core/type_info.h +++ b/core/type_info.h @@ -194,6 +194,7 @@ MAKE_TEMPLATE_TYPE_INFO(Vector, Color, Variant::POOL_COLOR_ARRAY) MAKE_TEMPLATE_TYPE_INFO(Vector, Variant, Variant::ARRAY) MAKE_TEMPLATE_TYPE_INFO(Vector, RID, Variant::ARRAY) MAKE_TEMPLATE_TYPE_INFO(Vector, Plane, Variant::ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, StringName, Variant::POOL_STRING_ARRAY) MAKE_TEMPLATE_TYPE_INFO(PoolVector, Plane, Variant::ARRAY) MAKE_TEMPLATE_TYPE_INFO(PoolVector, Face3, Variant::POOL_VECTOR3_ARRAY) diff --git a/core/variant.cpp b/core/variant.cpp index a6df95e310..c48aa57652 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -2012,6 +2012,19 @@ Variant::operator Vector<String>() const { } return to; } +Variant::operator Vector<StringName>() const { + + PoolVector<String> from = operator PoolVector<String>(); + Vector<StringName> to; + int len = from.size(); + to.resize(len); + for (int i = 0; i < len; i++) { + + to[i] = from[i]; + } + return to; +} + Variant::operator Vector<Vector3>() const { PoolVector<Vector3> from = operator PoolVector<Vector3>(); @@ -2444,6 +2457,17 @@ Variant::Variant(const Vector<String> &p_array) { *this = v; } +Variant::Variant(const Vector<StringName> &p_array) { + + type = NIL; + PoolVector<String> v; + int len = p_array.size(); + v.resize(len); + for (int i = 0; i < len; i++) + v.set(i, p_array[i]); + *this = v; +} + Variant::Variant(const Vector<Vector3> &p_array) { type = NIL; diff --git a/core/variant.h b/core/variant.h index f227e4bfdb..4b245d25e6 100644 --- a/core/variant.h +++ b/core/variant.h @@ -216,6 +216,7 @@ public: operator Vector<int>() const; operator Vector<real_t>() const; operator Vector<String>() const; + operator Vector<StringName>() const; operator Vector<Vector3>() const; operator Vector<Color>() const; operator Vector<RID>() const; @@ -280,6 +281,7 @@ public: Variant(const Vector<int> &p_int_array); Variant(const Vector<real_t> &p_real_array); Variant(const Vector<String> &p_string_array); + Variant(const Vector<StringName> &p_string_array); Variant(const Vector<Vector3> &p_vector3_array); Variant(const Vector<Color> &p_color_array); Variant(const Vector<Plane> &p_array); // helper diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index ba62a385af..6ffeddf5c1 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -207,6 +207,7 @@ <return type="Vector2"> </return> <description> + Returns the vector with all components rounded to the nearest integer, with halfway cases rounded away from zero. </description> </method> <method name="slerp"> diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index c754b27f1e..62a480166a 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -208,6 +208,7 @@ <return type="Vector3"> </return> <description> + Returns the vector with all components rounded to the nearest integer, with halfway cases rounded away from zero. </description> </method> <method name="slerp"> diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 30983ca149..2f0982e5d9 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -753,7 +753,6 @@ EditorAutoloadSettings::EditorAutoloadSettings() { autoload_cache.push_back(info); } - List<Node *> to_add; for (List<AutoLoadInfo>::Element *E = autoload_cache.front(); E; E = E->next()) { AutoLoadInfo &info = E->get(); @@ -763,9 +762,6 @@ EditorAutoloadSettings::EditorAutoloadSettings() { Ref<Script> scr = info.node->get_script(); info.in_editor = scr.is_valid() && scr->is_tool(); info.node->set_name(info.name); - if (info.in_editor) { - to_add.push_back(info.node); - } } if (info.is_singleton) { @@ -780,10 +776,6 @@ EditorAutoloadSettings::EditorAutoloadSettings() { } } - for (List<Node *>::Element *E = to_add.front(); E; E = E->next()) { - get_tree()->get_root()->add_child(E->get()); - } - autoload_changed = "autoload_changed"; updating_autoload = false; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 9a3174fb1a..79746dcb5a 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1464,7 +1464,8 @@ void EditorInspector::update_tree() { #endif for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) { Ref<EditorInspectorPlugin> ped = E->get(); - ped->parse_property(object, p.type, p.name, p.hint, p.hint_string, p.usage); + bool exclusive = ped->parse_property(object, p.type, p.name, p.hint, p.hint_string, p.usage); + List<EditorInspectorPlugin::AddedEditor> editors = ped->added_editors; //make a copy, since plugins may be used again in a sub-inspector ped->added_editors.clear(); @@ -1532,6 +1533,10 @@ void EditorInspector::update_tree() { } } } + + if (exclusive) { + break; + } } } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 83f1cd40ba..f099f29204 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -66,9 +66,11 @@ #include "editor/import/resource_importer_scene.h" #include "editor/import/resource_importer_texture.h" #include "editor/import/resource_importer_wav.h" -#include "editor/plugins/animation_blend_space_editor.h" +#include "editor/plugins/animation_blend_space_1d_editor.h" +#include "editor/plugins/animation_blend_space_2d_editor.h" #include "editor/plugins/animation_blend_tree_editor_plugin.h" #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/asset_library_editor_plugin.h" #include "editor/plugins/baked_lightmap_editor_plugin.h" @@ -97,6 +99,7 @@ #include "editor/plugins/physical_bone_plugin.h" #include "editor/plugins/polygon_2d_editor_plugin.h" #include "editor/plugins/resource_preloader_editor_plugin.h" +#include "editor/plugins/root_motion_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/plugins/script_text_editor.h" #include "editor/plugins/shader_editor_plugin.h" @@ -584,7 +587,6 @@ void EditorNode::edit_node(Node *p_node) { void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path) { editor_data.apply_changes_in_editors(); - int flg = 0; if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) flg |= ResourceSaver::FLAG_COMPRESS; @@ -1071,8 +1073,7 @@ void EditorNode::_save_scene(String p_file, int idx) { void EditorNode::_save_all_scenes() { - int i = _next_unsaved_scene(true, 0); - while (i != -1) { + for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { Node *scene = editor_data.get_edited_scene_root(i); if (scene && scene->get_filename() != "") { if (i != editor_data.get_edited_scene()) @@ -1080,7 +1081,6 @@ void EditorNode::_save_all_scenes() { else _save_scene_with_preview(scene->get_filename()); } // else: ignore new scenes - i = _next_unsaved_scene(true, ++i); } _save_default_environment(); @@ -1356,8 +1356,7 @@ void EditorNode::_save_default_environment() { if (fallback.is_valid() && fallback->get_path().is_resource_file()) { Map<RES, bool> processed; _find_and_save_edited_subresources(fallback.ptr(), processed, 0); - if (fallback->get_last_modified_time() != fallback->get_import_last_modified_time()) - save_resource_in_path(fallback, fallback->get_path()); + save_resource_in_path(fallback, fallback->get_path()); } } @@ -4633,6 +4632,10 @@ EditorNode::EditorNode() { Ref<EditorInspectorDefaultPlugin> eidp; eidp.instance(); EditorInspector::add_inspector_plugin(eidp); + + Ref<EditorInspectorRootMotionPlugin> rmp; + rmp.instance(); + EditorInspector::add_inspector_plugin(rmp); } _pvrtc_register_compressors(); @@ -4658,9 +4661,7 @@ EditorNode::EditorNode() { GLOBAL_DEF("editor/main_run_args", ""); - ClassDB::set_class_enabled("CollisionShape", true); - ClassDB::set_class_enabled("CollisionShape2D", true); - ClassDB::set_class_enabled("CollisionPolygon2D", true); + ClassDB::set_class_enabled("RootMotionView", true); //defs here, use EDITOR_GET in logic EDITOR_DEF("interface/scene_tabs/always_show_close_button", false); @@ -5400,7 +5401,9 @@ EditorNode::EditorNode() { // FIXME: Disabled for Godot 3.0 as made incompatible, it needs to be ported to the new API. //add_editor_plugin(memnew(ShaderGraphEditorPlugin(this))); add_editor_plugin(memnew(AnimationNodeBlendTreeEditorPlugin(this))); - add_editor_plugin(memnew(AnimationNodeBlendSpaceEditorPlugin(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))); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 5abcae80e0..2c22484d85 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -1530,6 +1530,8 @@ void EditorPropertyNodePath::_node_selected(const NodePath &p_path) { void EditorPropertyNodePath::_node_assign() { if (!scene_tree) { scene_tree = memnew(SceneTreeDialog); + scene_tree->get_scene_tree()->set_show_enabled_subscene(true); + scene_tree->get_scene_tree()->set_valid_types(valid_types); add_child(scene_tree); scene_tree->connect("selected", this, "_node_selected"); } @@ -1584,9 +1586,10 @@ void EditorPropertyNodePath::update_property() { assign->set_icon(icon); } -void EditorPropertyNodePath::setup(const NodePath &p_base_hint) { +void EditorPropertyNodePath::setup(const NodePath &p_base_hint, Vector<StringName> p_valid_types) { base_hint = p_base_hint; + valid_types = p_valid_types; } void EditorPropertyNodePath::_notification(int p_what) { @@ -1779,6 +1782,7 @@ void EditorPropertyResource::_menu_option(int p_which) { if (!scene_tree) { scene_tree = memnew(SceneTreeDialog); + scene_tree->get_scene_tree()->set_show_enabled_subscene(true); add_child(scene_tree); scene_tree->connect("selected", this, "_viewport_selected"); scene_tree->set_title(TTR("Pick a Viewport")); @@ -2665,7 +2669,12 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ EditorPropertyNodePath *editor = memnew(EditorPropertyNodePath); if (p_hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && p_hint_text != String()) { - editor->setup(p_hint_text); + editor->setup(p_hint_text, Vector<StringName>()); + } + if (p_hint == PROPERTY_HINT_NODE_PATH_VALID_TYPES && p_hint_text != String()) { + Vector<String> types = p_hint_text.split(",", false); + Vector<StringName> sn = Variant(types); //convert via variant + editor->setup(NodePath(), sn); } add_property_editor(p_path, editor); diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 734ca2de82..c67eccb60e 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -453,6 +453,7 @@ class EditorPropertyNodePath : public EditorProperty { SceneTreeDialog *scene_tree; NodePath base_hint; + Vector<StringName> valid_types; void _node_selected(const NodePath &p_path); void _node_assign(); void _node_clear(); @@ -463,7 +464,7 @@ protected: public: virtual void update_property(); - void setup(const NodePath &p_base_hint); + void setup(const NodePath &p_base_hint, Vector<StringName> p_valid_types); EditorPropertyNodePath(); }; diff --git a/editor/icons/icon_animation_tree.svg b/editor/icons/icon_animation_tree.svg new file mode 100644 index 0000000000..046506fa37 --- /dev/null +++ b/editor/icons/icon_animation_tree.svg @@ -0,0 +1,5 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<g transform="translate(0 -1036.4)"> +<path transform="translate(0 1036.4)" d="m1 1v14h1.166v-2h1.834v2h8v-2h2v2h1v-14h-1v2h-2v-2h-8v2h-1.834v-2h-1.166zm4 3h2v1 1h1 3v2h-2v1 1h1 1v2h-1-2a1.0001 1.0001 0 0 1 -1 -1v-1-2h-1a1.0001 1.0001 0 0 1 -1 -1v-1-1-1zm-2.834 1h1.834v2h-1.834v-2zm9.834 0h2v2h-2v-2zm-9.834 4h1.834v2h-1.834v-2zm9.834 0h2v2h-2v-2z" fill="#cea4f1"/> +</g> +</svg> diff --git a/editor/icons/icon_auto_end.svg b/editor/icons/icon_auto_end.svg new file mode 100644 index 0000000000..9e779c69f4 --- /dev/null +++ b/editor/icons/icon_auto_end.svg @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg6" + sodipodi:docname="icon_auto_end.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1273" + inkscape:window-height="766" + id="namedview8" + showgrid="false" + inkscape:zoom="41.7193" + inkscape:cx="12.08616" + inkscape:cy="6.9898672" + inkscape:window-x="539" + inkscape:window-y="208" + inkscape:window-maximized="0" + inkscape:current-layer="svg6" /> + <path + inkscape:connector-curvature="0" + id="path2" + style="color:#000000;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + d="m 13.999798,14 c 0.552262,-5.5e-5 0.999945,-0.447738 1,-1 V 3 c -5.5e-5,-0.5522619 -0.447738,-0.9999448 -1,-1 H 5.9997976 C 5.6959349,1.9998247 5.4084731,2.1378063 5.2185476,2.375 l -4,5 c -0.29139692,0.3649711 -0.29139692,0.8830289 0,1.248 l 4,5 c 0.189538,0.237924 0.4770584,0.376652 0.78125,0.37695 h 8.0000004 z m -1,-2 H 6.4802976 l -3.1992,-4 3.1992,-4 H 12.999798 Z M 6.9997976,10 V 6 l -2,2 z" + sodipodi:nodetypes="cccccccccccccccccccccc" /> + <g + aria-label="E" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#e0e0e0;fill-opacity:1;stroke:none" + id="text829" + transform="matrix(0.20475474,0,0,0.20475474,4.7903856,12.365563)"> + <path + d="M 15.129502,-36.414393 H 35.422471 V -30.7308 H 22.649034 v 5.429688 h 12.011718 v 5.683594 H 22.649034 v 6.679687 h 13.203125 v 5.6835938 H 15.129502 Z" + style="fill:#e0e0e0;fill-opacity:1" + id="path831" + inkscape:connector-curvature="0" /> + </g> +</svg> diff --git a/editor/icons/icon_play_travel.svg b/editor/icons/icon_play_travel.svg new file mode 100644 index 0000000000..5cd3e07e20 --- /dev/null +++ b/editor/icons/icon_play_travel.svg @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_play_travel.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1446" + inkscape:window-height="646" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="8.2818541" + inkscape:cy="5.7694884" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="matrix(0.59321602,0,0,0.59321602,-1.2203136,-611.14809)" + id="g6"> + <g + id="g4"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <g + transform="matrix(0.59321602,0,0,0.59321602,7.5254716,-610.94451)" + id="g6-3"> + <g + id="g4-6"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2-7" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#e0e0e0;fill-opacity:1" + id="rect842" + width="9.5593224" + height="0.54237264" + x="3.0058463" + y="8.1280737" + ry="0.27118632" /> +</svg> diff --git a/editor/icons/icon_tool_add_node.svg b/editor/icons/icon_tool_add_node.svg new file mode 100644 index 0000000000..a4ff4d08a0 --- /dev/null +++ b/editor/icons/icon_tool_add_node.svg @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_tool_add_node.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1516" + inkscape:window-height="747" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="8" + inkscape:cy="8" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="translate(0 -1036.4)" + id="g6"> + <g + transform="translate(-26.001 -9.8683)" + id="g4"> + <path + style="fill:#e0e0e0;fill-opacity:1" + d="m 27.917081,1047.5557 c -0.422624,0 -0.763672,0.3411 -0.763672,0.7637 v 11.8301 c 0,0.4226 0.341048,0.7637 0.763672,0.7637 h 12.507813 c 0.422624,0 0.761719,-0.3411 0.761719,-0.7637 v -11.8301 c 0,-0.4226 -0.339095,-0.7637 -0.761719,-0.7637 z m 1.898438,1.6954 h 8.642578 c 0.422624,0 0.763672,0.341 0.763672,0.7636 v 8.5078 c 0,0.4227 -0.341048,0.7618 -0.763672,0.7618 h -8.642578 c -0.422625,0 -0.763672,-0.3391 -0.763672,-0.7618 v -8.5078 c 0,-0.4226 0.341047,-0.7636 0.763672,-0.7636 z" + id="rect821" + inkscape:connector-curvature="0" /> + <rect + style="fill:#e0e0e0;fill-opacity:1" + id="rect826" + width="7.7966104" + height="2.3728814" + x="30.20439" + y="1052.9802" + ry="0.76286" /> + <rect + style="fill:#e0e0e0;fill-opacity:1;stroke-width:0.88253576" + id="rect828" + width="2.3728814" + height="7.5254235" + x="32.916256" + y="1050.3361" + ry="0.72997814" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_tool_connect.svg b/editor/icons/icon_tool_connect.svg new file mode 100644 index 0000000000..91d5893163 --- /dev/null +++ b/editor/icons/icon_tool_connect.svg @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_tool_connect.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1516" + inkscape:window-height="747" + id="namedview10" + showgrid="false" + inkscape:zoom="3.6875" + inkscape:cx="8.5909556" + inkscape:cy="7.8012075" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="translate(0 -1036.4)" + id="g6"> + <g + transform="translate(-26.001 -9.8683)" + id="g4"> + <rect + style="fill:#e0e0e0;fill-opacity:1" + id="rect849" + width="14.305085" + height="2.1694915" + x="26.766621" + y="1053.1389" + ry="0.76286" /> + <path + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:1.16725671px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 30.596131,1046.927 v 14.8861 l 8.228847,-7.5722 z" + id="path853" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_transition_end.svg b/editor/icons/icon_transition_end.svg new file mode 100644 index 0000000000..8a1937670a --- /dev/null +++ b/editor/icons/icon_transition_end.svg @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_end.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="10.204146" + inkscape:cy="5.3391396" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="translate(-2,-1036.4)" + id="g6"> + <g + id="g4"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east_asian:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#e0e0e0;fill-opacity:1" + id="rect862" + width="3.0681243" + height="10.067283" + x="11.16989" + y="3.0084109" + ry="0.76286" /> +</svg> diff --git a/editor/icons/icon_transition_end_auto.svg b/editor/icons/icon_transition_end_auto.svg new file mode 100644 index 0000000000..18927bc4ef --- /dev/null +++ b/editor/icons/icon_transition_end_auto.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_automatic.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="0.56831798" + inkscape:cy="5.1473818" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="translate(-2,-1036.4)" + id="g6" + style="fill:#77ce57;fill-opacity:1"> + <g + id="g4" + style="fill:#77ce57;fill-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east_asian:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto;fill-opacity:1" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#77ce57;fill-opacity:1" + id="rect862" + width="3.0681243" + height="10.067283" + x="11.16989" + y="3.0084109" + ry="0.76286" /> +</svg> diff --git a/editor/icons/icon_transition_end_auto_big.svg b/editor/icons/icon_transition_end_auto_big.svg new file mode 100644 index 0000000000..aaedafaf04 --- /dev/null +++ b/editor/icons/icon_transition_end_auto_big.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_automatic_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="0.3064671" + inkscape:cy="14.348448" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="matrix(1.4099529,0,0,1.4099529,-4.1975887,-1462.5094)" + id="g6" + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-opacity:1"> + <g + id="g4" + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-opacity:1;fill-rule:evenodd;stroke:#41562e;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-width:1.409953;stroke-opacity:1" + id="rect862" + width="4.3259106" + height="14.194397" + x="14.371336" + y="3.0076122" + ry="1.0755967" /> +</svg> diff --git a/editor/icons/icon_transition_end_big.svg b/editor/icons/icon_transition_end_big.svg new file mode 100644 index 0000000000..46d42e95e3 --- /dev/null +++ b/editor/icons/icon_transition_end_big.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_end_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="-1.1122019" + inkscape:cy="10.839132" + inkscape:window-x="517" + inkscape:window-y="261" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="matrix(1.4203458,0,0,1.4203458,-4.29479,-1473.1325)" + id="g6" + style="stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> + <g + id="g4" + style="stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#e0e0e0;fill-opacity:1;stroke:#424242;stroke-width:1.42026603;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect862" + width="4.3577976" + height="14.299023" + x="14.411009" + y="3.1868868" + ry="1.0835251" /> +</svg> diff --git a/editor/icons/icon_transition_immediate.svg b/editor/icons/icon_transition_immediate.svg new file mode 100644 index 0000000000..ba16a33c91 --- /dev/null +++ b/editor/icons/icon_transition_immediate.svg @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_immediate.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="4.0199579" + inkscape:cy="5.3391396" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="translate(-2,-1036.4)" + id="g6"> + <g + id="g4"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east_asian:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto;fill-opacity:1" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_transition_immediate_auto.svg b/editor/icons/icon_transition_immediate_auto.svg new file mode 100644 index 0000000000..c127560145 --- /dev/null +++ b/editor/icons/icon_transition_immediate_auto.svg @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_immediate_auto.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="-9.2592678" + inkscape:cy="5.3391396" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="translate(-2,-1036.4)" + id="g6"> + <g + id="g4"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east_asian:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto;fill-opacity:1" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_transition_immediate_auto_big.svg b/editor/icons/icon_transition_immediate_auto_big.svg new file mode 100644 index 0000000000..80d35a36f3 --- /dev/null +++ b/editor/icons/icon_transition_immediate_auto_big.svg @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_immediate_auto_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="11.321237" + inkscape:cy="3.5752171" + inkscape:window-x="517" + inkscape:window-y="261" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="matrix(1.571031,0,0,1.571031,-2.7257681,-1630.6239)" + id="g6" + style="stroke:#404040;stroke-opacity:1"> + <g + id="g4" + style="stroke:#404040;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-rule:evenodd;stroke:#41562e;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;fill-opacity:1" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_transition_immediate_big.svg b/editor/icons/icon_transition_immediate_big.svg new file mode 100644 index 0000000000..108dcdd500 --- /dev/null +++ b/editor/icons/icon_transition_immediate_big.svg @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_immediate_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="0.19928629" + inkscape:cy="4.534006" + inkscape:window-x="517" + inkscape:window-y="261" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="matrix(1.571031,0,0,1.571031,-2.7257681,-1630.6239)" + id="g6" + style="stroke:#404040;stroke-opacity:1"> + <g + id="g4" + style="stroke:#404040;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;stroke:#404040;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;fill-opacity:1" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_transition_sync.svg b/editor/icons/icon_transition_sync.svg new file mode 100644 index 0000000000..267d806615 --- /dev/null +++ b/editor/icons/icon_transition_sync.svg @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_sync.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="10.204146" + inkscape:cy="5.3391396" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="translate(2.5542471,-1036.4)" + id="g6"> + <g + id="g4"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#e0e0e0;fill-opacity:1" + id="rect862" + width="3.0681243" + height="10.067283" + x="1.9655174" + y="3.0084109" + ry="0.76286" /> +</svg> diff --git a/editor/icons/icon_transition_sync_auto.svg b/editor/icons/icon_transition_sync_auto.svg new file mode 100644 index 0000000000..5ce61e3a6a --- /dev/null +++ b/editor/icons/icon_transition_sync_auto.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_sync_auto.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="0.56831798" + inkscape:cy="5.1473818" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="translate(3.0815809,-1036.4)" + id="g6" + style="fill:#77ce57;fill-opacity:1"> + <g + id="g4" + style="fill:#77ce57;fill-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-opacity:1;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#77ce57;fill-opacity:1" + id="rect862" + width="3.0681243" + height="10.067283" + x="1.9655174" + y="3.0084109" + ry="0.76286" /> +</svg> diff --git a/editor/icons/icon_transition_sync_auto_big.svg b/editor/icons/icon_transition_sync_auto_big.svg new file mode 100644 index 0000000000..3e84d76398 --- /dev/null +++ b/editor/icons/icon_transition_sync_auto_big.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_sync_auto_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="0.3064671" + inkscape:cy="14.348448" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="matrix(1.4099529,0,0,1.4099529,2.1752927,-1462.5094)" + id="g6" + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-opacity:1"> + <g + id="g4" + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-opacity:1;fill-rule:evenodd;stroke:#41562e;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-width:1.409953;stroke-opacity:1" + id="rect862" + width="4.3259106" + height="14.194397" + x="1.6255733" + y="3.0076122" + ry="1.0755967" /> +</svg> diff --git a/editor/icons/icon_transition_sync_big.svg b/editor/icons/icon_transition_sync_big.svg new file mode 100644 index 0000000000..e7cf63e0b3 --- /dev/null +++ b/editor/icons/icon_transition_sync_big.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_sync_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="19.226781" + inkscape:cy="9.27981" + inkscape:window-x="302" + inkscape:window-y="226" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="matrix(1.4203458,0,0,1.4203458,1.8747015,-1473.1325)" + id="g6" + style="stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> + <g + id="g4" + style="stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#e0e0e0;fill-opacity:1;stroke:#424242;stroke-width:1.42026603;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect862" + width="4.3577976" + height="14.299023" + x="1.4618562" + y="3.1868868" + ry="1.0835251" /> +</svg> diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 21803a2184..b8dd4a87b7 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -188,7 +188,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati return OK; } -static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p_single_mesh, bool p_generate_tangents, Vector3 p_scale_mesh, List<String> *r_missing_deps) { +static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, List<String> *r_missing_deps) { FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); @@ -200,6 +200,8 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p bool generate_tangents = p_generate_tangents; Vector3 scale_mesh = p_scale_mesh; bool flip_faces = false; + int mesh_flags = p_optimize ? Mesh::ARRAY_COMPRESS_DEFAULT : 0; + //bool flip_faces = p_options["force/flip_faces"]; //bool force_smooth = p_options["force/smooth_shading"]; //bool weld_vertices = p_options["force/weld_vertices"]; @@ -331,7 +333,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p surf_tool->set_material(material_map[current_material_library][current_material]); } - mesh = surf_tool->commit(mesh); + mesh = surf_tool->commit(mesh, mesh_flags); if (current_material != String()) { mesh->surface_set_name(mesh->get_surface_count() - 1, current_material.get_basename()); @@ -402,7 +404,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in List<Ref<Mesh> > meshes; - Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, Vector3(1, 1, 1), r_missing_deps); + Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & IMPORT_USE_COMPRESSION, Vector3(1, 1, 1), r_missing_deps); if (err != OK) { if (r_err) { @@ -470,6 +472,7 @@ void ResourceImporterOBJ::get_import_options(List<ImportOption> *r_options, int r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_tangents"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "scale_mesh"), Vector3(1, 1, 1))); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "optimize_mesh"), true)); } bool ResourceImporterOBJ::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { @@ -480,7 +483,7 @@ Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_s List<Ref<Mesh> > meshes; - Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["scale_mesh"], NULL); + Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["optimize_mesh"], p_options["scale_mesh"], NULL); ERR_FAIL_COND_V(err != OK, err); ERR_FAIL_COND_V(meshes.size() != 1, ERR_BUG); diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp new file mode 100644 index 0000000000..2e128db883 --- /dev/null +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -0,0 +1,741 @@ +#include "animation_blend_space_1d_editor.h" + +#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)); +} + +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; + + if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) { + if (selected_point != -1) { + _erase_selected(); + accept_event(); + } + } + + Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (mb->get_button_index() == BUTTON_LEFT && tool_create->is_pressed()))) { + menu->clear(); + animations_menu->clear(); + animations_to_add.clear(); + + List<StringName> classes; + ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); + classes.sort_custom<StringName::AlphCompare>(); + + menu->add_submenu_item(TTR("Add Animation"), "animations"); + + AnimationTree *gp = blend_space->get_tree(); + ERR_FAIL_COND(!gp); + + if (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); + + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + animations_menu->add_icon_item(get_icon("Animation", "Editoricons"), E->get()); + animations_to_add.push_back(E->get()); + } + } + } + + for (List<StringName>::Element *E = classes.front(); E; E = E->next()) { + String name = String(E->get()).replace_first("AnimationNode", ""); + if (name == "Animation") + continue; + + int idx = menu->get_item_count(); + menu->add_item(vformat("Add %s", name)); + menu->set_item_metadata(idx, E->get()); + } + + 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()).x; + add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); + add_point_pos += blend_space->get_min_space(); + + if (snap->is_pressed()) { + add_point_pos = Math::stepify(add_point_pos, blend_space->get_snap()); + } + } + + if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + blend_space_draw->update(); // why not + + // try to see if a point can be selected + selected_point = -1; + _update_tool_erase(); + + for (int i = 0; i < points.size(); i++) { + + if (Math::abs(float(points[i] - mb->get_position().x)) < 10 * EDSCALE) { + selected_point = i; + + Ref<AnimationNode> node = blend_space->get_blend_point_node(i); + EditorNode::get_singleton()->push_item(node.ptr(), "", true); + dragging_selected_attempt = true; + drag_from = mb->get_position(); + _update_tool_erase(); + _update_edited_point_pos(); + return; + } + } + } + + if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT) { + if (dragging_selected) { + // move + float point = blend_space->get_blend_point_position(selected_point); + point += drag_ofs.x; + + if (snap->is_pressed()) { + point = Math::stepify(point, blend_space->get_snap()); + } + + updating = true; + undo_redo->create_action("Move Node Point"); + undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point); + undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->add_do_method(this, "_update_edited_point_pos"); + undo_redo->add_undo_method(this, "_update_edited_point_pos"); + undo_redo->commit_action(); + updating = false; + _update_edited_point_pos(); + } + + dragging_selected_attempt = false; + dragging_selected = false; + blend_space_draw->update(); + } + + // *set* the blend + if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + float blend_pos = mb->get_position().x / blend_space_draw->get_size().x; + 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); + blend_space_draw->update(); + } + + Ref<InputEventMouseMotion> mm = p_event; + + if (mm.is_valid() && !blend_space_draw->has_focus()) { + blend_space_draw->grab_focus(); + blend_space_draw->update(); + } + + if (mm.is_valid() && dragging_selected_attempt) { + dragging_selected = true; + drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * ((blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, 0)); + blend_space_draw->update(); + _update_edited_point_pos(); + } + + if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & BUTTON_MASK_LEFT) { + float blend_pos = mm->get_position().x / blend_space_draw->get_size().x; + 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); + blend_space_draw->update(); + } +} + +void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { + + Color linecolor = get_color("font_color", "Label"); + Color linecolor_soft = linecolor; + linecolor_soft.a *= 0.5; + + Ref<Font> font = get_font("font", "Label"); + Ref<Texture> icon = get_icon("KeyValue", "EditorIcons"); + Ref<Texture> icon_selected = get_icon("KeySelected", "EditorIcons"); + + Size2 s = blend_space_draw->get_size(); + + if (blend_space_draw->has_focus()) { + Color color = get_color("accent_color", "Editor"); + blend_space_draw->draw_rect(Rect2(Point2(), s), color, false); + } + + blend_space_draw->draw_line(Point2(1, s.height - 1), Point2(s.width - 1, s.height - 1), linecolor); + + if (blend_space->get_min_space() < 0) { + float point = 0.0; + point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); + point *= s.width; + + float x = point; + + blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor); + blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height() + font->get_ascent()), "0", linecolor); + blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft); + } + + if (snap->is_pressed()) { + + linecolor_soft.a = linecolor.a * 0.1; + + if (blend_space->get_snap() > 0) { + int prev_idx = -1; + + for (int i = 0; i < s.x; i++) { + float v = blend_space->get_min_space() + i * (blend_space->get_max_space() - blend_space->get_min_space()) / s.x; + int idx = int(v / blend_space->get_snap()); + + if (i > 0 && prev_idx != idx) { + blend_space_draw->draw_line(Point2(i, 0), Point2(i, s.height), linecolor_soft); + } + + prev_idx = idx; + } + } + } + + points.clear(); + + for (int i = 0; i < blend_space->get_blend_point_count(); i++) { + float point = blend_space->get_blend_point_position(i); + + if (dragging_selected && selected_point == i) { + point += drag_ofs.x; + if (snap->is_pressed()) { + point = Math::stepify(point, blend_space->get_snap()); + } + } + + point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); + point *= s.width; + + points.push_back(point); + + Vector2 gui_point = Vector2(point, s.height / 2.0); + + gui_point -= (icon->get_size() / 2.0); + + gui_point = gui_point.floor(); + + if (i == selected_point) { + blend_space_draw->draw_texture(icon_selected, gui_point); + } else { + blend_space_draw->draw_texture(icon, gui_point); + } + } + + // blend position + { + Color color; + if (tool_blend->is_pressed()) { + color = get_color("accent_color", "Editor"); + } else { + color = linecolor; + color.a *= 0.5; + } + + float point = blend_space->get_blend_pos(); + point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); + point *= s.width; + + Vector2 gui_point = Vector2(point, s.height / 2.0); + + float mind = 5 * EDSCALE; + float maxd = 15 * EDSCALE; + blend_space_draw->draw_line(gui_point + Vector2(mind, 0), gui_point + Vector2(maxd, 0), color, 2); + blend_space_draw->draw_line(gui_point + Vector2(-mind, 0), gui_point + Vector2(-maxd, 0), color, 2); + blend_space_draw->draw_line(gui_point + Vector2(0, mind), gui_point + Vector2(0, maxd), color, 2); + blend_space_draw->draw_line(gui_point + Vector2(0, -mind), gui_point + Vector2(0, -maxd), color, 2); + } +} + +void AnimationNodeBlendSpace1DEditor::_update_space() { + + if (updating) + return; + + 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()); + + label_value->set_text(blend_space->get_value_label()); + + snap_value->set_value(blend_space->get_snap()); + + blend_space_draw->update(); + + updating = false; +} + +void AnimationNodeBlendSpace1DEditor::_config_changed(double) { + if (updating) + return; + + updating = true; + undo_redo->create_action("Change BlendSpace1D Limits"); + undo_redo->add_do_method(blend_space.ptr(), "set_max_space", max_value->get_value()); + undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space()); + undo_redo->add_do_method(blend_space.ptr(), "set_min_space", min_value->get_value()); + undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space()); + undo_redo->add_do_method(blend_space.ptr(), "set_snap", snap_value->get_value()); + undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap()); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->commit_action(); + updating = false; + + blend_space_draw->update(); +} + +void AnimationNodeBlendSpace1DEditor::_labels_changed(String) { + if (updating) + return; + + updating = true; + undo_redo->create_action("Change BlendSpace1D Labels", UndoRedo::MERGE_ENDS); + undo_redo->add_do_method(blend_space.ptr(), "set_value_label", label_value->get_text()); + undo_redo->add_undo_method(blend_space.ptr(), "set_value_label", blend_space->get_value_label()); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->commit_action(); + updating = false; +} + +void AnimationNodeBlendSpace1DEditor::_snap_toggled() { + blend_space_draw->update(); +} + +void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) { + 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); + + Ref<AnimationNode> node(an); + + updating = true; + undo_redo->create_action("Add Node Point"); + undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos); + undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->commit_action(); + updating = false; + + blend_space_draw->update(); +} + +void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) { + Ref<AnimationNodeAnimation> anim; + anim.instance(); + + anim->set_animation(animations_to_add[p_index]); + + updating = true; + undo_redo->create_action("Add Animation Point"); + undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos); + undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->commit_action(); + updating = false; + + blend_space_draw->update(); +} + +void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) { + + if (p_tool == 0) { + tool_erase->show(); + tool_erase_sep->show(); + } else { + tool_erase->hide(); + tool_erase_sep->hide(); + } + + _update_tool_erase(); + blend_space_draw->update(); +} + +void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() { + if (updating) + return; + + if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { + float pos = blend_space->get_blend_point_position(selected_point); + + if (dragging_selected) { + pos += drag_ofs.x; + + if (snap->is_pressed()) { + pos = Math::stepify(pos, blend_space->get_snap()); + } + } + + updating = true; + edit_value->set_value(pos); + updating = false; + } +} + +void AnimationNodeBlendSpace1DEditor::_update_tool_erase() { + + bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count(); + tool_erase->set_disabled(!point_valid); + + if (point_valid) { + Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); + + if (EditorNode::get_singleton()->item_has_editor(an.ptr())) { + open_editor->show(); + } else { + open_editor->hide(); + } + + edit_hb->show(); + } else { + edit_hb->hide(); + } +} + +void AnimationNodeBlendSpace1DEditor::_erase_selected() { + if (selected_point != -1) { + updating = true; + + undo_redo->create_action("Remove BlendSpace1D Point"); + undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point); + undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", blend_space->get_blend_point_node(selected_point), blend_space->get_blend_point_position(selected_point), selected_point); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->commit_action(); + + updating = false; + + blend_space_draw->update(); + } +} + +void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) { + if (updating) + return; + + updating = true; + undo_redo->create_action("Move BlendSpace1D Node Point"); + undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, edit_value->get_value()); + undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->add_do_method(this, "_update_edited_point_pos"); + undo_redo->add_undo_method(this, "_update_edited_point_pos"); + undo_redo->commit_action(); + updating = false; + + blend_space_draw->update(); +} + +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()); + } +} + +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) { + 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")); + tool_blend->set_icon(get_icon("EditPivot", "EditorIcons")); + tool_select->set_icon(get_icon("ToolSelect", "EditorIcons")); + tool_create->set_icon(get_icon("EditKey", "EditorIcons")); + 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()) { + 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(); + } + + if (error != error_label->get_text()) { + error_label->set_text(error); + if (error != String()) { + error_panel->show(); + } else { + error_panel->hide(); + } + } + } +} + +void AnimationNodeBlendSpace1DEditor::_bind_methods() { + ClassDB::bind_method("_blend_space_gui_input", &AnimationNodeBlendSpace1DEditor::_blend_space_gui_input); + ClassDB::bind_method("_blend_space_draw", &AnimationNodeBlendSpace1DEditor::_blend_space_draw); + ClassDB::bind_method("_config_changed", &AnimationNodeBlendSpace1DEditor::_config_changed); + ClassDB::bind_method("_labels_changed", &AnimationNodeBlendSpace1DEditor::_labels_changed); + ClassDB::bind_method("_update_space", &AnimationNodeBlendSpace1DEditor::_update_space); + ClassDB::bind_method("_snap_toggled", &AnimationNodeBlendSpace1DEditor::_snap_toggled); + ClassDB::bind_method("_tool_switch", &AnimationNodeBlendSpace1DEditor::_tool_switch); + ClassDB::bind_method("_erase_selected", &AnimationNodeBlendSpace1DEditor::_erase_selected); + ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace1DEditor::_update_tool_erase); + ClassDB::bind_method("_edit_point_pos", &AnimationNodeBlendSpace1DEditor::_edit_point_pos); + + ClassDB::bind_method("_add_menu_type", &AnimationNodeBlendSpace1DEditor::_add_menu_type); + ClassDB::bind_method("_add_animation_type", &AnimationNodeBlendSpace1DEditor::_add_animation_type); + + 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); +} + +void AnimationNodeBlendSpace1DEditor::edit(AnimationNodeBlendSpace1D *p_blend_space) { + + if (blend_space.is_valid()) { + blend_space->disconnect("removed_from_graph", this, "_removed_from_graph"); + } + + if (p_blend_space) { + blend_space = Ref<AnimationNodeBlendSpace1D>(p_blend_space); + } else { + blend_space.unref(); + } + + if (blend_space.is_null()) { + hide(); + } else { + blend_space->connect("removed_from_graph", this, "_removed_from_graph"); + + _update_space(); + } +} + +AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = NULL; + +AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { + singleton = this; + updating = false; + + HBoxContainer *top_hb = memnew(HBoxContainer); + add_child(top_hb); + + 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); + top_hb->add_child(tool_blend); + tool_blend->set_pressed(true); + tool_blend->set_tooltip(TTR("Set the blending position within the space")); + tool_blend->connect("pressed", this, "_tool_switch", varray(3)); + + tool_select = memnew(ToolButton); + tool_select->set_toggle_mode(true); + tool_select->set_button_group(bg); + top_hb->add_child(tool_select); + tool_select->set_tooltip(TTR("Select and move points, create points with RMB.")); + tool_select->connect("pressed", this, "_tool_switch", varray(0)); + + tool_create = memnew(ToolButton); + tool_create->set_toggle_mode(true); + tool_create->set_button_group(bg); + top_hb->add_child(tool_create); + tool_create->set_tooltip(TTR("Create points.")); + tool_create->connect("pressed", this, "_tool_switch", varray(1)); + + tool_erase_sep = memnew(VSeparator); + top_hb->add_child(tool_erase_sep); + tool_erase = memnew(ToolButton); + top_hb->add_child(tool_erase); + tool_erase->set_tooltip(TTR("Erase points.")); + tool_erase->connect("pressed", this, "_erase_selected"); + + top_hb->add_child(memnew(VSeparator)); + + snap = memnew(ToolButton); + snap->set_toggle_mode(true); + top_hb->add_child(snap); + snap->set_pressed(true); + snap->connect("pressed", this, "_snap_toggled"); + + snap_value = memnew(SpinBox); + top_hb->add_child(snap_value); + snap_value->set_min(0.01); + snap_value->set_step(0.01); + snap_value->set_max(1000); + + edit_hb = memnew(HBoxContainer); + top_hb->add_child(edit_hb); + edit_hb->add_child(memnew(VSeparator)); + edit_hb->add_child(memnew(Label(TTR("Point")))); + + edit_value = memnew(SpinBox); + edit_hb->add_child(edit_value); + edit_value->set_min(-1000); + edit_value->set_max(1000); + edit_value->set_step(0.01); + edit_value->connect("value_changed", this, "_edit_point_pos"); + + open_editor = memnew(Button); + edit_hb->add_child(open_editor); + open_editor->set_text(TTR("Open Editor")); + open_editor->connect("pressed", this, "_open_editor", varray(), CONNECT_DEFERRED); + + edit_hb->hide(); + open_editor->hide(); + + VBoxContainer *main_vb = memnew(VBoxContainer); + add_child(main_vb); + main_vb->set_v_size_flags(SIZE_EXPAND_FILL); + + panel = memnew(PanelContainer); + panel->set_clip_contents(true); + main_vb->add_child(panel); + panel->set_h_size_flags(SIZE_EXPAND_FILL); + panel->set_v_size_flags(SIZE_EXPAND_FILL); + + blend_space_draw = memnew(Control); + blend_space_draw->connect("gui_input", this, "_blend_space_gui_input"); + blend_space_draw->connect("draw", this, "_blend_space_draw"); + blend_space_draw->set_focus_mode(FOCUS_ALL); + + panel->add_child(blend_space_draw); + + { + HBoxContainer *bottom_hb = memnew(HBoxContainer); + main_vb->add_child(bottom_hb); + bottom_hb->set_h_size_flags(SIZE_EXPAND_FILL); + + min_value = memnew(SpinBox); + min_value->set_max(0); + min_value->set_min(-10000); + min_value->set_step(0.01); + + max_value = memnew(SpinBox); + max_value->set_max(10000); + max_value->set_min(0.01); + max_value->set_step(0.01); + + label_value = memnew(LineEdit); + label_value->set_expand_to_text_length(true); + + // now add + + bottom_hb->add_child(min_value); + bottom_hb->add_spacer(); + bottom_hb->add_child(label_value); + bottom_hb->add_spacer(); + bottom_hb->add_child(max_value); + } + + snap_value->connect("value_changed", this, "_config_changed"); + min_value->connect("value_changed", this, "_config_changed"); + max_value->connect("value_changed", this, "_config_changed"); + label_value->connect("text_changed", this, "_labels_changed"); + + error_panel = memnew(PanelContainer); + add_child(error_panel); + + error_label = memnew(Label); + error_panel->add_child(error_label); + error_label->set_text("hmmm"); + + undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + menu = memnew(PopupMenu); + add_child(menu); + menu->connect("index_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"); + + selected_point = -1; + dragging_selected = false; + dragging_selected_attempt = false; + + set_custom_minimum_size(Size2(0, 150 * EDSCALE)); +} diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h new file mode 100644 index 0000000000..52139626e6 --- /dev/null +++ b/editor/plugins/animation_blend_space_1d_editor.h @@ -0,0 +1,117 @@ +#ifndef ANIMATION_BLEND_SPACE_1D_EDITOR_H +#define ANIMATION_BLEND_SPACE_1D_EDITOR_H + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "editor/property_editor.h" +#include "scene/animation/animation_blend_space_1d.h" +#include "scene/gui/button.h" +#include "scene/gui/graph_edit.h" +#include "scene/gui/popup.h" +#include "scene/gui/tree.h" + +class AnimationNodeBlendSpace1DEditor : public VBoxContainer { + + GDCLASS(AnimationNodeBlendSpace1DEditor, VBoxContainer) + + Ref<AnimationNodeBlendSpace1D> blend_space; + + HBoxContainer *goto_parent_hb; + ToolButton *goto_parent; + + PanelContainer *panel; + ToolButton *tool_blend; + ToolButton *tool_select; + ToolButton *tool_create; + VSeparator *tool_erase_sep; + ToolButton *tool_erase; + ToolButton *snap; + SpinBox *snap_value; + + LineEdit *label_value; + SpinBox *max_value; + SpinBox *min_value; + + HBoxContainer *edit_hb; + SpinBox *edit_value; + Button *open_editor; + + int selected_point; + + Control *blend_space_draw; + + PanelContainer *error_panel; + Label *error_label; + + bool updating; + + UndoRedo *undo_redo; + + static AnimationNodeBlendSpace1DEditor *singleton; + + void _blend_space_gui_input(const Ref<InputEvent> &p_event); + void _blend_space_draw(); + + void _update_space(); + + void _config_changed(double); + void _labels_changed(String); + void _snap_toggled(); + + PopupMenu *menu; + PopupMenu *animations_menu; + Vector<String> animations_to_add; + float add_point_pos; + Vector<float> points; + + bool dragging_selected_attempt; + bool dragging_selected; + Vector2 drag_from; + Vector2 drag_ofs; + + void _add_menu_type(int p_index); + void _add_animation_type(int p_index); + + void _tool_switch(int p_tool); + void _update_edited_point_pos(); + void _update_tool_erase(); + void _erase_selected(); + void _edit_point_pos(double); + void _open_editor(); + + void _goto_parent(); + + void _removed_from_graph(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + static AnimationNodeBlendSpace1DEditor *get_singleton() { return singleton; } + void edit(AnimationNodeBlendSpace1D *p_blend_space); + 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 diff --git a/editor/plugins/animation_blend_space_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 9118211bf2..8d17062248 100644 --- a/editor/plugins/animation_blend_space_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -1,4 +1,4 @@ -#include "animation_blend_space_editor.h" +#include "animation_blend_space_2d_editor.h" #include "core/io/resource_loader.h" #include "core/project_settings.h" @@ -11,14 +11,14 @@ #include "scene/gui/panel.h" #include "scene/main/viewport.h" -void AnimationNodeBlendSpaceEditor::edit(AnimationNodeBlendSpace *p_blend_space) { +void AnimationNodeBlendSpace2DEditor::edit(AnimationNodeBlendSpace2D *p_blend_space) { if (blend_space.is_valid()) { blend_space->disconnect("removed_from_graph", this, "_removed_from_graph"); } if (p_blend_space) { - blend_space = Ref<AnimationNodeBlendSpace>(p_blend_space); + blend_space = Ref<AnimationNodeBlendSpace2D>(p_blend_space); } else { blend_space.unref(); } @@ -32,7 +32,7 @@ void AnimationNodeBlendSpaceEditor::edit(AnimationNodeBlendSpace *p_blend_space) } } -void AnimationNodeBlendSpaceEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { +void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) { @@ -54,7 +54,7 @@ void AnimationNodeBlendSpaceEditor::_blend_space_gui_input(const Ref<InputEvent> ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); menu->add_submenu_item(TTR("Add Animation"), "animations"); - AnimationGraphPlayer *gp = blend_space->get_graph_player(); + AnimationTree *gp = blend_space->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())); @@ -203,7 +203,7 @@ void AnimationNodeBlendSpaceEditor::_blend_space_gui_input(const Ref<InputEvent> 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); + blend_space->set_blend_position(blend_pos); blend_space_draw->update(); } @@ -237,12 +237,12 @@ void AnimationNodeBlendSpaceEditor::_blend_space_gui_input(const Ref<InputEvent> 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); + blend_space->set_blend_position(blend_pos); blend_space_draw->update(); } } -void AnimationNodeBlendSpaceEditor::_add_menu_type(int p_index) { +void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { String type = menu->get_item_metadata(p_index); @@ -265,7 +265,7 @@ void AnimationNodeBlendSpaceEditor::_add_menu_type(int p_index) { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_add_animation_type(int p_index) { +void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) { Ref<AnimationNodeAnimation> anim; anim.instance(); @@ -284,7 +284,7 @@ void AnimationNodeBlendSpaceEditor::_add_animation_type(int p_index) { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_update_tool_erase() { +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); @@ -299,7 +299,7 @@ void AnimationNodeBlendSpaceEditor::_update_tool_erase() { } } -void AnimationNodeBlendSpaceEditor::_tool_switch(int p_tool) { +void AnimationNodeBlendSpace2DEditor::_tool_switch(int p_tool) { making_triangle.clear(); if (p_tool == 2) { @@ -325,7 +325,7 @@ void AnimationNodeBlendSpaceEditor::_tool_switch(int p_tool) { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_blend_space_draw() { +void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { Color linecolor = get_color("font_color", "Label"); Color linecolor_soft = linecolor; @@ -352,7 +352,7 @@ void AnimationNodeBlendSpaceEditor::_blend_space_draw() { } if (blend_space->get_min_space().x < 0) { - int x = (blend_space->get_max_space().x / (blend_space->get_max_space().x - blend_space->get_min_space().x)) * s.width; + int x = (-blend_space->get_min_space().x / (blend_space->get_max_space().x - blend_space->get_min_space().x)) * s.width; blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor); blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height() + font->get_ascent()), "0", linecolor); blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft); @@ -490,13 +490,13 @@ void AnimationNodeBlendSpaceEditor::_blend_space_draw() { color.a *= 0.5; } - Vector2 point = blend_space->get_blend_pos(); + Vector2 point = blend_space->get_blend_position(); 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_pos()); + Vector2 closest = blend_space->get_closest_point(blend_space->get_blend_position()); 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; @@ -515,12 +515,12 @@ void AnimationNodeBlendSpaceEditor::_blend_space_draw() { } } -void AnimationNodeBlendSpaceEditor::_snap_toggled() { +void AnimationNodeBlendSpace2DEditor::_snap_toggled() { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_update_space() { +void AnimationNodeBlendSpace2DEditor::_update_space() { if (updating) return; @@ -558,12 +558,12 @@ void AnimationNodeBlendSpaceEditor::_update_space() { updating = false; } -void AnimationNodeBlendSpaceEditor::_config_changed(double) { +void AnimationNodeBlendSpace2DEditor::_config_changed(double) { if (updating) return; updating = true; - undo_redo->create_action("Change BlendSpace Limits"); + undo_redo->create_action("Change BlendSpace2D Limits"); undo_redo->add_do_method(blend_space.ptr(), "set_max_space", Vector2(max_x_value->get_value(), max_y_value->get_value())); undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space()); undo_redo->add_do_method(blend_space.ptr(), "set_min_space", Vector2(min_x_value->get_value(), min_y_value->get_value())); @@ -578,12 +578,12 @@ void AnimationNodeBlendSpaceEditor::_config_changed(double) { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_labels_changed(String) { +void AnimationNodeBlendSpace2DEditor::_labels_changed(String) { if (updating) return; updating = true; - undo_redo->create_action("Change BlendSpace Labels", UndoRedo::MERGE_ENDS); + undo_redo->create_action("Change BlendSpace2D Labels", UndoRedo::MERGE_ENDS); undo_redo->add_do_method(blend_space.ptr(), "set_x_label", label_x->get_text()); undo_redo->add_undo_method(blend_space.ptr(), "set_x_label", blend_space->get_x_label()); undo_redo->add_do_method(blend_space.ptr(), "set_y_label", label_y->get_text()); @@ -594,12 +594,12 @@ void AnimationNodeBlendSpaceEditor::_labels_changed(String) { updating = false; } -void AnimationNodeBlendSpaceEditor::_erase_selected() { +void AnimationNodeBlendSpace2DEditor::_erase_selected() { if (selected_point != -1) { updating = true; - undo_redo->create_action("Remove BlendSpace Point"); + undo_redo->create_action("Remove BlendSpace2D Point"); undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point); undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", blend_space->get_blend_point_node(selected_point), blend_space->get_blend_point_position(selected_point), selected_point); @@ -622,7 +622,7 @@ void AnimationNodeBlendSpaceEditor::_erase_selected() { } else if (selected_triangle != -1) { updating = true; - undo_redo->create_action("Remove BlendSpace Triangle"); + undo_redo->create_action("Remove BlendSpace2D Triangle"); undo_redo->add_do_method(blend_space.ptr(), "remove_triangle", selected_triangle); undo_redo->add_undo_method(blend_space.ptr(), "add_triangle", blend_space->get_triangle_point(selected_triangle, 0), blend_space->get_triangle_point(selected_triangle, 1), blend_space->get_triangle_point(selected_triangle, 2), selected_triangle); @@ -635,7 +635,7 @@ void AnimationNodeBlendSpaceEditor::_erase_selected() { } } -void AnimationNodeBlendSpaceEditor::_update_edited_point_pos() { +void AnimationNodeBlendSpace2DEditor::_update_edited_point_pos() { if (updating) return; @@ -655,7 +655,7 @@ void AnimationNodeBlendSpaceEditor::_update_edited_point_pos() { } } -void AnimationNodeBlendSpaceEditor::_edit_point_pos(double) { +void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) { if (updating) return; updating = true; @@ -672,7 +672,7 @@ void AnimationNodeBlendSpaceEditor::_edit_point_pos(double) { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_notification(int p_what) { +void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); @@ -693,12 +693,12 @@ void AnimationNodeBlendSpaceEditor::_notification(int p_what) { String error; - if (!blend_space->get_graph_player()) { - error = TTR("BlendSpace does not belong to an AnimationGraphPlayer node."); - } else if (!blend_space->get_graph_player()->is_active()) { - error = TTR("AnimationGraphPlayer is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (blend_space->get_graph_player()->is_state_invalid()) { - error = blend_space->get_graph_player()->get_invalid_state_reason(); + if (!blend_space->get_tree()) { + error = TTR("BlendSpace2D does not belong to an AnimationTree node."); + } else if (!blend_space->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 (blend_space->get_triangle_count() == 0) { error = TTR("No triangles exist, so no blending can take place."); } @@ -714,7 +714,7 @@ void AnimationNodeBlendSpaceEditor::_notification(int p_what) { } } -void AnimationNodeBlendSpaceEditor::_open_editor() { +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); @@ -723,16 +723,16 @@ void AnimationNodeBlendSpaceEditor::_open_editor() { } } -void AnimationNodeBlendSpaceEditor::_goto_parent() { +void AnimationNodeBlendSpace2DEditor::_goto_parent() { EditorNode::get_singleton()->edit_item(blend_space->get_parent().ptr()); } -void AnimationNodeBlendSpaceEditor::_removed_from_graph() { +void AnimationNodeBlendSpace2DEditor::_removed_from_graph() { EditorNode::get_singleton()->edit_item(NULL); } -void AnimationNodeBlendSpaceEditor::_auto_triangles_toggled() { +void AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled() { undo_redo->create_action("Toggle Auto Triangles"); undo_redo->add_do_method(blend_space.ptr(), "set_auto_triangles", auto_triangles->is_pressed()); @@ -742,35 +742,35 @@ void AnimationNodeBlendSpaceEditor::_auto_triangles_toggled() { undo_redo->commit_action(); } -void AnimationNodeBlendSpaceEditor::_bind_methods() { +void AnimationNodeBlendSpace2DEditor::_bind_methods() { - ClassDB::bind_method("_blend_space_gui_input", &AnimationNodeBlendSpaceEditor::_blend_space_gui_input); - ClassDB::bind_method("_blend_space_draw", &AnimationNodeBlendSpaceEditor::_blend_space_draw); - ClassDB::bind_method("_config_changed", &AnimationNodeBlendSpaceEditor::_config_changed); - ClassDB::bind_method("_labels_changed", &AnimationNodeBlendSpaceEditor::_labels_changed); - ClassDB::bind_method("_update_space", &AnimationNodeBlendSpaceEditor::_update_space); - ClassDB::bind_method("_snap_toggled", &AnimationNodeBlendSpaceEditor::_snap_toggled); - ClassDB::bind_method("_tool_switch", &AnimationNodeBlendSpaceEditor::_tool_switch); - ClassDB::bind_method("_erase_selected", &AnimationNodeBlendSpaceEditor::_erase_selected); - ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpaceEditor::_update_tool_erase); - ClassDB::bind_method("_edit_point_pos", &AnimationNodeBlendSpaceEditor::_edit_point_pos); + ClassDB::bind_method("_blend_space_gui_input", &AnimationNodeBlendSpace2DEditor::_blend_space_gui_input); + ClassDB::bind_method("_blend_space_draw", &AnimationNodeBlendSpace2DEditor::_blend_space_draw); + ClassDB::bind_method("_config_changed", &AnimationNodeBlendSpace2DEditor::_config_changed); + ClassDB::bind_method("_labels_changed", &AnimationNodeBlendSpace2DEditor::_labels_changed); + ClassDB::bind_method("_update_space", &AnimationNodeBlendSpace2DEditor::_update_space); + ClassDB::bind_method("_snap_toggled", &AnimationNodeBlendSpace2DEditor::_snap_toggled); + ClassDB::bind_method("_tool_switch", &AnimationNodeBlendSpace2DEditor::_tool_switch); + ClassDB::bind_method("_erase_selected", &AnimationNodeBlendSpace2DEditor::_erase_selected); + ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace2DEditor::_update_tool_erase); + ClassDB::bind_method("_edit_point_pos", &AnimationNodeBlendSpace2DEditor::_edit_point_pos); - ClassDB::bind_method("_add_menu_type", &AnimationNodeBlendSpaceEditor::_add_menu_type); - ClassDB::bind_method("_add_animation_type", &AnimationNodeBlendSpaceEditor::_add_animation_type); + ClassDB::bind_method("_add_menu_type", &AnimationNodeBlendSpace2DEditor::_add_menu_type); + ClassDB::bind_method("_add_animation_type", &AnimationNodeBlendSpace2DEditor::_add_animation_type); - ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpaceEditor::_update_edited_point_pos); + ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace2DEditor::_update_edited_point_pos); - ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpaceEditor::_open_editor); - ClassDB::bind_method("_goto_parent", &AnimationNodeBlendSpaceEditor::_goto_parent); + ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace2DEditor::_open_editor); + ClassDB::bind_method("_goto_parent", &AnimationNodeBlendSpace2DEditor::_goto_parent); - ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpaceEditor::_removed_from_graph); + ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace2DEditor::_removed_from_graph); - ClassDB::bind_method("_auto_triangles_toggled", &AnimationNodeBlendSpaceEditor::_auto_triangles_toggled); + ClassDB::bind_method("_auto_triangles_toggled", &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled); } -AnimationNodeBlendSpaceEditor *AnimationNodeBlendSpaceEditor::singleton = NULL; +AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = NULL; -AnimationNodeBlendSpaceEditor::AnimationNodeBlendSpaceEditor() { +AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { singleton = this; updating = false; @@ -982,17 +982,17 @@ AnimationNodeBlendSpaceEditor::AnimationNodeBlendSpaceEditor() { dragging_selected_attempt = false; } -void AnimationNodeBlendSpaceEditorPlugin::edit(Object *p_object) { +void AnimationNodeBlendSpace2DEditorPlugin::edit(Object *p_object) { - anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendSpace>(p_object)); + anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendSpace2D>(p_object)); } -bool AnimationNodeBlendSpaceEditorPlugin::handles(Object *p_object) const { +bool AnimationNodeBlendSpace2DEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("AnimationNodeBlendSpace"); + return p_object->is_class("AnimationNodeBlendSpace2D"); } -void AnimationNodeBlendSpaceEditorPlugin::make_visible(bool p_visible) { +void AnimationNodeBlendSpace2DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { //editor->hide_animation_player_editors(); @@ -1009,15 +1009,15 @@ void AnimationNodeBlendSpaceEditorPlugin::make_visible(bool p_visible) { } } -AnimationNodeBlendSpaceEditorPlugin::AnimationNodeBlendSpaceEditorPlugin(EditorNode *p_node) { +AnimationNodeBlendSpace2DEditorPlugin::AnimationNodeBlendSpace2DEditorPlugin(EditorNode *p_node) { editor = p_node; - anim_tree_editor = memnew(AnimationNodeBlendSpaceEditor); + anim_tree_editor = memnew(AnimationNodeBlendSpace2DEditor); anim_tree_editor->set_custom_minimum_size(Size2(0, 300)); - button = editor->add_bottom_panel_item(TTR("BlendSpace"), anim_tree_editor); + button = editor->add_bottom_panel_item(TTR("BlendSpace2D"), anim_tree_editor); button->hide(); } -AnimationNodeBlendSpaceEditorPlugin::~AnimationNodeBlendSpaceEditorPlugin() { +AnimationNodeBlendSpace2DEditorPlugin::~AnimationNodeBlendSpace2DEditorPlugin() { } diff --git a/editor/plugins/animation_blend_space_editor.h b/editor/plugins/animation_blend_space_2d_editor.h index 66d2ec6cae..a0e497804e 100644 --- a/editor/plugins/animation_blend_space_editor.h +++ b/editor/plugins/animation_blend_space_2d_editor.h @@ -1,10 +1,10 @@ -#ifndef ANIMATION_BLEND_SPACE_EDITOR_H -#define ANIMATION_BLEND_SPACE_EDITOR_H +#ifndef ANIMATION_BLEND_SPACE_2D_EDITOR_H +#define ANIMATION_BLEND_SPACE_2D_EDITOR_H #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "editor/property_editor.h" -#include "scene/animation/animation_blend_space.h" +#include "scene/animation/animation_blend_space_2d.h" #include "scene/gui/button.h" #include "scene/gui/graph_edit.h" #include "scene/gui/popup.h" @@ -13,11 +13,11 @@ @author Juan Linietsky <reduzio@gmail.com> */ -class AnimationNodeBlendSpaceEditor : public VBoxContainer { +class AnimationNodeBlendSpace2DEditor : public VBoxContainer { - GDCLASS(AnimationNodeBlendSpaceEditor, VBoxContainer); + GDCLASS(AnimationNodeBlendSpace2DEditor, VBoxContainer); - Ref<AnimationNodeBlendSpace> blend_space; + Ref<AnimationNodeBlendSpace2D> blend_space; HBoxContainer *goto_parent_hb; ToolButton *goto_parent; @@ -59,7 +59,7 @@ class AnimationNodeBlendSpaceEditor : public VBoxContainer { UndoRedo *undo_redo; - static AnimationNodeBlendSpaceEditor *singleton; + static AnimationNodeBlendSpace2DEditor *singleton; void _blend_space_gui_input(const Ref<InputEvent> &p_event); void _blend_space_draw(); @@ -104,27 +104,27 @@ protected: static void _bind_methods(); public: - static AnimationNodeBlendSpaceEditor *get_singleton() { return singleton; } - void edit(AnimationNodeBlendSpace *p_blend_space); - AnimationNodeBlendSpaceEditor(); + static AnimationNodeBlendSpace2DEditor *get_singleton() { return singleton; } + void edit(AnimationNodeBlendSpace2D *p_blend_space); + AnimationNodeBlendSpace2DEditor(); }; -class AnimationNodeBlendSpaceEditorPlugin : public EditorPlugin { +class AnimationNodeBlendSpace2DEditorPlugin : public EditorPlugin { - GDCLASS(AnimationNodeBlendSpaceEditorPlugin, EditorPlugin); + GDCLASS(AnimationNodeBlendSpace2DEditorPlugin, EditorPlugin); - AnimationNodeBlendSpaceEditor *anim_tree_editor; + AnimationNodeBlendSpace2DEditor *anim_tree_editor; EditorNode *editor; Button *button; public: - virtual String get_name() const { return "BlendSpace"; } + 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); - AnimationNodeBlendSpaceEditorPlugin(EditorNode *p_node); - ~AnimationNodeBlendSpaceEditorPlugin(); + AnimationNodeBlendSpace2DEditorPlugin(EditorNode *p_node); + ~AnimationNodeBlendSpace2DEditorPlugin(); }; -#endif // ANIMATION_BLEND_SPACE_EDITOR_H +#endif // ANIMATION_BLEND_SPACE_2D_EDITOR_H diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 0875c93a16..3efb2736b5 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -169,7 +169,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { ProgressBar *pb = memnew(ProgressBar); - AnimationGraphPlayer *player = anim->get_graph_player(); + AnimationTree *player = anim->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) { @@ -417,14 +417,14 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano if (updating || _filter_edit != anode) return false; - NodePath player_path = anode->get_graph_player()->get_animation_player(); + NodePath player_path = anode->get_tree()->get_animation_player(); - if (!anode->get_graph_player()->has_node(player_path)) { + if (!anode->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_graph_player()->get_node(player_path)); + AnimationPlayer *player = Object::cast_to<AnimationPlayer>(anode->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; @@ -603,12 +603,12 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { String error; - if (!blend_tree->get_graph_player()) { - error = TTR("BlendTree does not belong to an AnimationGraphPlayer node."); - } else if (!blend_tree->get_graph_player()->is_active()) { - error = TTR("AnimationGraphPlayer is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (blend_tree->get_graph_player()->is_state_invalid()) { - error = blend_tree->get_graph_player()->get_invalid_state_reason(); + if (!blend_tree->get_tree()) { + error = TTR("BlendTree does not belong to an AnimationTree node."); + } else if (!blend_tree->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(); } if (error != error_label->get_text()) { @@ -624,13 +624,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_graph_player() && !blend_tree->get_graph_player()->is_state_invalid()) { + if (blend_tree->get_tree() && !blend_tree->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); } - AnimationGraphPlayer *graph_player = blend_tree->get_graph_player(); + AnimationTree *graph_player = blend_tree->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())); @@ -767,14 +767,17 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { add_options.push_back(AddOption("Animation", "AnimationNodeAnimation")); add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot")); - add_options.push_back(AddOption("Add", "AnimationNodeAdd")); + add_options.push_back(AddOption("Add2", "AnimationNodeAdd2")); + add_options.push_back(AddOption("Add3", "AnimationNodeAdd3")); add_options.push_back(AddOption("Blend2", "AnimationNodeBlend2")); add_options.push_back(AddOption("Blend3", "AnimationNodeBlend3")); add_options.push_back(AddOption("Seek", "AnimationNodeTimeSeek")); add_options.push_back(AddOption("TimeScale", "AnimationNodeTimeScale")); add_options.push_back(AddOption("Transition", "AnimationNodeTransition")); add_options.push_back(AddOption("BlendTree", "AnimationNodeBlendTree")); - add_options.push_back(AddOption("BlendSpace", "AnimationNodeBlendSpace")); + add_options.push_back(AddOption("BlendSpace1D", "AnimationNodeBlendSpace1D")); + add_options.push_back(AddOption("BlendSpace2D", "AnimationNodeBlendSpace2D")); + add_options.push_back(AddOption("StateMachine", "AnimationNodeStateMachine")); _update_options_menu(); error_panel = memnew(PanelContainer); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp new file mode 100644 index 0000000000..04bd5f0cec --- /dev/null +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -0,0 +1,1313 @@ +#include "animation_state_machine_editor.h" + +#include "core/io/resource_loader.h" +#include "core/project_settings.h" +#include "math/delaunay.h" +#include "os/input.h" +#include "os/keyboard.h" +#include "scene/animation/animation_blend_tree.h" +#include "scene/animation/animation_player.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/panel.h" +#include "scene/main/viewport.h" + +void AnimationNodeStateMachineEditor::edit(AnimationNodeStateMachine *p_state_machine) { + + 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(); + selected_node = StringName(); + _update_mode(); + _update_graph(); + } +} + +void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) { + + 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()) { + _erase_selected(); + accept_event(); + } + } + + Ref<InputEventMouseButton> mb = p_event; + + //Add new node + if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == BUTTON_LEFT))) { + menu->clear(); + animations_menu->clear(); + animations_to_add.clear(); + List<StringName> classes; + classes.sort_custom<StringName::AlphCompare>(); + + ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); + menu->add_submenu_item(TTR("Add Animation"), "animations"); + + AnimationTree *gp = state_machine->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())); + if (ap) { + List<StringName> names; + ap->get_animation_list(&names); + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get()); + animations_to_add.push_back(E->get()); + } + } + } + + for (List<StringName>::Element *E = classes.front(); E; E = E->next()) { + + String name = String(E->get()).replace_first("AnimationNode", ""); + if (name == "Animation") + continue; // nope + int idx = menu->get_item_count(); + menu->add_item(vformat("Add %s", name)); + menu->set_item_metadata(idx, E->get()); + } + + menu->set_global_position(state_machine_draw->get_global_transform().xform(mb->get_position())); + menu->popup(); + add_node_pos = mb->get_position() / EDSCALE + state_machine->get_graph_offset(); + } + + // select node or push a field inside + if (mb.is_valid() && !mb->get_shift() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + + selected_transition_from = StringName(); + selected_transition_to = StringName(); + selected_node = StringName(); + + 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()) { + //start + state_machine->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); + } + } + state_machine_draw->update(); + return; + } + + if (node_rects[i].name.has_point(mb->get_position())) { //edit name + + Ref<StyleBox> line_sb = get_stylebox("normal", "LineEdit"); + + Rect2 edit_rect = node_rects[i].name; + edit_rect.position -= line_sb->get_offset(); + edit_rect.size += line_sb->get_minimum_size(); + + name_edit->set_global_position(state_machine_draw->get_global_transform().xform(edit_rect.position)); + name_edit->set_size(edit_rect.size); + name_edit->set_text(node_rects[i].node_name); + name_edit->show_modal(); + name_edit->grab_focus(); + name_edit->select_all(); + + prev_name = node_rects[i].node_name; + return; + } + + if (node_rects[i].edit.has_point(mb->get_position())) { //edit name + call_deferred("_open_editor", node_rects[i].node_name); + return; + } + + if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected + selected_node = node_rects[i].node_name; + + Ref<AnimationNode> anode = state_machine->get_node(selected_node); + EditorNode::get_singleton()->push_item(anode.ptr(), "", true); + state_machine_draw->update(); + dragging_selected_attempt = true; + dragging_selected = false; + drag_from = mb->get_position(); + snap_x = StringName(); + snap_y = StringName(); + _update_mode(); + return; + } + } + + //test the lines now + int closest = -1; + float closest_d = 1e20; + for (int i = 0; i < transition_lines.size(); i++) { + + Vector2 s[2] = { + transition_lines[i].from, + transition_lines[i].to + }; + Vector2 cpoint = Geometry::get_closest_point_to_segment_2d(mb->get_position(), s); + float d = cpoint.distance_to(mb->get_position()); + if (d > transition_lines[i].width) { + continue; + } + + if (d < closest_d) { + closest = i; + closest_d = d; + } + } + + if (closest >= 0) { + selected_transition_from = transition_lines[closest].from_node; + selected_transition_to = transition_lines[closest].to_node; + + Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(closest); + EditorNode::get_singleton()->push_item(tr.ptr(), "", true); + } + + state_machine_draw->update(); + _update_mode(); + } + + //end moving node + if (mb.is_valid() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) { + + if (dragging_selected) { + + 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(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + } + snap_x = StringName(); + snap_y = StringName(); + + dragging_selected_attempt = false; + dragging_selected = false; + state_machine_draw->update(); + } + + //connect nodes + if (mb.is_valid() && ((tool_select->is_pressed() && mb->get_shift()) || tool_connect->is_pressed()) && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { + + for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order + if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected + connecting = true; + connecting_from = node_rects[i].node_name; + connecting_to = mb->get_position(); + connecting_to_node = StringName(); + return; + } + } + } + + //end connecting nodes + if (mb.is_valid() && connecting && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) { + + if (connecting_to_node != StringName()) { + + if (state_machine->has_transition(connecting_from, connecting_to_node)) { + EditorNode::get_singleton()->show_warning("Transition exists!"); + + } else { + + Ref<AnimationNodeStateMachineTransition> tr; + tr.instance(); + tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected())); + + updating = true; + undo_redo->create_action("Add Transition"); + undo_redo->add_do_method(state_machine.ptr(), "add_transition", connecting_from, connecting_to_node, tr); + undo_redo->add_undo_method(state_machine.ptr(), "remove_transition", connecting_from, connecting_to_node); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + + selected_transition_from = connecting_from; + selected_transition_to = connecting_to_node; + + EditorNode::get_singleton()->push_item(tr.ptr(), "", true); + _update_mode(); + } + } + connecting_to_node = StringName(); + connecting = false; + state_machine_draw->update(); + } + + Ref<InputEventMouseMotion> mm = p_event; + + //pan window + if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) { + + h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x); + v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y); + } + + //move mouse while connecting + if (mm.is_valid() && connecting) { + + connecting_to = mm->get_position(); + connecting_to_node = StringName(); + state_machine_draw->update(); + + for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order + if (node_rects[i].node_name != connecting_from && node_rects[i].node.has_point(connecting_to)) { //select node since nothing else was selected + connecting_to_node = node_rects[i].node_name; + return; + } + } + } + + //move mouse while moving a node + if (mm.is_valid() && dragging_selected_attempt) { + + dragging_selected = true; + drag_ofs = mm->get_position() - drag_from; + snap_x = StringName(); + snap_y = StringName(); + { + //snap + Vector2 cpos = state_machine->get_node(selected_node)->get_position() + drag_ofs / EDSCALE; + List<StringName> nodes; + state_machine->get_node_list(&nodes); + + float best_d_x = 1e20; + float best_d_y = 1e20; + + 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(); + + float d_x = ABS(npos.x - cpos.x); + if (d_x < MIN(5, best_d_x)) { + drag_ofs.x -= cpos.x - npos.x; + best_d_x = d_x; + snap_x = E->get(); + } + + float d_y = ABS(npos.y - cpos.y); + if (d_y < MIN(5, best_d_y)) { + drag_ofs.y -= cpos.y - npos.y; + best_d_y = d_y; + snap_y = E->get(); + } + } + } + + state_machine_draw->update(); + } + + //put ibeam (text cursor) over names to make it clearer that they are editable + if (mm.is_valid()) { + + state_machine_draw->grab_focus(); + + bool over_text_now = false; + String new_over_node = StringName(); + int new_over_node_what = -1; + if (tool_select->is_pressed()) { + + for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order + + if (node_rects[i].name.has_point(mm->get_position())) { + over_text_now = true; + break; + } + + if (node_rects[i].node.has_point(mm->get_position())) { + new_over_node = node_rects[i].node_name; + if (node_rects[i].play.has_point(mm->get_position())) { + new_over_node_what = 0; + } + if (node_rects[i].edit.has_point(mm->get_position())) { + new_over_node_what = 1; + } + } + } + } + + if (new_over_node != over_node || new_over_node_what != over_node_what) { + over_node = new_over_node; + over_node_what = new_over_node_what; + state_machine_draw->update(); + } + + if (over_text != over_text_now) { + + if (over_text_now) { + state_machine_draw->set_default_cursor_shape(CURSOR_IBEAM); + } else { + state_machine_draw->set_default_cursor_shape(CURSOR_ARROW); + } + + over_text = over_text_now; + } + } +} + +void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { + + 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); + + Ref<AnimationNode> node(an); + node->set_position(add_node_pos); + + String base_name = type.replace_first("AnimationNode", ""); + int base = 1; + String name = base_name; + while (state_machine->has_node(name)) { + base++; + name = base_name + " " + itos(base); + } + + updating = true; + undo_redo->create_action("Add Node"); + undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node); + 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"); + undo_redo->commit_action(); + updating = false; + + state_machine_draw->update(); +} + +void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) { + + Ref<AnimationNodeAnimation> anim; + anim.instance(); + + anim->set_animation(animations_to_add[p_index]); + + String base_name = animations_to_add[p_index]; + int base = 1; + String name = base_name; + while (state_machine->has_node(name)) { + base++; + 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_undo_method(state_machine.ptr(), "remove_node", name); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + + state_machine_draw->update(); +} + +void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance) { + + Color linecolor = get_color("font_color", "Label"); + Color icon_color(1, 1, 1); + Color accent = get_color("accent_color", "Editor"); + + if (!p_enabled) { + linecolor.a *= 0.2; + icon_color.a *= 0.2; + accent.a *= 0.6; + } + + Ref<Texture> icons[6] = { + get_icon("TransitionImmediateBig", "EditorIcons"), + get_icon("TransitionSyncBig", "EditorIcons"), + get_icon("TransitionEndBig", "EditorIcons"), + get_icon("TransitionImmediateAutoBig", "EditorIcons"), + get_icon("TransitionSyncAutoBig", "EditorIcons"), + get_icon("TransitionEndAutoBig", "EditorIcons") + }; + + if (p_selected) { + state_machine_draw->draw_line(p_from, p_to, accent, 6, true); + } + + if (p_travel) { + linecolor = accent; + linecolor.set_hsv(1.0, linecolor.get_s(), linecolor.get_v()); + } + state_machine_draw->draw_line(p_from, p_to, linecolor, 2, true); + + Ref<Texture> icon = icons[p_mode + (p_auto_advance ? 3 : 0)]; + + Transform2D xf; + xf.elements[0] = (p_to - p_from).normalized(); + xf.elements[1] = xf.elements[0].tangent(); + xf.elements[2] = (p_from + p_to) * 0.5 - xf.elements[1] * icon->get_height() * 0.5 - xf.elements[0] * icon->get_height() * 0.5; + + state_machine_draw->draw_set_transform_matrix(xf); + state_machine_draw->draw_texture(icon, Vector2(), icon_color); + state_machine_draw->draw_set_transform_matrix(Transform2D()); +} + +void AnimationNodeStateMachineEditor::_clip_src_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect) { + + if (r_to == r_from) + return; + + //this could be optimized... + Vector2 n = (r_to - r_from).normalized(); + while (p_rect.has_point(r_from)) { + r_from += n; + } +} + +void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect) { + + if (r_to == r_from) + return; + + //this could be optimized... + Vector2 n = (r_to - r_from).normalized(); + while (p_rect.has_point(r_to)) { + r_to -= n; + } +} + +void AnimationNodeStateMachineEditor::_state_machine_draw() { + + Ref<StyleBox> style = get_stylebox("frame", "GraphNode"); + Ref<StyleBox> style_selected = get_stylebox("selectedframe", "GraphNode"); + + Ref<Font> font = get_font("title_font", "GraphNode"); + Color font_color = get_color("title_color", "GraphNode"); + Ref<Texture> play = get_icon("Play", "EditorIcons"); + Ref<Texture> auto_play = get_icon("AutoPlay", "EditorIcons"); + Ref<Texture> edit = get_icon("Edit", "EditorIcons"); + Color accent = get_color("accent_color", "Editor"); + Color linecolor = get_color("font_color", "Label"); + 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(); + + if (state_machine_draw->has_focus()) { + state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), accent, false); + } + int sep = 3 * EDSCALE; + + List<StringName> nodes; + state_machine->get_node_list(&nodes); + + node_rects.clear(); + Rect2 scroll_range(Point2(), state_machine_draw->get_size()); + + //snap lines + if (dragging_selected) { + + Vector2 from = (state_machine->get_node(selected_node)->get_position() * 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; + 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; + state_machine_draw->draw_line(from, to, linecolor, 2); + } + } + + //pre pass nodes so we know the rectangles + for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { + + Ref<AnimationNode> anode = state_machine->get_node(E->get()); + String name = E->get(); + bool needs_editor = EditorNode::get_singleton()->item_has_editor(anode.ptr()); + Ref<StyleBox> sb = E->get() == selected_node ? style_selected : style; + + Size2 s = sb->get_minimum_size(); + int strsize = font->get_string_size(name).width; + s.width += strsize; + s.height += MAX(font->get_height(), play->get_height()); + s.width += sep + play->get_width(); + if (needs_editor) { + s.width += sep + edit->get_width(); + } + + Vector2 offset; + offset += anode->get_position() * EDSCALE; + if (selected_node == E->get() && dragging_selected) { + offset += drag_ofs; + } + offset -= s / 2; + offset = offset.floor(); + + //prepre rect + + NodeRect nr; + nr.node = Rect2(offset, s); + nr.node_name = E->get(); + + scroll_range = scroll_range.merge(nr.node); //merge with range + + //now scroll it to draw + nr.node.position -= state_machine->get_graph_offset() * EDSCALE; + + node_rects.push_back(nr); + } + + transition_lines.clear(); + + //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 to; + if (connecting_to_node != StringName()) { + to = (state_machine->get_node(connecting_to_node)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; + } else { + to = connecting_to; + } + + for (int i = 0; i < node_rects.size(); i++) { + if (node_rects[i].node_name == connecting_from) { + _clip_src_line_to_rect(from, to, node_rects[i].node); + } + if (node_rects[i].node_name == connecting_to_node) { + _clip_dst_line_to_rect(from, to, node_rects[i].node); + } + } + + _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()), true, false, false, false); + } + + Ref<Texture> tr_reference_icon = get_icon("TransitionImmediateBig", "EditorIcons"); + float tr_bidi_offset = int(tr_reference_icon->get_height() * 0.8); + + //draw transition lines + for (int i = 0; i < state_machine->get_transition_count(); i++) { + + 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.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; + + Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i); + tl.disabled = tr->is_disabled(); + tl.auto_advance = tr->has_auto_advance(); + tl.mode = tr->get_switch_mode(); + tl.width = tr_bidi_offset; + + if (state_machine->has_transition(tl.to_node, tl.from_node)) { //offset if same exists + Vector2 offset = -(tl.from - tl.to).normalized().tangent() * tr_bidi_offset; + tl.from += offset; + tl.to += offset; + } + + for (int i = 0; i < node_rects.size(); i++) { + if (node_rects[i].node_name == tl.from_node) { + _clip_src_line_to_rect(tl.from, tl.to, node_rects[i].node); + } + if (node_rects[i].node_name == tl.to_node) { + _clip_dst_line_to_rect(tl.from, tl.to, node_rects[i].node); + } + } + + bool selected = selected_transition_from == tl.from_node && selected_transition_to == tl.to_node; + + bool travel = false; + + if (blend_from == tl.from_node && current == tl.to_node) { + travel = true; + } + + if (travel_path.size()) { + + if (current == tl.from_node && travel_path[0] == tl.to_node) { + travel = true; + } else { + for (int j = 0; j < travel_path.size() - 1; j++) { + if (travel_path[j] == tl.from_node && travel_path[j + 1] == tl.to_node) { + travel = true; + break; + } + } + } + } + _connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, selected, travel, tl.auto_advance); + + transition_lines.push_back(tl); + } + + //draw actual nodes + for (int i = 0; i < node_rects.size(); i++) { + + 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()); + Ref<StyleBox> sb = name == selected_node ? style_selected : style; + int strsize = font->get_string_size(name).width; + + NodeRect &nr = node_rects[i]; + + Vector2 offset = nr.node.position; + int h = nr.node.size.height; + + //prepre rect + + //now scroll it to draw + state_machine_draw->draw_style_box(sb, nr.node); + + if (playing && (blend_from == name || current == name || travel_path.find(name) != -1)) { + state_machine_draw->draw_style_box(playing_overlay, nr.node); + } + + bool onstart = state_machine->get_start_node() == name; + if (onstart) { + state_machine_draw->draw_string(font, offset + Vector2(0, -font->get_height() - 3 * EDSCALE + font->get_ascent()), TTR("Start"), font_color); + } + + if (state_machine->get_end_node() == name) { + + int endofs = nr.node.size.x - font->get_string_size(TTR("End")).x; + state_machine_draw->draw_string(font, offset + Vector2(endofs, -font->get_height() - 3 * EDSCALE + font->get_ascent()), TTR("End"), font_color); + } + + offset.x += sb->get_offset().x; + + nr.play.position = offset + Vector2(0, (h - play->get_height()) / 2).floor(); + nr.play.size = play->get_size(); + + Ref<Texture> play_tex = onstart ? auto_play : play; + + if (over_node == name && over_node_what == 0) { + state_machine_draw->draw_texture(play_tex, nr.play.position, accent); + } else { + state_machine_draw->draw_texture(play_tex, nr.play.position); + } + offset.x += sep + play->get_width(); + + nr.name.position = offset + Vector2(0, (h - font->get_height()) / 2).floor(); + nr.name.size = Vector2(strsize, font->get_height()); + + state_machine_draw->draw_string(font, nr.name.position + Vector2(0, font->get_ascent()), name, font_color); + offset.x += strsize + sep; + + if (needs_editor) { + nr.edit.position = offset + Vector2(0, (h - edit->get_height()) / 2).floor(); + nr.edit.size = edit->get_size(); + + if (over_node == name && over_node_what == 1) { + state_machine_draw->draw_texture(edit, nr.edit.position, accent); + } else { + state_machine_draw->draw_texture(edit, nr.edit.position); + } + offset.x += sep + edit->get_width(); + } + } + + scroll_range = scroll_range.grow(200 * EDSCALE); + + //adjust scrollbars + updating = true; + h_scroll->set_min(scroll_range.position.x); + h_scroll->set_max(scroll_range.position.x + scroll_range.size.x); + h_scroll->set_page(state_machine_draw->get_size().x); + h_scroll->set_value(state_machine->get_graph_offset().x); + + v_scroll->set_min(scroll_range.position.y); + v_scroll->set_max(scroll_range.position.y + scroll_range.size.y); + v_scroll->set_page(state_machine_draw->get_size().y); + v_scroll->set_value(state_machine->get_graph_offset().y); + updating = false; + + state_machine_play_pos->update(); +} + +void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { + + if (!state_machine->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()) { + idx = i; + break; + } + } + + if (idx == -1) + return; + + NodeRect &nr = node_rects[idx]; + + Vector2 from; + from.x = nr.play.position.x; + from.y = (nr.play.position.y + nr.play.size.y + nr.node.position.y + nr.node.size.y) * 0.5; + + Vector2 to; + if (nr.edit.size.x) { + to.x = nr.edit.position.x + nr.edit.size.x; + } else { + to.x = nr.name.position.x + nr.name.size.x; + } + to.y = from.y; + + float len = MAX(0.0001, state_machine->get_current_length()); + + float pos = CLAMP(state_machine->get_current_play_pos(), 0, len); + float c = pos / len; + Color fg = get_color("font_color", "Label"); + Color bg = fg; + bg.a *= 0.3; + + state_machine_play_pos->draw_line(from, to, bg, 2); + + to = from.linear_interpolate(to, c); + + state_machine_play_pos->draw_line(from, to, fg, 2); +} + +void AnimationNodeStateMachineEditor::_update_graph() { + + if (updating) + return; + + updating = true; + + if (state_machine->get_parent().is_valid()) { + goto_parent_hbox->show(); + } else { + goto_parent_hbox->hide(); + } + + state_machine_draw->update(); + + updating = false; +} + +void AnimationNodeStateMachineEditor::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + 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")); + tool_connect->set_icon(get_icon("ToolConnect", "EditorIcons")); + + transition_mode->clear(); + transition_mode->add_icon_item(get_icon("TransitionImmediate", "EditorIcons"), TTR("Immediate")); + transition_mode->add_icon_item(get_icon("TransitionSync", "EditorIcons"), TTR("Sync")); + transition_mode->add_icon_item(get_icon("TransitionEnd", "EditorIcons"), TTR("At End")); + + //force filter on those, so they deform better + get_icon("TransitionImmediateBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + get_icon("TransitionEndBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + get_icon("TransitionSyncBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + get_icon("TransitionImmediateAutoBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + get_icon("TransitionEndAutoBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + get_icon("TransitionSyncAutoBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + + tool_erase->set_icon(get_icon("Remove", "EditorIcons")); + tool_autoplay->set_icon(get_icon("AutoPlay", "EditorIcons")); + tool_end->set_icon(get_icon("AutoEnd", "EditorIcons")); + + play_mode->clear(); + play_mode->add_icon_item(get_icon("PlayTravel", "EditorIcons"), TTR("Travel")); + play_mode->add_icon_item(get_icon("Play", "EditorIcons"), TTR("Immediate")); + } + + if (p_what == NOTIFICATION_PROCESS) { + + String error; + + 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()) { + 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")) { + 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."); + } + } + + if (error != error_label->get_text()) { + error_label->set_text(error); + if (error != String()) { + error_panel->show(); + } else { + error_panel->hide(); + } + } + + for (int i = 0; i < transition_lines.size(); i++) { + int tidx = -1; + for (int j = 0; j < state_machine->get_transition_count(); j++) { + if (transition_lines[i].from_node == state_machine->get_transition_from(j) && transition_lines[i].to_node == state_machine->get_transition_to(j)) { + tidx = j; + break; + } + } + + if (tidx == -1) { //missing transition, should redraw + state_machine_draw->update(); + break; + } + + if (transition_lines[i].disabled != state_machine->get_transition(tidx)->is_disabled()) { + state_machine_draw->update(); + break; + } + + if (transition_lines[i].auto_advance != state_machine->get_transition(tidx)->has_auto_advance()) { + state_machine_draw->update(); + break; + } + + if (transition_lines[i].mode != state_machine->get_transition(tidx)->get_switch_mode()) { + state_machine_draw->update(); + break; + } + } + + bool same_travel_path = true; + Vector<StringName> tp = state_machine->get_travel_path(); + + { + + if (last_travel_path.size() != tp.size()) { + same_travel_path = false; + } else { + for (int i = 0; i < last_travel_path.size(); i++) { + if (last_travel_path[i] != tp[i]) { + same_travel_path = false; + break; + } + } + } + } + + //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()) { + + 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(); + state_machine_play_pos->update(); + } + + if (last_play_pos != state_machine->get_current_play_pos()) { + + last_play_pos = state_machine->get_current_play_pos(); + state_machine_play_pos->update(); + } + } + + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + over_node = StringName(); + } +} + +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()); +} + +void AnimationNodeStateMachineEditor::_removed_from_graph() { + EditorNode::get_singleton()->edit_item(NULL); +} + +void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) { + + String new_name = p_text; + + ERR_FAIL_COND(new_name == "" || new_name.find(".") != -1 || new_name.find("/") != -1) + + ERR_FAIL_COND(new_name == prev_name); + + String base_name = new_name; + int base = 1; + String name = base_name; + while (state_machine->has_node(name)) { + base++; + name = base_name + " " + itos(base); + } + + updating = true; + undo_redo->create_action("Node Renamed"); + undo_redo->add_do_method(state_machine.ptr(), "rename_node", prev_name, name); + undo_redo->add_undo_method(state_machine.ptr(), "rename_node", name, prev_name); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + + state_machine_draw->update(); + + name_edit->hide(); +} + +void AnimationNodeStateMachineEditor::_scroll_changed(double) { + if (updating) + return; + + state_machine->set_graph_offset(Vector2(h_scroll->get_value(), v_scroll->get_value())); + state_machine_draw->update(); +} + +void AnimationNodeStateMachineEditor::_erase_selected() { + + if (selected_node != StringName() && state_machine->has_node(selected_node)) { + updating = true; + undo_redo->create_action("Node Removed"); + undo_redo->add_do_method(state_machine.ptr(), "remove_node", selected_node); + undo_redo->add_undo_method(state_machine.ptr(), "add_node", selected_node, state_machine->get_node(selected_node)); + for (int i = 0; i < state_machine->get_transition_count(); i++) { + String from = state_machine->get_transition_from(i); + String to = state_machine->get_transition_to(i); + if (from == selected_node || to == selected_node) { + undo_redo->add_undo_method(state_machine.ptr(), "add_transition", from, to, state_machine->get_transition(i)); + } + } + if (String(state_machine->get_start_node()) == selected_node) { + undo_redo->add_undo_method(state_machine.ptr(), "set_start_node", selected_node); + } + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + selected_node = StringName(); + } + + if (selected_transition_to != StringName() && selected_transition_from != StringName() && state_machine->has_transition(selected_transition_from, selected_transition_to)) { + + Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(state_machine->find_transition(selected_transition_from, selected_transition_to)); + updating = true; + undo_redo->create_action("Transition Removed"); + undo_redo->add_do_method(state_machine.ptr(), "remove_transition", selected_transition_from, selected_transition_to); + undo_redo->add_undo_method(state_machine.ptr(), "add_transition", selected_transition_from, selected_transition_to, tr); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + selected_transition_from = StringName(); + selected_transition_to = StringName(); + } + + state_machine_draw->update(); +} + +void AnimationNodeStateMachineEditor::_autoplay_selected() { + + if (selected_node != StringName() && state_machine->has_node(selected_node)) { + + StringName new_start_node; + if (state_machine->get_start_node() == selected_node) { //toggle it + new_start_node = StringName(); + } else { + new_start_node = selected_node; + } + + updating = true; + undo_redo->create_action("Set Start Node (Autoplay)"); + undo_redo->add_do_method(state_machine.ptr(), "set_start_node", new_start_node); + undo_redo->add_undo_method(state_machine.ptr(), "set_start_node", state_machine->get_start_node()); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + state_machine_draw->update(); + } +} + +void AnimationNodeStateMachineEditor::_end_selected() { + + if (selected_node != StringName() && state_machine->has_node(selected_node)) { + + StringName new_end_node; + if (state_machine->get_end_node() == selected_node) { //toggle it + new_end_node = StringName(); + } else { + new_end_node = selected_node; + } + + updating = true; + undo_redo->create_action("Set Start Node (Autoplay)"); + undo_redo->add_do_method(state_machine.ptr(), "set_end_node", new_end_node); + undo_redo->add_undo_method(state_machine.ptr(), "set_end_node", state_machine->get_end_node()); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + state_machine_draw->update(); + } +} +void AnimationNodeStateMachineEditor::_update_mode() { + + if (tool_select->is_pressed()) { + tool_erase_hb->show(); + tool_erase->set_disabled(selected_node == StringName() && selected_transition_from == StringName() && selected_transition_to == StringName()); + tool_autoplay->set_disabled(selected_node == StringName()); + tool_end->set_disabled(selected_node == StringName()); + } else { + tool_erase_hb->hide(); + } +} + +void AnimationNodeStateMachineEditor::_bind_methods() { + + ClassDB::bind_method("_state_machine_gui_input", &AnimationNodeStateMachineEditor::_state_machine_gui_input); + ClassDB::bind_method("_state_machine_draw", &AnimationNodeStateMachineEditor::_state_machine_draw); + ClassDB::bind_method("_state_machine_pos_draw", &AnimationNodeStateMachineEditor::_state_machine_pos_draw); + ClassDB::bind_method("_update_graph", &AnimationNodeStateMachineEditor::_update_graph); + + ClassDB::bind_method("_add_menu_type", &AnimationNodeStateMachineEditor::_add_menu_type); + ClassDB::bind_method("_add_animation_type", &AnimationNodeStateMachineEditor::_add_animation_type); + + 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); + ClassDB::bind_method("_scroll_changed", &AnimationNodeStateMachineEditor::_scroll_changed); + + ClassDB::bind_method("_erase_selected", &AnimationNodeStateMachineEditor::_erase_selected); + ClassDB::bind_method("_autoplay_selected", &AnimationNodeStateMachineEditor::_autoplay_selected); + ClassDB::bind_method("_end_selected", &AnimationNodeStateMachineEditor::_end_selected); + ClassDB::bind_method("_update_mode", &AnimationNodeStateMachineEditor::_update_mode); +} + +AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = NULL; + +AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { + + singleton = this; + updating = false; + + 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(); + + tool_select = memnew(ToolButton); + top_hb->add_child(tool_select); + tool_select->set_toggle_mode(true); + tool_select->set_button_group(bg); + tool_select->set_pressed(true); + tool_select->set_tooltip(TTR("Select and move nodes.\nRMB to add new nodes.\nShift+LMB to create connections.")); + tool_select->connect("pressed", this, "_update_mode", varray(), CONNECT_DEFERRED); + + tool_create = memnew(ToolButton); + top_hb->add_child(tool_create); + tool_create->set_toggle_mode(true); + tool_create->set_button_group(bg); + tool_create->set_tooltip(TTR("Create new nodes.")); + tool_create->connect("pressed", this, "_update_mode", varray(), CONNECT_DEFERRED); + + tool_connect = memnew(ToolButton); + top_hb->add_child(tool_connect); + tool_connect->set_toggle_mode(true); + tool_connect->set_button_group(bg); + tool_connect->set_tooltip(TTR("Connect nodes.")); + tool_connect->connect("pressed", this, "_update_mode", varray(), CONNECT_DEFERRED); + + tool_erase_hb = memnew(HBoxContainer); + top_hb->add_child(tool_erase_hb); + tool_erase_hb->add_child(memnew(VSeparator)); + tool_erase = memnew(ToolButton); + tool_erase->set_tooltip(TTR("Remove selected node or transition")); + tool_erase_hb->add_child(tool_erase); + tool_erase->connect("pressed", this, "_erase_selected"); + tool_erase->set_disabled(true); + + tool_erase_hb->add_child(memnew(VSeparator)); + + tool_autoplay = memnew(ToolButton); + tool_autoplay->set_tooltip(TTR("Toggle autoplay this animation on start, restart or seek to zero.")); + tool_erase_hb->add_child(tool_autoplay); + tool_autoplay->connect("pressed", this, "_autoplay_selected"); + tool_autoplay->set_disabled(true); + + tool_end = memnew(ToolButton); + tool_end->set_tooltip(TTR("Set the end animation. This is useful for sub-transitions.")); + tool_erase_hb->add_child(tool_end); + tool_end->connect("pressed", this, "_end_selected"); + tool_end->set_disabled(true); + + top_hb->add_child(memnew(VSeparator)); + top_hb->add_child(memnew(Label(TTR("Transition: ")))); + transition_mode = memnew(OptionButton); + top_hb->add_child(transition_mode); + + top_hb->add_spacer(); + + top_hb->add_child(memnew(Label("Play Mode:"))); + play_mode = memnew(OptionButton); + top_hb->add_child(play_mode); + + GridContainer *main_grid = memnew(GridContainer); + main_grid->set_columns(2); + add_child(main_grid); + main_grid->set_v_size_flags(SIZE_EXPAND_FILL); + + panel = memnew(PanelContainer); + panel->set_clip_contents(true); + main_grid->add_child(panel); + panel->set_h_size_flags(SIZE_EXPAND_FILL); + + state_machine_draw = memnew(Control); + state_machine_draw->connect("gui_input", this, "_state_machine_gui_input"); + state_machine_draw->connect("draw", this, "_state_machine_draw"); + state_machine_draw->set_focus_mode(FOCUS_ALL); + + state_machine_play_pos = memnew(Control); + state_machine_draw->add_child(state_machine_play_pos); + state_machine_play_pos->set_mouse_filter(MOUSE_FILTER_PASS); //pass all to parent + state_machine_play_pos->set_anchors_and_margins_preset(PRESET_WIDE); + state_machine_play_pos->connect("draw", this, "_state_machine_pos_draw"); + + panel->add_child(state_machine_draw); + panel->set_v_size_flags(SIZE_EXPAND_FILL); + + v_scroll = memnew(VScrollBar); + main_grid->add_child(v_scroll); + v_scroll->connect("value_changed", this, "_scroll_changed"); + + h_scroll = memnew(HScrollBar); + main_grid->add_child(h_scroll); + h_scroll->connect("value_changed", this, "_scroll_changed"); + + main_grid->add_child(memnew(Control)); //empty bottom right + + error_panel = memnew(PanelContainer); + add_child(error_panel); + error_label = memnew(Label); + error_panel->add_child(error_label); + error_label->set_text("eh"); + + undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + set_custom_minimum_size(Size2(0, 300 * EDSCALE)); + + menu = memnew(PopupMenu); + add_child(menu); + menu->connect("index_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"); + + name_edit = memnew(LineEdit); + state_machine_draw->add_child(name_edit); + name_edit->hide(); + name_edit->connect("text_entered", this, "_name_edited"); + name_edit->set_as_toplevel(true); + + over_text = false; + + over_node_what = -1; + dragging_selected_attempt = false; + connecting = false; + + last_active = false; + + 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() { +} diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h new file mode 100644 index 0000000000..efd3de7415 --- /dev/null +++ b/editor/plugins/animation_state_machine_editor.h @@ -0,0 +1,167 @@ +#ifndef ANIMATION_STATE_MACHINE_EDITOR_H +#define ANIMATION_STATE_MACHINE_EDITOR_H + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "editor/property_editor.h" +#include "scene/animation/animation_node_state_machine.h" +#include "scene/gui/button.h" +#include "scene/gui/graph_edit.h" +#include "scene/gui/popup.h" +#include "scene/gui/tree.h" + +class AnimationNodeStateMachineEditor : public VBoxContainer { + + GDCLASS(AnimationNodeStateMachineEditor, VBoxContainer); + + Ref<AnimationNodeStateMachine> state_machine; + + ToolButton *tool_select; + ToolButton *tool_create; + ToolButton *tool_connect; + LineEdit *name_edit; + + HBoxContainer *tool_erase_hb; + ToolButton *tool_erase; + ToolButton *tool_autoplay; + ToolButton *tool_end; + + OptionButton *transition_mode; + OptionButton *play_mode; + + HBoxContainer *goto_parent_hbox; + ToolButton *goto_parent; + + PanelContainer *panel; + + StringName selected_node; + + HScrollBar *h_scroll; + VScrollBar *v_scroll; + + Control *state_machine_draw; + Control *state_machine_play_pos; + + PanelContainer *error_panel; + Label *error_label; + + bool updating; + + UndoRedo *undo_redo; + + static AnimationNodeStateMachineEditor *singleton; + + void _state_machine_gui_input(const Ref<InputEvent> &p_event); + void _connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance); + void _state_machine_draw(); + void _state_machine_pos_draw(); + + void _update_graph(); + + PopupMenu *menu; + PopupMenu *animations_menu; + Vector<String> animations_to_add; + + Vector2 add_node_pos; + + bool dragging_selected_attempt; + bool dragging_selected; + Vector2 drag_from; + Vector2 drag_ofs; + StringName snap_x; + StringName snap_y; + + bool connecting; + StringName connecting_from; + Vector2 connecting_to; + StringName connecting_to_node; + + void _add_menu_type(int p_index); + void _add_animation_type(int p_index); + + void _goto_parent(); + + void _removed_from_graph(); + + struct NodeRect { + StringName node_name; + Rect2 node; + Rect2 play; + Rect2 name; + Rect2 edit; + }; + + Vector<NodeRect> node_rects; + + struct TransitionLine { + StringName from_node; + StringName to_node; + Vector2 from; + Vector2 to; + AnimationNodeStateMachineTransition::SwitchMode mode; + bool disabled; + bool auto_advance; + float width; + }; + + Vector<TransitionLine> transition_lines; + + StringName selected_transition_from; + StringName selected_transition_to; + + bool over_text; + StringName over_node; + int over_node_what; + + String prev_name; + void _name_edited(const String &p_text); + void _open_editor(const String &p_name); + void _scroll_changed(double); + + void _clip_src_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect); + void _clip_dst_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect); + + void _erase_selected(); + void _update_mode(); + void _autoplay_selected(); + void _end_selected(); + + bool last_active; + StringName last_blend_from_node; + StringName last_current_node; + Vector<StringName> last_travel_path; + float last_play_pos; + + float error_time; + String error_text; + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + static AnimationNodeStateMachineEditor *get_singleton() { return singleton; } + void edit(AnimationNodeStateMachine *p_state_machine); + 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 diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp new file mode 100644 index 0000000000..89c1b3a978 --- /dev/null +++ b/editor/plugins/root_motion_editor_plugin.cpp @@ -0,0 +1,293 @@ +#include "root_motion_editor_plugin.h" +#include "editor/editor_node.h" +#include "scene/main/viewport.h" + +void EditorPropertyRootMotion::_confirmed() { + + TreeItem *ti = filters->get_selected(); + if (!ti) + return; + + NodePath path = ti->get_metadata(0); + emit_signal("property_changed", get_edited_property(), path); + update_property(); + filter_dialog->hide(); //may come from activated +} + +void EditorPropertyRootMotion::_node_assign() { + + NodePath current = get_edited_object()->get(get_edited_property()); + + AnimationTree *atree = Object::cast_to<AnimationTree>(get_edited_object()); + if (!atree->has_node(atree->get_animation_player())) { + EditorNode::get_singleton()->show_warning(TTR("AnimationTree has no path set to an AnimationPlayer")); + return; + } + AnimationPlayer *player = Object::cast_to<AnimationPlayer>(atree->get_node(atree->get_animation_player())); + if (!player) { + EditorNode::get_singleton()->show_warning(TTR("Path to AnimationPlayer is invalid")); + return; + } + + Node *base = player->get_node(player->get_root()); + + if (!base) { + EditorNode::get_singleton()->show_warning(TTR("Animation player has no valid root node path, so unable to retrieve track names.")); + return; + } + + Set<String> paths; + { + List<StringName> animations; + player->get_animation_list(&animations); + + for (List<StringName>::Element *E = animations.front(); E; E = E->next()) { + + Ref<Animation> anim = player->get_animation(E->get()); + for (int i = 0; i < anim->get_track_count(); i++) { + paths.insert(anim->track_get_path(i)); + } + } + } + + filters->clear(); + TreeItem *root = filters->create_item(); + + Map<String, TreeItem *> parenthood; + + for (Set<String>::Element *E = paths.front(); E; E = E->next()) { + + NodePath path = E->get(); + TreeItem *ti = NULL; + String accum; + for (int i = 0; i < path.get_name_count(); i++) { + String name = path.get_name(i); + if (accum != String()) { + accum += "/"; + } + accum += name; + if (!parenthood.has(accum)) { + if (ti) { + ti = filters->create_item(ti); + } else { + ti = filters->create_item(root); + } + parenthood[accum] = ti; + ti->set_text(0, name); + ti->set_selectable(0, false); + ti->set_editable(0, false); + + if (base->has_node(accum)) { + Node *node = base->get_node(accum); + if (has_icon(node->get_class(), "EditorIcons")) { + ti->set_icon(0, get_icon(node->get_class(), "EditorIcons")); + } else { + ti->set_icon(0, get_icon("Node", "EditorIcons")); + } + } + + } else { + ti = parenthood[accum]; + } + } + + Node *node = NULL; + if (base->has_node(accum)) { + node = base->get_node(accum); + } + if (!node) + continue; //no node, cant edit + + if (path.get_subname_count()) { + + String concat = path.get_concatenated_subnames(); + + Skeleton *skeleton = Object::cast_to<Skeleton>(node); + if (skeleton && skeleton->find_bone(concat) != -1) { + //path in skeleton + String bone = concat; + int idx = skeleton->find_bone(bone); + List<String> bone_path; + while (idx != -1) { + bone_path.push_front(skeleton->get_bone_name(idx)); + idx = skeleton->get_bone_parent(idx); + } + + accum += ":"; + for (List<String>::Element *F = bone_path.front(); F; F = F->next()) { + if (F != bone_path.front()) { + accum += "/"; + } + + accum += F->get(); + if (!parenthood.has(accum)) { + ti = filters->create_item(ti); + parenthood[accum] = ti; + ti->set_text(0, F->get()); + ti->set_selectable(0, true); + ti->set_editable(0, false); + ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons")); + ti->set_metadata(0, accum); + } else { + ti = parenthood[accum]; + } + } + + ti->set_selectable(0, true); + ti->set_text(0, concat); + ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons")); + ti->set_metadata(0, path); + if (path == current) { + ti->select(0); + } + + } else { + //just a property + ti = filters->create_item(ti); + ti->set_text(0, concat); + ti->set_selectable(0, true); + ti->set_metadata(0, path); + if (path == current) { + ti->select(0); + } + } + } else { + if (ti) { + //just a node, likely call or animation track + ti->set_selectable(0, true); + ti->set_metadata(0, path); + if (path == current) { + ti->select(0); + } + } + } + } + + filters->ensure_cursor_is_visible(); + filter_dialog->popup_centered_ratio(); +} + +void EditorPropertyRootMotion::_node_clear() { + + emit_signal("property_changed", get_edited_property(), NodePath()); + update_property(); +} + +void EditorPropertyRootMotion::update_property() { + + NodePath p = get_edited_object()->get(get_edited_property()); + + assign->set_tooltip(p); + if (p == NodePath()) { + assign->set_icon(Ref<Texture>()); + assign->set_text(TTR("Assign..")); + assign->set_flat(false); + return; + } + assign->set_flat(true); + + Node *base_node = NULL; + if (base_hint != NodePath()) { + if (get_tree()->get_root()->has_node(base_hint)) { + base_node = get_tree()->get_root()->get_node(base_hint); + } + } else { + base_node = Object::cast_to<Node>(get_edited_object()); + } + + if (!base_node || !base_node->has_node(p)) { + assign->set_icon(Ref<Texture>()); + assign->set_text(p); + return; + } + + Node *target_node = base_node->get_node(p); + ERR_FAIL_COND(!target_node); + + assign->set_text(target_node->get_name()); + + Ref<Texture> icon; + if (has_icon(target_node->get_class(), "EditorIcons")) + icon = get_icon(target_node->get_class(), "EditorIcons"); + else + icon = get_icon("Node", "EditorIcons"); + + assign->set_icon(icon); +} + +void EditorPropertyRootMotion::setup(const NodePath &p_base_hint) { + + base_hint = p_base_hint; +} + +void EditorPropertyRootMotion::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Ref<Texture> t = get_icon("Clear", "EditorIcons"); + clear->set_icon(t); + } +} + +void EditorPropertyRootMotion::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_confirmed"), &EditorPropertyRootMotion::_confirmed); + ClassDB::bind_method(D_METHOD("_node_assign"), &EditorPropertyRootMotion::_node_assign); + ClassDB::bind_method(D_METHOD("_node_clear"), &EditorPropertyRootMotion::_node_clear); +} + +EditorPropertyRootMotion::EditorPropertyRootMotion() { + + HBoxContainer *hbc = memnew(HBoxContainer); + add_child(hbc); + assign = memnew(Button); + assign->set_flat(true); + assign->set_h_size_flags(SIZE_EXPAND_FILL); + assign->set_clip_text(true); + assign->connect("pressed", this, "_node_assign"); + hbc->add_child(assign); + + clear = memnew(Button); + clear->set_flat(true); + clear->connect("pressed", this, "_node_clear"); + hbc->add_child(clear); + + filter_dialog = memnew(ConfirmationDialog); + add_child(filter_dialog); + filter_dialog->set_title(TTR("Edit Filtered Tracks:")); + filter_dialog->connect("confirmed", this, "_confirmed"); + + filters = memnew(Tree); + filter_dialog->add_child(filters); + filters->set_v_size_flags(SIZE_EXPAND_FILL); + filters->set_hide_root(true); + filters->connect("item_activated", this, "_confirmed"); + //filters->connect("item_edited", this, "_filter_edited"); +} +////////////////////////// + +bool EditorInspectorRootMotionPlugin::can_handle(Object *p_object) { + return true; //can handle everything +} + +void EditorInspectorRootMotionPlugin::parse_begin(Object *p_object) { + //do none +} + +bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) { + + if (p_path == "root_motion_track" && p_object->is_class("AnimationTree") && p_type == Variant::NODE_PATH) { + print_line("use custom!"); + EditorPropertyRootMotion *editor = memnew(EditorPropertyRootMotion); + if (p_hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && p_hint_text != String()) { + editor->setup(p_hint_text); + } + add_property_editor(p_path, editor); + return true; + } + + return false; //can be overriden, although it will most likely be last anyway +} + +void EditorInspectorRootMotionPlugin::parse_end() { + //do none +} diff --git a/editor/plugins/root_motion_editor_plugin.h b/editor/plugins/root_motion_editor_plugin.h new file mode 100644 index 0000000000..84af47872f --- /dev/null +++ b/editor/plugins/root_motion_editor_plugin.h @@ -0,0 +1,42 @@ +#ifndef ROOT_MOTION_EDITOR_PLUGIN_H +#define ROOT_MOTION_EDITOR_PLUGIN_H + +#include "editor/editor_inspector.h" +#include "editor/editor_spin_slider.h" +#include "editor/property_selector.h" +#include "scene/animation/animation_tree.h" + +class EditorPropertyRootMotion : public EditorProperty { + GDCLASS(EditorPropertyRootMotion, EditorProperty) + Button *assign; + Button *clear; + NodePath base_hint; + + ConfirmationDialog *filter_dialog; + Tree *filters; + + void _confirmed(); + void _node_assign(); + void _node_clear(); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + virtual void update_property(); + void setup(const NodePath &p_base_hint); + EditorPropertyRootMotion(); +}; + +class EditorInspectorRootMotionPlugin : public EditorInspectorPlugin { + GDCLASS(EditorInspectorRootMotionPlugin, EditorInspectorPlugin) + +public: + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); + virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage); + virtual void parse_end(); +}; + +#endif // ROOT_MOTION_EDITOR_PLUGIN_H diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index ea133cd749..7264af3488 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -133,16 +133,14 @@ void TileMapEditor::_menu_option(int p_option) { if (!selection_active) return; - undo_redo->create_action(TTR("Erase Selection")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Erase Selection")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { _set_cell(Point2i(j, i), TileMap::INVALID_CELL, false, false, false); } } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); selection_active = false; copydata.clear(); @@ -208,6 +206,46 @@ void TileMapEditor::set_selected_tile(int p_tile) { } } +void TileMapEditor::_create_set_cell_undo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new) { + + Dictionary cell_old; + Dictionary cell_new; + + cell_old["id"] = p_cell_old.idx; + cell_old["flip_h"] = p_cell_old.xf; + cell_old["flip_y"] = p_cell_old.yf; + cell_old["transpose"] = p_cell_old.tr; + cell_old["auto_coord"] = p_cell_old.ac; + + cell_new["id"] = p_cell_new.idx; + cell_new["flip_h"] = p_cell_new.xf; + cell_new["flip_y"] = p_cell_new.yf; + cell_new["transpose"] = p_cell_new.tr; + cell_new["auto_coord"] = p_cell_new.ac; + + undo_redo->add_undo_method(node, "set_celld", p_vec, cell_old); + undo_redo->add_do_method(node, "set_celld", p_vec, cell_new); +} + +void TileMapEditor::_start_undo(const String &p_action) { + + undo_data.clear(); + undo_redo->create_action(p_action); +} + +void TileMapEditor::_finish_undo() { + + if (undo_data.size()) { + for (Map<Point2i, CellOp>::Element *E = undo_data.front(); E; E = E->next()) { + _create_set_cell_undo(E->key(), E->get(), _get_op_from_cell(E->key())); + } + + undo_data.clear(); + } + + undo_redo->commit_action(); +} + void TileMapEditor::_set_cell(const Point2i &p_pos, int p_value, bool p_flip_h, bool p_flip_v, bool p_transpose) { ERR_FAIL_COND(!node); @@ -234,6 +272,15 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, int p_value, bool p_flip_h, if (p_value == prev_val && p_flip_h == prev_flip_h && p_flip_v == prev_flip_v && p_transpose == prev_transpose && prev_position == position) return; //check that it's actually different + for (int y = p_pos.y - 1; y <= p_pos.y + 1; y++) { + for (int x = p_pos.x - 1; x <= p_pos.x + 1; x++) { + Point2i p = Point2i(x, y); + if (!undo_data.has(p)) { + undo_data[p] = _get_op_from_cell(p); + } + } + } + node->set_cell(p_pos.x, p_pos.y, p_value, p_flip_h, p_flip_v, p_transpose); if (manual_autotile) { if (current != -1) { @@ -844,8 +891,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { tool = TOOL_PAINTING; - undo_redo->create_action(TTR("Paint TileMap")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Paint TileMap")); } } else if (tool == TOOL_PICKING) { @@ -869,8 +915,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (id != TileMap::INVALID_CELL) { _set_cell(over_tile, id, flip_h, flip_v, transpose); - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); paint_undo.clear(); } @@ -880,14 +925,12 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (id != TileMap::INVALID_CELL) { - undo_redo->create_action(TTR("Line Draw")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Line Draw")); for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { _set_cell(E->key(), id, flip_h, flip_v, transpose); } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); paint_undo.clear(); @@ -899,16 +942,14 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (id != TileMap::INVALID_CELL) { - undo_redo->create_action(TTR("Rectangle Paint")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Rectangle Paint")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { _set_cell(Point2i(j, i), id, flip_h, flip_v, transpose); } } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); canvas_item_editor->update(); } @@ -916,14 +957,12 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Point2 ofs = over_tile - rectangle.position; - undo_redo->create_action(TTR("Duplicate")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Duplicate")); for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) { _set_cell(E->get().pos + ofs, E->get().cell, E->get().flip_h, E->get().flip_v, E->get().transpose); } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); copydata.clear(); @@ -932,8 +971,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Point2 ofs = over_tile - rectangle.position; - undo_redo->create_action(TTR("Move")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Move")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { @@ -944,8 +982,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { _set_cell(E->get().pos + ofs, E->get().cell, E->get().flip_h, E->get().flip_v, E->get().transpose); } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); copydata.clear(); selection_active = false; @@ -964,7 +1001,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { return false; undo_redo->create_action(TTR("Bucket Fill")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); Dictionary op; op["id"] = get_selected_tile(); @@ -974,7 +1010,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { _fill_points(points, op); - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); // We want to keep the bucket-tool active @@ -1026,8 +1061,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Point2 local = node->world_to_map(xform_inv.xform(mb->get_position())); - undo_redo->create_action(TTR("Erase TileMap")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Erase TileMap")); if (mb->get_shift()) { #ifdef APPLE_STYLE_KEYS @@ -1054,8 +1088,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } else { if (tool == TOOL_ERASING || tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); if (tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { canvas_item_editor->update(); @@ -1621,6 +1654,7 @@ TileMapEditor::CellOp TileMapEditor::_get_op_from_cell(const Point2i &p_pos) { op.yf = true; if (node->is_cell_transposed(p_pos.x, p_pos.y)) op.tr = true; + op.ac = node->get_cell_autotile_coord(p_pos.x, p_pos.y); } return op; } diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index a1f5d93a8d..77e9a33892 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -129,6 +129,7 @@ class TileMapEditor : public VBoxContainer { bool xf; bool yf; bool tr; + Vector2 ac; CellOp() : idx(TileMap::INVALID_CELL), @@ -155,6 +156,8 @@ class TileMapEditor : public VBoxContainer { List<TileData> copydata; + Map<Point2i, CellOp> undo_data; + void _pick_tile(const Point2 &p_pos); PoolVector<Vector2> _bucket_fill(const Point2i &p_start, bool erase = false, bool preview = false); @@ -181,6 +184,9 @@ class TileMapEditor : public VBoxContainer { void _menu_option(int p_option); void _palette_selected(int index); + void _start_undo(const String &p_action); + void _finish_undo(); + void _create_set_cell_undo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new); void _set_cell(const Point2i &p_pos, int p_value, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false); void _canvas_mouse_enter(); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 7d2127d4f8..88d614ab89 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -166,6 +166,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { } TreeItem *item = tree->create_item(p_parent); + item->set_text(0, p_node->get_name()); if (can_rename && !part_of_subscene /*(p_node->get_owner() == get_scene_node() || p_node==get_scene_node())*/) item->set_editable(0, true); @@ -196,7 +197,9 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { if (part_of_subscene) { //item->set_selectable(0,marked_selectable); - item->set_custom_color(0, get_color("disabled_font_color", "Editor")); + if (valid_types.size() == 0) { + item->set_custom_color(0, get_color("disabled_font_color", "Editor")); + } } else if (marked.has(p_node)) { @@ -323,6 +326,22 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { keep = keep || child_keep; } + if (valid_types.size()) { + bool valid = false; + for (int i = 0; i < valid_types.size(); i++) { + if (p_node->is_class(valid_types[i])) { + valid = true; + break; + } + } + + if (!valid) { + //item->set_selectable(0,marked_selectable); + item->set_custom_color(0, get_color("disabled_font_color", "Editor")); + item->set_selectable(0, false); + } + } + if (!keep) { memdelete(item); return false; @@ -716,6 +735,10 @@ bool SceneTreeEditor::get_display_foreign_nodes() const { return display_foreign; } +void SceneTreeEditor::set_valid_types(const Vector<StringName> &p_valid) { + valid_types = p_valid; +} + void SceneTreeEditor::set_editor_selection(EditorSelection *p_selection) { editor_selection = p_selection; diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index b173d7d215..c4f63f5736 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -131,6 +131,8 @@ class SceneTreeEditor : public Control { List<StringName> *script_types; bool _is_script_type(const StringName &p_type) const; + Vector<StringName> valid_types; + public: void set_filter(const String &p_filter); String get_filter() const; @@ -147,6 +149,7 @@ public: void set_editor_selection(EditorSelection *p_selection); void set_show_enabled_subscene(bool p_show) { show_enabled_subscene = p_show; } + void set_valid_types(const Vector<StringName> &p_valid); void update_tree() { _update_tree(); } diff --git a/main/app_icon.png b/main/app_icon.png Binary files differindex 1d75cdc710..cf31af18a4 100644 --- a/main/app_icon.png +++ b/main/app_icon.png diff --git a/main/main.cpp b/main/main.cpp index 2e3c2f41b9..e2b3bb8e6f 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -867,6 +867,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/allow_per_pixel_transparency", false); video_mode.use_vsync = GLOBAL_DEF("display/window/vsync/use_vsync", true); + OS::get_singleton()->_use_vsync = video_mode.use_vsync; + video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency", false); video_mode.layered_splash = GLOBAL_DEF("display/window/per_pixel_transparency_splash", false); diff --git a/main/splash.png b/main/splash.png Binary files differindex 34be46557f..32960db65f 100644 --- a/main/splash.png +++ b/main/splash.png diff --git a/main/splash_editor.png b/main/splash_editor.png Binary files differindex d8677f1749..f003995d6f 100644 --- a/main/splash_editor.png +++ b/main/splash_editor.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-480h@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-480h@2x.png Binary files differindex 6b9b10daae..1299ceaee5 100644 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-480h@2x.png +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-480h@2x.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png Binary files differindex 50497496b7..604a7ba701 100644 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-667h@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-667h@2x.png Binary files differindex 1c489de69f..bffb8c9fde 100644 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-667h@2x.png +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-667h@2x.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-736h@3x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-736h@3x.png Binary files differindex d82dfce936..47826cd683 100644 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-736h@3x.png +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-736h@3x.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-X.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-X.png Binary files differindex 5120595df8..0f44a704b5 100644 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-X.png +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape-X.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png Binary files differindex cf6cf1347a..07ab777bc2 100644 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png Binary files differindex 4eb167ae18..774b9c5bbf 100644 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-736h@3x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-736h@3x.png Binary files differindex a9f951deac..fff36679c7 100644 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-736h@3x.png +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-736h@3x.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-X.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-X.png Binary files differindex 06d16412e2..0804519faa 100644 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-X.png +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait-X.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait.png Binary files differindex d70cab17be..833142222c 100644 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait.png +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png Binary files differindex f934971074..4c934c4a53 100644 --- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png diff --git a/misc/dist/uwp_template/Assets/SplashScreen.scale-100.png b/misc/dist/uwp_template/Assets/SplashScreen.scale-100.png Binary files differindex 540bfb1c01..0c27fda8e7 100644 --- a/misc/dist/uwp_template/Assets/SplashScreen.scale-100.png +++ b/misc/dist/uwp_template/Assets/SplashScreen.scale-100.png diff --git a/misc/dist/uwp_template/Assets/Square150x150Logo.scale-100.png b/misc/dist/uwp_template/Assets/Square150x150Logo.scale-100.png Binary files differindex 6e307e5eb8..96871f7413 100644 --- a/misc/dist/uwp_template/Assets/Square150x150Logo.scale-100.png +++ b/misc/dist/uwp_template/Assets/Square150x150Logo.scale-100.png diff --git a/misc/dist/uwp_template/Assets/Square310x310Logo.scale-100.png b/misc/dist/uwp_template/Assets/Square310x310Logo.scale-100.png Binary files differindex cb2516d7a0..96494b1020 100644 --- a/misc/dist/uwp_template/Assets/Square310x310Logo.scale-100.png +++ b/misc/dist/uwp_template/Assets/Square310x310Logo.scale-100.png diff --git a/misc/dist/uwp_template/Assets/Square44x44Logo.scale-100.png b/misc/dist/uwp_template/Assets/Square44x44Logo.scale-100.png Binary files differindex 6e14223e87..d21bc42009 100644 --- a/misc/dist/uwp_template/Assets/Square44x44Logo.scale-100.png +++ b/misc/dist/uwp_template/Assets/Square44x44Logo.scale-100.png diff --git a/misc/dist/uwp_template/Assets/Square71x71Logo.scale-100.png b/misc/dist/uwp_template/Assets/Square71x71Logo.scale-100.png Binary files differindex 0d4bd54da8..22a43cf95f 100644 --- a/misc/dist/uwp_template/Assets/Square71x71Logo.scale-100.png +++ b/misc/dist/uwp_template/Assets/Square71x71Logo.scale-100.png diff --git a/misc/dist/uwp_template/Assets/StoreLogo.scale-100.png b/misc/dist/uwp_template/Assets/StoreLogo.scale-100.png Binary files differindex 1501a09557..3960b0424b 100644 --- a/misc/dist/uwp_template/Assets/StoreLogo.scale-100.png +++ b/misc/dist/uwp_template/Assets/StoreLogo.scale-100.png diff --git a/misc/dist/uwp_template/Assets/Wide310x150Logo.scale-100.png b/misc/dist/uwp_template/Assets/Wide310x150Logo.scale-100.png Binary files differindex 593568e980..d836e113b1 100644 --- a/misc/dist/uwp_template/Assets/Wide310x150Logo.scale-100.png +++ b/misc/dist/uwp_template/Assets/Wide310x150Logo.scale-100.png diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index ba27d6839d..5f13474d2c 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -2020,7 +2020,7 @@ void CSGPolygon::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees"); ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node"), "set_path_node", "get_path_node"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path"), "set_path_node", "get_path_node"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "path_interval", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_path_interval", "get_path_interval"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub index a3434995aa..116a86b27b 100644 --- a/modules/gdnative/SCsub +++ b/modules/gdnative/SCsub @@ -13,6 +13,7 @@ gdn_env.add_source_files(env.modules_sources, "gdnative_library_editor_plugin.cp gdn_env.Append(CPPPATH=['#modules/gdnative/include/']) +SConscript("net/SCsub") SConscript("arvr/SCsub") SConscript("pluginscript/SCsub") diff --git a/modules/gdnative/config.py b/modules/gdnative/config.py index 626e9239f8..c5b37d35b4 100644 --- a/modules/gdnative/config.py +++ b/modules/gdnative/config.py @@ -10,6 +10,7 @@ def get_doc_classes(): "GDNative", "GDNativeLibrary", "NativeScript", + "PacketPeerGDNative", "PluginScript", ] diff --git a/modules/gdnative/include/net/godot_net.h b/modules/gdnative/include/net/godot_net.h new file mode 100644 index 0000000000..bfa688592d --- /dev/null +++ b/modules/gdnative/include/net/godot_net.h @@ -0,0 +1,118 @@ +/*************************************************************************/ +/* godot_net.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 GODOT_NATIVENET_H +#define GODOT_NATIVENET_H + +#include <gdnative/gdnative.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// For future versions of the API we should only add new functions at the end of the structure and use the +// version info to detect whether a call is available + +// Use these to populate version in your plugin +#define GODOT_NET_API_MAJOR 3 +#define GODOT_NET_API_MINOR 1 + +typedef struct { + + godot_gdnative_api_version version; /* version of our API */ + godot_object *data; /* User reference */ + + /* This is StreamPeer */ + godot_error (*get_data)(void *user, uint8_t *p_buffer, int p_bytes); + godot_error (*get_partial_data)(void *user, uint8_t *p_buffer, int p_bytes, int &r_received); + godot_error (*put_data)(void *user, const uint8_t *p_data, int p_bytes); + godot_error (*put_partial_data)(void *user, const uint8_t *p_data, int p_bytes, int &r_sent); + + int (*get_available_bytes)(const void *user); + + void *next; /* For extension? */ +} godot_net_stream_peer; + +/* Binds a StreamPeerGDNative to the provided interface */ +void godot_net_bind_stream_peer(godot_object *p_obj, godot_net_stream_peer *p_interface); + +typedef struct { + godot_gdnative_api_version version; /* version of our API */ + + godot_object *data; /* User reference */ + + /* This is PacketPeer */ + godot_error (*get_packet)(void *, const uint8_t **, int &); + godot_error (*put_packet)(void *, const uint8_t *, int); + godot_int (*get_available_packet_count)(const void *); + godot_int (*get_max_packet_size)(const void *); + + void *next; /* For extension? */ +} godot_net_packet_peer; + +/* Binds a PacketPeerGDNative to the provided interface */ +void GDAPI godot_net_bind_packet_peer(godot_object *p_obj, const godot_net_packet_peer *); + +typedef struct { + godot_gdnative_api_version version; /* version of our API */ + + godot_object *data; /* User reference */ + + /* This is PacketPeer */ + godot_error (*get_packet)(void *, const uint8_t **, int &); + godot_error (*put_packet)(void *, const uint8_t *, int); + godot_int (*get_available_packet_count)(const void *); + godot_int (*get_max_packet_size)(const void *); + + /* This is NetworkedMultiplayerPeer */ + void (*set_transfer_mode)(void *, godot_int); + godot_int (*get_transfer_mode)(const void *); + // 0 = broadcast, 1 = server, <0 = all but abs(value) + void (*set_target_peer)(void *, godot_int); + godot_int (*get_packet_peer)(const void *); + godot_bool (*is_server)(const void *); + void (*poll)(void *); + // Must be > 0, 1 is for server + int32_t (*get_unique_id)(const void *); + void (*set_refuse_new_connections)(void *, godot_bool); + godot_bool (*is_refusing_new_connections)(const void *); + godot_int (*get_connection_status)(const void *); + + void *next; /* For extension? Or maybe not... */ +} godot_net_multiplayer_peer; + +/* Binds a MultiplayerPeerGDNative to the provided interface */ +void GDAPI godot_net_bind_multiplayer_peer(godot_object *p_obj, const godot_net_multiplayer_peer *); + +#ifdef __cplusplus +} +#endif + +#endif /* GODOT_NATIVENET_H */ diff --git a/modules/gdnative/net/SCsub b/modules/gdnative/net/SCsub new file mode 100644 index 0000000000..53f9271128 --- /dev/null +++ b/modules/gdnative/net/SCsub @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +import os +import methods + +Import('env') +Import('env_modules') + +env_net_gdnative = env_modules.Clone() + +env_net_gdnative.Append(CPPPATH=['#modules/gdnative/include/']) +env_net_gdnative.add_source_files(env.modules_sources, '*.cpp') diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp new file mode 100644 index 0000000000..e2d710b5ad --- /dev/null +++ b/modules/gdnative/net/multiplayer_peer_gdnative.cpp @@ -0,0 +1,124 @@ +/*************************************************************************/ +/* multiplayer_peer_gdnative.cpp */ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ + +#include "multiplayer_peer_gdnative.h" + +MultiplayerPeerGDNative::MultiplayerPeerGDNative() { + interface = NULL; +} + +MultiplayerPeerGDNative::~MultiplayerPeerGDNative() { +} + +void MultiplayerPeerGDNative::set_native_multiplayer_peer(const godot_net_multiplayer_peer *p_interface) { + interface = p_interface; +} + +Error MultiplayerPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->get_packet(interface->data, r_buffer, r_buffer_size); +} + +Error MultiplayerPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size); +} + +int MultiplayerPeerGDNative::get_max_packet_size() const { + ERR_FAIL_COND_V(interface == NULL, 0); + return interface->get_max_packet_size(interface->data); +} + +int MultiplayerPeerGDNative::get_available_packet_count() const { + ERR_FAIL_COND_V(interface == NULL, 0); + return interface->get_available_packet_count(interface->data); +} + +/* NetworkedMultiplayerPeer */ +void MultiplayerPeerGDNative::set_transfer_mode(TransferMode p_mode) { + ERR_FAIL_COND(interface == NULL); + interface->set_transfer_mode(interface->data, (godot_int)p_mode); +} + +NetworkedMultiplayerPeer::TransferMode MultiplayerPeerGDNative::get_transfer_mode() const { + ERR_FAIL_COND_V(interface == NULL, TRANSFER_MODE_UNRELIABLE); + return (TransferMode)interface->get_transfer_mode(interface->data); +} + +void MultiplayerPeerGDNative::set_target_peer(int p_peer_id) { + ERR_FAIL_COND(interface == NULL); + interface->set_target_peer(interface->data, p_peer_id); +} + +int MultiplayerPeerGDNative::get_packet_peer() const { + ERR_FAIL_COND_V(interface == NULL, 0); + return interface->get_packet_peer(interface->data); +} + +bool MultiplayerPeerGDNative::is_server() const { + ERR_FAIL_COND_V(interface == NULL, false); + return interface->is_server(interface->data); +} + +void MultiplayerPeerGDNative::poll() { + ERR_FAIL_COND(interface == NULL); + interface->poll(interface->data); +} + +int MultiplayerPeerGDNative::get_unique_id() const { + ERR_FAIL_COND_V(interface == NULL, 0); + return interface->get_unique_id(interface->data); +} + +void MultiplayerPeerGDNative::set_refuse_new_connections(bool p_enable) { + ERR_FAIL_COND(interface == NULL); + interface->set_refuse_new_connections(interface->data, p_enable); +} + +bool MultiplayerPeerGDNative::is_refusing_new_connections() const { + ERR_FAIL_COND_V(interface == NULL, true); + return interface->is_refusing_new_connections(interface->data); +} + +NetworkedMultiplayerPeer::ConnectionStatus MultiplayerPeerGDNative::get_connection_status() const { + ERR_FAIL_COND_V(interface == NULL, CONNECTION_DISCONNECTED); + return (ConnectionStatus)interface->get_connection_status(interface->data); +} + +void MultiplayerPeerGDNative::_bind_methods() { +} + +extern "C" { + +void GDAPI godot_net_bind_multiplayer_peer(godot_object *p_obj, const godot_net_multiplayer_peer *p_impl) { + + ((MultiplayerPeerGDNative *)p_obj)->set_native_multiplayer_peer(p_impl); +} +} diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.h b/modules/gdnative/net/multiplayer_peer_gdnative.h new file mode 100644 index 0000000000..c8c95b3dd7 --- /dev/null +++ b/modules/gdnative/net/multiplayer_peer_gdnative.h @@ -0,0 +1,77 @@ +/*************************************************************************/ +/* multiplayer_peer_gdnative.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 MULTIPLAYER_PEER_GDNATIVE_H +#define MULTIPLAYER_PEER_GDNATIVE_H + +#include "core/io/networked_multiplayer_peer.h" +#include "modules/gdnative/gdnative.h" +#include "modules/gdnative/include/net/godot_net.h" + +class MultiplayerPeerGDNative : public NetworkedMultiplayerPeer { + GDCLASS(MultiplayerPeerGDNative, NetworkedMultiplayerPeer) + +protected: + static void _bind_methods(); + const godot_net_multiplayer_peer *interface; + +public: + MultiplayerPeerGDNative(); + ~MultiplayerPeerGDNative(); + + /* Sets the interface implementation from GDNative */ + void set_native_multiplayer_peer(const godot_net_multiplayer_peer *p_impl); + + /* Specific to PacketPeer */ + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); + virtual int get_max_packet_size() const; + virtual int get_available_packet_count() const; + + /* Specific to NetworkedMultiplayerPeer */ + virtual void set_transfer_mode(TransferMode p_mode); + virtual TransferMode get_transfer_mode() const; + virtual void set_target_peer(int p_peer_id); + + virtual int get_packet_peer() const; + + virtual bool is_server() const; + + virtual void poll(); + + virtual int get_unique_id() const; + + virtual void set_refuse_new_connections(bool p_enable); + virtual bool is_refusing_new_connections() const; + + virtual ConnectionStatus get_connection_status() const; +}; + +#endif // MULTIPLAYER_PEER_GDNATIVE_H diff --git a/modules/gdnative/net/packet_peer_gdnative.cpp b/modules/gdnative/net/packet_peer_gdnative.cpp new file mode 100644 index 0000000000..ceae79edc0 --- /dev/null +++ b/modules/gdnative/net/packet_peer_gdnative.cpp @@ -0,0 +1,73 @@ +/*************************************************************************/ +/* packet_peer_gdnative.cpp */ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ + +#include "packet_peer_gdnative.h" + +PacketPeerGDNative::PacketPeerGDNative() { + interface = NULL; +} + +PacketPeerGDNative::~PacketPeerGDNative() { +} + +void PacketPeerGDNative::set_native_packet_peer(const godot_net_packet_peer *p_impl) { + interface = p_impl; +} + +void PacketPeerGDNative::_bind_methods() { +} + +Error PacketPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->get_packet(interface->data, r_buffer, r_buffer_size); +} + +Error PacketPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size); +} + +int PacketPeerGDNative::get_max_packet_size() const { + ERR_FAIL_COND_V(interface == NULL, 0); + return interface->get_max_packet_size(interface->data); +} + +int PacketPeerGDNative::get_available_packet_count() const { + ERR_FAIL_COND_V(interface == NULL, 0); + return interface->get_available_packet_count(interface->data); +} + +extern "C" { + +void GDAPI godot_net_bind_packet_peer(godot_object *p_obj, const godot_net_packet_peer *p_impl) { + + ((PacketPeerGDNative *)p_obj)->set_native_packet_peer(p_impl); +} +} diff --git a/modules/gdnative/net/packet_peer_gdnative.h b/modules/gdnative/net/packet_peer_gdnative.h new file mode 100644 index 0000000000..71814177ed --- /dev/null +++ b/modules/gdnative/net/packet_peer_gdnative.h @@ -0,0 +1,59 @@ +/*************************************************************************/ +/* packet_peer_gdnative.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 PACKET_PEER_GDNATIVE_H +#define PACKET_PEER_GDNATIVE_H + +#include "core/io/packet_peer.h" +#include "modules/gdnative/gdnative.h" +#include "modules/gdnative/include/net/godot_net.h" + +class PacketPeerGDNative : public PacketPeer { + GDCLASS(PacketPeerGDNative, PacketPeer) + +protected: + static void _bind_methods(); + const godot_net_packet_peer *interface; + +public: + PacketPeerGDNative(); + ~PacketPeerGDNative(); + + /* Sets the interface implementation from GDNative */ + void set_native_packet_peer(const godot_net_packet_peer *p_impl); + + /* Specific to PacketPeer */ + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); + virtual int get_max_packet_size() const; + virtual int get_available_packet_count() const; +}; + +#endif // PACKET_PEER_GDNATIVE_H diff --git a/modules/gdnative/net/register_types.cpp b/modules/gdnative/net/register_types.cpp new file mode 100644 index 0000000000..c3fb4d8008 --- /dev/null +++ b/modules/gdnative/net/register_types.cpp @@ -0,0 +1,43 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ + +#include "register_types.h" +#include "multiplayer_peer_gdnative.h" +#include "packet_peer_gdnative.h" +#include "stream_peer_gdnative.h" + +void register_net_types() { + ClassDB::register_class<MultiplayerPeerGDNative>(); + ClassDB::register_class<PacketPeerGDNative>(); + ClassDB::register_class<StreamPeerGDNative>(); +} + +void unregister_net_types() { +} diff --git a/modules/gdnative/net/register_types.h b/modules/gdnative/net/register_types.h new file mode 100644 index 0000000000..9545a2ba8f --- /dev/null +++ b/modules/gdnative/net/register_types.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* register_types.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. */ +/*************************************************************************/ + +void register_net_types(); +void unregister_net_types(); diff --git a/modules/gdnative/net/stream_peer_gdnative.cpp b/modules/gdnative/net/stream_peer_gdnative.cpp new file mode 100644 index 0000000000..4d1f2ec9a5 --- /dev/null +++ b/modules/gdnative/net/stream_peer_gdnative.cpp @@ -0,0 +1,77 @@ +/*************************************************************************/ +/* stream_peer_gdnative.cpp */ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ + +#include "stream_peer_gdnative.h" + +StreamPeerGDNative::StreamPeerGDNative() { + interface = NULL; +} + +StreamPeerGDNative::~StreamPeerGDNative() { +} + +void StreamPeerGDNative::set_native_stream_peer(godot_net_stream_peer *p_interface) { + interface = p_interface; +} + +void StreamPeerGDNative::_bind_methods() { +} + +Error StreamPeerGDNative::put_data(const uint8_t *p_data, int p_bytes) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)(interface->put_data(interface->data, p_data, p_bytes)); +} + +Error StreamPeerGDNative::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)(interface->put_partial_data(interface->data, p_data, p_bytes, r_sent)); +} + +Error StreamPeerGDNative::get_data(uint8_t *p_buffer, int p_bytes) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)(interface->get_data(interface->data, p_buffer, p_bytes)); +} + +Error StreamPeerGDNative::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)(interface->get_partial_data(interface->data, p_buffer, p_bytes, r_received)); +} + +int StreamPeerGDNative::get_available_bytes() const { + ERR_FAIL_COND_V(interface == NULL, 0); + return interface->get_available_bytes(interface->data); +} + +extern "C" { + +void GDAPI godot_net_bind_stream_peer(godot_object *p_obj, godot_net_stream_peer *p_interface) { + ((StreamPeerGDNative *)p_obj)->set_native_stream_peer(p_interface); +} +} diff --git a/modules/gdnative/net/stream_peer_gdnative.h b/modules/gdnative/net/stream_peer_gdnative.h new file mode 100644 index 0000000000..654234e6ab --- /dev/null +++ b/modules/gdnative/net/stream_peer_gdnative.h @@ -0,0 +1,61 @@ +/*************************************************************************/ +/* stream_peer_gdnative.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 STREAM_PEER_GDNATIVE_H +#define STREAM_PEER_GDNATIVE_H + +#include "core/io/stream_peer.h" +#include "modules/gdnative/gdnative.h" +#include "modules/gdnative/include/net/godot_net.h" + +class StreamPeerGDNative : public StreamPeer { + + GDCLASS(StreamPeerGDNative, StreamPeer); + +protected: + static void _bind_methods(); + godot_net_stream_peer *interface; + +public: + StreamPeerGDNative(); + ~StreamPeerGDNative(); + + /* Sets the interface implementation from GDNative */ + void set_native_stream_peer(godot_net_stream_peer *p_interface); + + /* Specific to StreamPeer */ + Error put_data(const uint8_t *p_data, int p_bytes); + Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent); + Error get_data(uint8_t *p_buffer, int p_bytes); + Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received); + int get_available_bytes() const; +}; + +#endif // STREAM_PEER_GDNATIVE_H diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index a0b6fbeb75..d18297f2f8 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -38,6 +38,7 @@ #include "arvr/register_types.h" #include "nativescript/register_types.h" +#include "net/register_types.h" #include "pluginscript/register_types.h" #include "core/engine.h" @@ -321,6 +322,7 @@ void register_gdnative_types() { GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall); + register_net_types(); register_arvr_types(); register_nativescript_types(); register_pluginscript_types(); @@ -379,6 +381,7 @@ void unregister_gdnative_types() { unregister_pluginscript_types(); unregister_nativescript_types(); unregister_arvr_types(); + unregister_net_types(); memdelete(GDNativeCallRegistry::singleton); diff --git a/modules/websocket/lws_helper.h b/modules/websocket/lws_helper.h index a850a545d3..a4920c3d54 100644 --- a/modules/websocket/lws_helper.h +++ b/modules/websocket/lws_helper.h @@ -30,6 +30,9 @@ #ifndef LWS_HELPER_H #define LWS_HELPER_H +#define LWS_BUF_SIZE 65536 +#define LWS_PACKET_SIZE LWS_BUF_SIZE + #include "core/io/stream_peer.h" #include "core/os/os.h" #include "core/reference.h" @@ -124,6 +127,7 @@ static void _lws_make_protocols(void *p_obj, lws_callback_function *p_callback, /* LWS protocol structs */ ref->lws_structs = (struct lws_protocols *)memalloc(sizeof(struct lws_protocols) * (len + 2)); + memset(ref->lws_structs, 0, sizeof(struct lws_protocols) * (len + 2)); CharString strings = p_names.join(",").ascii(); int str_len = strings.length(); @@ -145,13 +149,15 @@ static void _lws_make_protocols(void *p_obj, lws_callback_function *p_callback, structs_ptr[0].name = "http-only"; structs_ptr[0].callback = p_callback; structs_ptr[0].per_session_data_size = data_size; - structs_ptr[0].rx_buffer_size = 0; + structs_ptr[0].rx_buffer_size = LWS_BUF_SIZE; + structs_ptr[0].tx_packet_size = LWS_PACKET_SIZE; /* add user defined protocols */ for (i = 0; i < len; i++) { structs_ptr[i + 1].name = (const char *)&names_ptr[pos]; structs_ptr[i + 1].callback = p_callback; structs_ptr[i + 1].per_session_data_size = data_size; - structs_ptr[i + 1].rx_buffer_size = 0; + structs_ptr[i + 1].rx_buffer_size = LWS_BUF_SIZE; + structs_ptr[i + 1].tx_packet_size = LWS_PACKET_SIZE; pos += pnr[i].ascii().length() + 1; names_ptr[pos - 1] = '\0'; } diff --git a/platform/android/java/res/drawable-hdpi/notify_panel_notification_icon_bg.png b/platform/android/java/res/drawable-hdpi/notify_panel_notification_icon_bg.png Binary files differindex 94bc406416..372b763ec5 100644 --- a/platform/android/java/res/drawable-hdpi/notify_panel_notification_icon_bg.png +++ b/platform/android/java/res/drawable-hdpi/notify_panel_notification_icon_bg.png diff --git a/platform/android/java/res/drawable-mdpi/notify_panel_notification_icon_bg.png b/platform/android/java/res/drawable-mdpi/notify_panel_notification_icon_bg.png Binary files differindex ef6fe4e836..c61c440636 100644 --- a/platform/android/java/res/drawable-mdpi/notify_panel_notification_icon_bg.png +++ b/platform/android/java/res/drawable-mdpi/notify_panel_notification_icon_bg.png diff --git a/platform/android/java/res/drawable/icon.png b/platform/android/java/res/drawable/icon.png Binary files differindex 29c4a7b8fc..6ad9b43117 100644 --- a/platform/android/java/res/drawable/icon.png +++ b/platform/android/java/res/drawable/icon.png diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index 90848e6a90..8a2d789dc5 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -32,6 +32,7 @@ package org.godotengine.godot; import android.R; import android.app.Activity; +import android.content.pm.ConfigurationInfo; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; @@ -246,9 +247,11 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } }; - public void onVideoInit(boolean use_gl2) { + public void onVideoInit() { - //mView = new GodotView(getApplication(),io,use_gl2); + boolean use_gl3 = getGLESVersionCode() >= 0x00030000; + + //mView = new GodotView(getApplication(),io,use_gl3); //setContentView(mView); layout = new FrameLayout(this); @@ -261,7 +264,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC // ...add to FrameLayout layout.addView(edittext); - mView = new GodotView(getApplication(), io, use_gl2, use_32_bits, this); + mView = new GodotView(getApplication(), io, use_gl3, use_32_bits, this); layout.addView(mView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); edittext.setView(mView); io.setEdit(edittext); @@ -338,6 +341,12 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC return Godot._self; } + public int getGLESVersionCode() { + ActivityManager am = (ActivityManager)Godot.getInstance().getSystemService(Context.ACTIVITY_SERVICE); + ConfigurationInfo deviceInfo = am.getDeviceConfigurationInfo(); + return deviceInfo.reqGlEsVersion; + } + private String[] getCommandLine() { InputStream is; try { diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 579c06f76b..e6240ad9e9 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -614,6 +614,7 @@ static jmethodID _hideKeyboard = 0; static jmethodID _setScreenOrientation = 0; static jmethodID _getUniqueID = 0; static jmethodID _getSystemDir = 0; +static jmethodID _getGLESVersionCode = 0; static jmethodID _playVideo = 0; static jmethodID _isVideoPlaying = 0; static jmethodID _pauseVideo = 0; @@ -685,6 +686,11 @@ static String _get_system_dir(int p_dir) { return String(env->GetStringUTFChars(s, NULL)); } +static int _get_gles_version_code() { + JNIEnv *env = ThreadAndroid::get_env(); + return env->CallIntMethod(_godot_instance, _getGLESVersionCode); +} + static void _hide_vk() { JNIEnv *env = ThreadAndroid::get_env(); @@ -764,9 +770,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en godot_io = gob; - _on_video_init = env->GetMethodID(cls, "onVideoInit", "(Z)V"); + _on_video_init = env->GetMethodID(cls, "onVideoInit", "()V"); _setKeepScreenOn = env->GetMethodID(cls, "setKeepScreenOn", "(Z)V"); _alertDialog = env->GetMethodID(cls, "alert", "(Ljava/lang/String;Ljava/lang/String;)V"); + _getGLESVersionCode = env->GetMethodID(cls, "getGLESVersionCode", "()I"); jclass clsio = env->FindClass("org/godotengine/godot/Godot"); if (cls) { @@ -800,16 +807,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en AudioDriverAndroid::setup(gob); } - os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_user_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _get_vk_height, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion); + os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_user_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _get_vk_height, _set_screen_orient, _get_unique_id, _get_system_dir, _get_gles_version_code, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion); os_android->set_need_reload_hooks(p_need_reload_hook); char wd[500]; getcwd(wd, 500); - //video driver is determined here, because once initialized, it can't be changed - // String vd = ProjectSettings::get_singleton()->get("display/driver"); - - env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean) true); + env->CallVoidMethod(_godot_instance, _on_video_init); } static void _initialize_java_modules() { diff --git a/platform/android/logo.png b/platform/android/logo.png Binary files differindex fcf684c026..ba2a0e366a 100644 --- a/platform/android/logo.png +++ b/platform/android/logo.png diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index fc41adeb76..9188f09f21 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -32,6 +32,7 @@ #include "core/io/file_access_buffered_fa.h" #include "core/project_settings.h" +#include "drivers/gles2/rasterizer_gles2.h" #include "drivers/gles3/rasterizer_gles3.h" #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" @@ -125,13 +126,20 @@ void OS_Android::set_opengl_extensions(const char *p_gl_extensions) { Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { - use_gl2 = p_video_driver != 1; + bool use_gl3 = get_gl_version_code_func() >= 0x00030000; + use_gl3 = use_gl3 && (GLOBAL_GET("rendering/quality/driver/driver_name") == "GLES3"); + use_gl2 = !use_gl3; if (gfx_init_func) gfx_init_func(gfx_init_ud, use_gl2); - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); + if (use_gl2) { + RasterizerGLES2::register_config(); + RasterizerGLES2::make_current(); + } else { + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); + } visual_server = memnew(VisualServerRaster); /* if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { @@ -684,7 +692,7 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) { return false; } -OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetUserDataDirFunc p_get_user_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) { +OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetUserDataDirFunc p_get_user_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, GetGLVersionCodeFunc p_get_gl_version_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) { use_apk_expansion = p_use_apk_expansion; default_videomode.width = 800; @@ -706,6 +714,7 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI get_screen_dpi_func = p_get_screen_dpi_func; get_unique_id_func = p_get_unique_id; get_system_dir_func = p_get_sdir_func; + get_gl_version_code_func = p_get_gl_version_func; video_play_func = p_video_play_func; video_is_playing_func = p_video_is_playing_func; diff --git a/platform/android/os_android.h b/platform/android/os_android.h index d2457e538d..ac901d4832 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -58,6 +58,7 @@ typedef void (*ShowVirtualKeyboardFunc)(const String &); typedef void (*HideVirtualKeyboardFunc)(); typedef void (*SetScreenOrientationFunc)(int); typedef String (*GetSystemDirFunc)(int); +typedef int (*GetGLVersionCodeFunc)(); typedef void (*VideoPlayFunc)(const String &); typedef bool (*VideoIsPlayingFunc)(); @@ -126,6 +127,7 @@ private: SetScreenOrientationFunc set_screen_orientation_func; GetUniqueIDFunc get_unique_id_func; GetSystemDirFunc get_system_dir_func; + GetGLVersionCodeFunc get_gl_version_code_func; VideoPlayFunc video_play_func; VideoIsPlayingFunc video_is_playing_func; @@ -239,7 +241,7 @@ public: void joy_connection_changed(int p_device, bool p_connected, String p_name); virtual bool _check_internal_feature_support(const String &p_feature); - OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetUserDataDirFunc p_get_user_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion); + OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetUserDataDirFunc p_get_user_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, GetGLVersionCodeFunc p_get_gl_version_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion); ~OS_Android(); }; diff --git a/platform/android/run_icon.png b/platform/android/run_icon.png Binary files differindex e53f8e9da5..b687c9ac31 100644 --- a/platform/android/run_icon.png +++ b/platform/android/run_icon.png diff --git a/platform/haiku/logo.png b/platform/haiku/logo.png Binary files differindex d5d98e4cc6..a2d8e242a6 100644 --- a/platform/haiku/logo.png +++ b/platform/haiku/logo.png diff --git a/platform/iphone/logo.png b/platform/iphone/logo.png Binary files differindex 8dd718524c..405b6f93ca 100644 --- a/platform/iphone/logo.png +++ b/platform/iphone/logo.png diff --git a/platform/javascript/logo.png b/platform/javascript/logo.png Binary files differindex ce911180ac..36832d93ba 100644 --- a/platform/javascript/logo.png +++ b/platform/javascript/logo.png diff --git a/platform/javascript/run_icon.png b/platform/javascript/run_icon.png Binary files differindex dedee6f479..574abb0150 100644 --- a/platform/javascript/run_icon.png +++ b/platform/javascript/run_icon.png diff --git a/platform/osx/logo.png b/platform/osx/logo.png Binary files differindex 93c6890e85..62086fc415 100644 --- a/platform/osx/logo.png +++ b/platform/osx/logo.png diff --git a/platform/server/logo.png b/platform/server/logo.png Binary files differindex 5e98ac26ec..8666ada9ca 100644 --- a/platform/server/logo.png +++ b/platform/server/logo.png diff --git a/platform/windows/logo.png b/platform/windows/logo.png Binary files differindex 4376abd563..f06b463850 100644 --- a/platform/windows/logo.png +++ b/platform/windows/logo.png diff --git a/platform/x11/logo.png b/platform/x11/logo.png Binary files differindex 1cc93b46ac..078654b757 100644 --- a/platform/x11/logo.png +++ b/platform/x11/logo.png diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index 329382c034..7d5360c0e4 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -158,8 +158,8 @@ void Joint2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint2D::set_exclude_nodes_from_collision); ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint2D::get_exclude_nodes_from_collision); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a"), "set_node_a", "get_node_a"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b"), "set_node_b", "get_node_b"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject2D"), "set_node_a", "get_node_a"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject2D"), "set_node_b", "get_node_b"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "bias", PROPERTY_HINT_RANGE, "0,0.9,0.001"), "set_bias", "get_bias"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_collision"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision"); } diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 4d6ebc81c3..81ed3c63c3 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -649,7 +649,7 @@ void Polygon2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-1440,1440,0.1"), "set_texture_rotation_degrees", "get_texture_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation"); ADD_GROUP("Skeleton", ""); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton"), "set_skeleton", "get_skeleton"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton"); ADD_GROUP("Invert", "invert_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enable"), "set_invert", "get_invert"); diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp index da764e032b..63c3d78dfd 100644 --- a/scene/2d/remote_transform_2d.cpp +++ b/scene/2d/remote_transform_2d.cpp @@ -201,7 +201,7 @@ void RemoteTransform2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_update_scale", "update_remote_scale"), &RemoteTransform2D::set_update_scale); ClassDB::bind_method(D_METHOD("get_update_scale"), &RemoteTransform2D::get_update_scale); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path"), "set_remote_node", "get_remote_node"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_remote_node", "get_remote_node"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_coordinates"), "set_use_global_coordinates", "get_use_global_coordinates"); ADD_GROUP("Update", "update_"); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 98275510d6..1d60037287 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -708,7 +708,7 @@ void TileMap::_erase_quadrant(Map<PosKey, Quadrant>::Element *Q) { rect_cache_dirty = true; } -void TileMap::_make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q) { +void TileMap::_make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q, bool update) { Quadrant &q = Q->get(); if (!q.dirty_list.in_list()) @@ -719,7 +719,10 @@ void TileMap::_make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q) { pending_update = true; if (!is_inside_tree()) return; - _update_dirty_quadrants(); + + if (update) { + _update_dirty_quadrants(); + } } void TileMap::set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose) { @@ -727,6 +730,11 @@ void TileMap::set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x, bool p_ set_cell(p_pos.x, p_pos.y, p_tile, p_flip_x, p_flip_y, p_transpose); } +void TileMap::set_celld(const Vector2 &p_pos, const Dictionary &p_data) { + + set_cell(p_pos.x, p_pos.y, p_data["id"], p_data["flip_h"], p_data["flip_y"], p_data["transpose"], p_data["auto_coord"]); +} + void TileMap::set_cell(int p_x, int p_y, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose, Vector2 p_autotile_coord) { PosKey pk(p_x, p_y); @@ -1016,8 +1024,9 @@ void TileMap::_recreate_quadrants() { } Q->get().cells.insert(E->key()); - _make_quadrant_dirty(Q); + _make_quadrant_dirty(Q, false); } + _update_dirty_quadrants(); } void TileMap::_clear_quadrants() { @@ -1612,6 +1621,7 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cell", "x", "y", "tile", "flip_x", "flip_y", "transpose", "autotile_coord"), &TileMap::set_cell, DEFVAL(false), DEFVAL(false), DEFVAL(false), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("set_cellv", "position", "tile", "flip_x", "flip_y", "transpose"), &TileMap::set_cellv, DEFVAL(false), DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_celld", "data"), &TileMap::set_celld); ClassDB::bind_method(D_METHOD("get_cell", "x", "y"), &TileMap::get_cell); ClassDB::bind_method(D_METHOD("get_cellv", "position"), &TileMap::get_cellv); ClassDB::bind_method(D_METHOD("is_cell_x_flipped", "x", "y"), &TileMap::is_cell_x_flipped); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 07947004b3..3ddb143f4a 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -188,7 +188,7 @@ private: Map<PosKey, Quadrant>::Element *_create_quadrant(const PosKey &p_qk); void _erase_quadrant(Map<PosKey, Quadrant>::Element *Q); - void _make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q); + void _make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q, bool update = true); void _recreate_quadrants(); void _clear_quadrants(); void _update_dirty_quadrants(); @@ -241,6 +241,7 @@ public: void set_cell_autotile_coord(int p_x, int p_y, const Vector2 &p_coord); Vector2 get_cell_autotile_coord(int p_x, int p_y) const; + void set_celld(const Vector2 &p_pos, const Dictionary &p_data); void set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false); int get_cellv(const Vector2 &p_pos) const; diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index 80bae911d4..e836a6154a 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -371,7 +371,7 @@ void MeshInstance::_bind_methods() { ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton"), "set_skeleton_path", "get_skeleton_path"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path"); } MeshInstance::MeshInstance() { diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp index b2d10006f7..c7a002e675 100644 --- a/scene/3d/physics_joint.cpp +++ b/scene/3d/physics_joint.cpp @@ -154,8 +154,8 @@ void Joint::_bind_methods() { ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint::set_exclude_nodes_from_collision); ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint::get_exclude_nodes_from_collision); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a"), "set_node_a", "get_node_a"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b"), "set_node_b", "get_node_b"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject"), "set_node_a", "get_node_a"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject"), "set_node_b", "get_node_b"); ADD_PROPERTY(PropertyInfo(Variant::INT, "solver/priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision/exclude_nodes"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision"); diff --git a/scene/3d/remote_transform.cpp b/scene/3d/remote_transform.cpp index afb85f7314..2156e24cd0 100644 --- a/scene/3d/remote_transform.cpp +++ b/scene/3d/remote_transform.cpp @@ -194,7 +194,7 @@ void RemoteTransform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_update_scale", "update_remote_scale"), &RemoteTransform::set_update_scale); ClassDB::bind_method(D_METHOD("get_update_scale"), &RemoteTransform::get_update_scale); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path"), "set_remote_node", "get_remote_node"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Spatial"), "set_remote_node", "get_remote_node"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_coordinates"), "set_use_global_coordinates", "get_use_global_coordinates"); ADD_GROUP("Update", "update_"); diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp new file mode 100644 index 0000000000..d3d2870c3f --- /dev/null +++ b/scene/animation/animation_blend_space_1d.cpp @@ -0,0 +1,294 @@ +#include "animation_blend_space_1d.h" + +void AnimationNodeBlendSpace1D::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 AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const { + if (property.name.begins_with("blend_point_")) { + String left = property.name.get_slicec('/', 0); + int idx = left.get_slicec('_', 2).to_int(); + if (idx >= blend_points_used) { + property.usage = 0; + } + } + AnimationRootNode::_validate_property(property); +} + +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); + ClassDB::bind_method(D_METHOD("get_blend_point_position", "point"), &AnimationNodeBlendSpace1D::get_blend_point_position); + ClassDB::bind_method(D_METHOD("set_blend_point_node", "point", "node"), &AnimationNodeBlendSpace1D::set_blend_point_node); + ClassDB::bind_method(D_METHOD("get_blend_point_node", "point"), &AnimationNodeBlendSpace1D::get_blend_point_node); + ClassDB::bind_method(D_METHOD("remove_blend_point", "point"), &AnimationNodeBlendSpace1D::remove_blend_point); + ClassDB::bind_method(D_METHOD("get_blend_point_count"), &AnimationNodeBlendSpace1D::get_blend_point_count); + + ClassDB::bind_method(D_METHOD("set_min_space", "min_space"), &AnimationNodeBlendSpace1D::set_min_space); + ClassDB::bind_method(D_METHOD("get_min_space"), &AnimationNodeBlendSpace1D::get_min_space); + + ClassDB::bind_method(D_METHOD("set_max_space", "max_space"), &AnimationNodeBlendSpace1D::set_max_space); + ClassDB::bind_method(D_METHOD("get_max_space"), &AnimationNodeBlendSpace1D::get_max_space); + + 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); + + 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::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::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) { + p_at_index = blend_points_used; + } else { + for (int i = blend_points_used - 1; i > p_at_index; i++) { + blend_points[i] = blend_points[i - 1]; + } + } + + 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_used++; +} + +void AnimationNodeBlendSpace1D::set_blend_point_position(int p_point, float p_position) { + ERR_FAIL_INDEX(p_point, blend_points_used); + + blend_points[p_point].position = p_position; +} + +void AnimationNodeBlendSpace1D::set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node) { + ERR_FAIL_INDEX(p_point, blend_points_used); + 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 = p_node; + blend_points[p_point].node->set_parent(this); + blend_points[p_point].node->set_tree(get_tree()); +} + +float AnimationNodeBlendSpace1D::get_blend_point_position(int p_point) const { + ERR_FAIL_INDEX_V(p_point, blend_points_used, 0); + return blend_points[p_point].position; +} + +Ref<AnimationRootNode> AnimationNodeBlendSpace1D::get_blend_point_node(int p_point) const { + ERR_FAIL_INDEX_V(p_point, blend_points_used, Ref<AnimationRootNode>()); + return blend_points[p_point].node; +} + +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); + + for (int i = p_point; i < blend_points_used - 1; i++) { + blend_points[i] = blend_points[i + 1]; + } + + blend_points_used--; +} + +int AnimationNodeBlendSpace1D::get_blend_point_count() const { + + return blend_points_used; +} + +void AnimationNodeBlendSpace1D::set_min_space(float p_min) { + min_space = p_min; + + if (min_space >= max_space) { + min_space = max_space - 1; + } +} + +float AnimationNodeBlendSpace1D::get_min_space() const { + return min_space; +} + +void AnimationNodeBlendSpace1D::set_max_space(float p_max) { + max_space = p_max; + + if (max_space <= min_space) { + max_space = min_space + 1; + } +} + +float AnimationNodeBlendSpace1D::get_max_space() const { + return max_space; +} + +void AnimationNodeBlendSpace1D::set_snap(float p_snap) { + snap = p_snap; +} + +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; +} + +String AnimationNodeBlendSpace1D::get_value_label() const { + return value_label; +} + +void AnimationNodeBlendSpace1D::_add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node) { + if (p_index == blend_points_used) { + add_blend_point(p_node, 0); + } else { + set_blend_point_node(p_index, p_node); + } +} + +float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) { + + if (blend_points_used == 0) { + 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); + } + + float weights[MAX_BLEND_POINTS] = {}; + + int point_lower = -1; + float pos_lower = 0.0; + int point_higher = -1; + float pos_higher = 0.0; + + // find the closest two points to blend between + for (int i = 0; i < blend_points_used; i++) { + + float pos = blend_points[i].position; + + if (pos <= blend_pos) { + if (point_lower == -1) { + point_lower = i; + pos_lower = pos; + } else if ((blend_pos - pos) < (blend_pos - pos_lower)) { + point_lower = i; + pos_lower = pos; + } + } else { + if (point_higher == -1) { + point_higher = i; + pos_higher = pos; + } else if ((pos - blend_pos) < (pos_higher - blend_pos)) { + point_higher = i; + pos_higher = pos; + } + } + } + + // fill in weights + + if (point_lower == -1) { + // we are on the left side, no other point to the left + // we just play the next point. + + weights[point_higher] = 1.0; + } else if (point_higher == -1) { + // we are on the right side, no other point to the right + // we just play the previous point + + weights[point_lower] = 1.0; + } else { + + // we are between two points. + // figure out weights, then blend the animations + + float distance_between_points = pos_higher - pos_lower; + + float current_pos_inbetween = blend_pos - pos_lower; + + float blend_percentage = current_pos_inbetween / distance_between_points; + + float blend_lower = 1.0 - blend_percentage; + float blend_higher = blend_percentage; + + weights[point_lower] = blend_lower; + weights[point_higher] = blend_higher; + } + + // actually blend the animations now + + 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); + + max_time_remaining = MAX(max_time_remaining, remaining); + } + + return max_time_remaining; +} + +String AnimationNodeBlendSpace1D::get_caption() const { + return "BlendSpace1D"; +} + +AnimationNodeBlendSpace1D::AnimationNodeBlendSpace1D() { + + blend_points_used = 0; + max_space = 1; + min_space = -1; + + snap = 0.1; + value_label = "value"; +} + +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()); + } +} diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h new file mode 100644 index 0000000000..774894ef4b --- /dev/null +++ b/scene/animation/animation_blend_space_1d.h @@ -0,0 +1,71 @@ +#ifndef ANIMATION_BLEND_SPACE_1D_H +#define ANIMATION_BLEND_SPACE_1D_H + +#include "scene/animation/animation_tree.h" + +class AnimationNodeBlendSpace1D : public AnimationRootNode { + GDCLASS(AnimationNodeBlendSpace1D, AnimationRootNode) + + enum { + MAX_BLEND_POINTS = 64 + }; + + struct BlendPoint { + Ref<AnimationRootNode> node; + float position; + }; + + BlendPoint blend_points[MAX_BLEND_POINTS]; + int blend_points_used; + + float blend_pos; + + float max_space; + float min_space; + + float snap; + + String value_label; + + void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node); + +protected: + virtual void _validate_property(PropertyInfo &property) const; + static void _bind_methods(); + +public: + + virtual void set_tree(AnimationTree *p_player); + + 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); + void set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node); + + float get_blend_point_position(int p_point) const; + Ref<AnimationRootNode> get_blend_point_node(int p_point) const; + void remove_blend_point(int p_point); + int get_blend_point_count() const; + + void set_min_space(float p_min); + float get_min_space() const; + + void set_max_space(float p_max); + float get_max_space() const; + + 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; + + AnimationNodeBlendSpace1D(); + ~AnimationNodeBlendSpace1D(); +}; + +#endif // ANIMATION_BLEND_SPACE_1D_H diff --git a/scene/animation/animation_blend_space.cpp b/scene/animation/animation_blend_space_2d.cpp index 44b2d980e2..82db647124 100644 --- a/scene/animation/animation_blend_space.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -1,7 +1,16 @@ -#include "animation_blend_space.h" +#include "animation_blend_space_2d.h" #include "math/delaunay.h" -void AnimationNodeBlendSpace::add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index) { +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::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()); @@ -10,7 +19,7 @@ void AnimationNodeBlendSpace::add_blend_point(const Ref<AnimationRootNode> &p_no if (p_at_index == -1 || p_at_index == blend_points_used) { p_at_index = blend_points_used; } else { - for (int i = blend_points_used; i > p_at_index; i--) { + for (int i = blend_points_used - 1; i > p_at_index; i--) { blend_points[i] = blend_points[i - 1]; } for (int i = 0; i < triangles.size(); i++) { @@ -25,7 +34,7 @@ void AnimationNodeBlendSpace::add_blend_point(const Ref<AnimationRootNode> &p_no blend_points[p_at_index].position = p_position; blend_points[p_at_index].node->set_parent(this); - blend_points[p_at_index].node->set_graph_player(get_graph_player()); + blend_points[p_at_index].node->set_tree(get_tree()); blend_points_used++; if (auto_triangles) { @@ -33,38 +42,38 @@ void AnimationNodeBlendSpace::add_blend_point(const Ref<AnimationRootNode> &p_no } } -void AnimationNodeBlendSpace::set_blend_point_position(int p_point, const Vector2 &p_position) { +void AnimationNodeBlendSpace2D::set_blend_point_position(int p_point, const Vector2 &p_position) { ERR_FAIL_INDEX(p_point, blend_points_used); blend_points[p_point].position = p_position; if (auto_triangles) { trianges_dirty = true; } } -void AnimationNodeBlendSpace::set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node) { +void AnimationNodeBlendSpace2D::set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node) { ERR_FAIL_INDEX(p_point, blend_points_used); 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_graph_player(NULL); + blend_points[p_point].node->set_tree(NULL); } blend_points[p_point].node = p_node; blend_points[p_point].node->set_parent(this); - blend_points[p_point].node->set_graph_player(get_graph_player()); + blend_points[p_point].node->set_tree(get_tree()); } -Vector2 AnimationNodeBlendSpace::get_blend_point_position(int p_point) const { +Vector2 AnimationNodeBlendSpace2D::get_blend_point_position(int p_point) const { ERR_FAIL_INDEX_V(p_point, blend_points_used, Vector2()); return blend_points[p_point].position; } -Ref<AnimationRootNode> AnimationNodeBlendSpace::get_blend_point_node(int p_point) const { +Ref<AnimationRootNode> AnimationNodeBlendSpace2D::get_blend_point_node(int p_point) const { ERR_FAIL_INDEX_V(p_point, blend_points_used, Ref<AnimationRootNode>()); return blend_points[p_point].node; } -void AnimationNodeBlendSpace::remove_blend_point(int p_point) { +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_graph_player(NULL); + blend_points[p_point].node->set_tree(NULL); for (int i = 0; i < triangles.size(); i++) { bool erase = false; @@ -89,12 +98,12 @@ void AnimationNodeBlendSpace::remove_blend_point(int p_point) { blend_points_used--; } -int AnimationNodeBlendSpace::get_blend_point_count() const { +int AnimationNodeBlendSpace2D::get_blend_point_count() const { return blend_points_used; } -bool AnimationNodeBlendSpace::has_triangle(int p_x, int p_y, int p_z) const { +bool AnimationNodeBlendSpace2D::has_triangle(int p_x, int p_y, int p_z) const { ERR_FAIL_INDEX_V(p_x, blend_points_used, false); ERR_FAIL_INDEX_V(p_y, blend_points_used, false); @@ -123,7 +132,7 @@ bool AnimationNodeBlendSpace::has_triangle(int p_x, int p_y, int p_z) const { return false; } -void AnimationNodeBlendSpace::add_triangle(int p_x, int p_y, int p_z, int p_at_index) { +void AnimationNodeBlendSpace2D::add_triangle(int p_x, int p_y, int p_z, int p_at_index) { ERR_FAIL_INDEX(p_x, blend_points_used); ERR_FAIL_INDEX(p_y, blend_points_used); @@ -156,7 +165,7 @@ void AnimationNodeBlendSpace::add_triangle(int p_x, int p_y, int p_z, int p_at_i triangles.insert(p_at_index, t); } } -int AnimationNodeBlendSpace::get_triangle_point(int p_triangle, int p_point) { +int AnimationNodeBlendSpace2D::get_triangle_point(int p_triangle, int p_point) { _update_triangles(); @@ -164,17 +173,17 @@ int AnimationNodeBlendSpace::get_triangle_point(int p_triangle, int p_point) { ERR_FAIL_INDEX_V(p_triangle, triangles.size(), -1); return triangles[p_triangle].points[p_point]; } -void AnimationNodeBlendSpace::remove_triangle(int p_triangle) { +void AnimationNodeBlendSpace2D::remove_triangle(int p_triangle) { ERR_FAIL_INDEX(p_triangle, triangles.size()); triangles.remove(p_triangle); } -int AnimationNodeBlendSpace::get_triangle_count() const { +int AnimationNodeBlendSpace2D::get_triangle_count() const { return triangles.size(); } -void AnimationNodeBlendSpace::set_min_space(const Vector2 &p_min) { +void AnimationNodeBlendSpace2D::set_min_space(const Vector2 &p_min) { min_space = p_min; if (min_space.x >= max_space.x) { @@ -184,11 +193,11 @@ void AnimationNodeBlendSpace::set_min_space(const Vector2 &p_min) { min_space.y = max_space.y - 1; } } -Vector2 AnimationNodeBlendSpace::get_min_space() const { +Vector2 AnimationNodeBlendSpace2D::get_min_space() const { return min_space; } -void AnimationNodeBlendSpace::set_max_space(const Vector2 &p_max) { +void AnimationNodeBlendSpace2D::set_max_space(const Vector2 &p_max) { max_space = p_max; if (max_space.x <= min_space.x) { @@ -198,39 +207,39 @@ void AnimationNodeBlendSpace::set_max_space(const Vector2 &p_max) { max_space.y = min_space.y + 1; } } -Vector2 AnimationNodeBlendSpace::get_max_space() const { +Vector2 AnimationNodeBlendSpace2D::get_max_space() const { return max_space; } -void AnimationNodeBlendSpace::set_snap(const Vector2 &p_snap) { +void AnimationNodeBlendSpace2D::set_snap(const Vector2 &p_snap) { snap = p_snap; } -Vector2 AnimationNodeBlendSpace::get_snap() const { +Vector2 AnimationNodeBlendSpace2D::get_snap() const { return snap; } -void AnimationNodeBlendSpace::set_blend_pos(const Vector2 &p_pos) { +void AnimationNodeBlendSpace2D::set_blend_position(const Vector2 &p_pos) { blend_pos = p_pos; } -Vector2 AnimationNodeBlendSpace::get_blend_pos() const { +Vector2 AnimationNodeBlendSpace2D::get_blend_position() const { return blend_pos; } -void AnimationNodeBlendSpace::set_x_label(const String &p_label) { +void AnimationNodeBlendSpace2D::set_x_label(const String &p_label) { x_label = p_label; } -String AnimationNodeBlendSpace::get_x_label() const { +String AnimationNodeBlendSpace2D::get_x_label() const { return x_label; } -void AnimationNodeBlendSpace::set_y_label(const String &p_label) { +void AnimationNodeBlendSpace2D::set_y_label(const String &p_label) { y_label = p_label; } -String AnimationNodeBlendSpace::get_y_label() const { +String AnimationNodeBlendSpace2D::get_y_label() const { return y_label; } -void AnimationNodeBlendSpace::_add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node) { +void AnimationNodeBlendSpace2D::_add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node) { if (p_index == blend_points_used) { add_blend_point(p_node, Vector2()); } else { @@ -238,7 +247,7 @@ void AnimationNodeBlendSpace::_add_blend_point(int p_index, const Ref<AnimationR } } -void AnimationNodeBlendSpace::_set_triangles(const Vector<int> &p_triangles) { +void AnimationNodeBlendSpace2D::_set_triangles(const Vector<int> &p_triangles) { if (auto_triangles) return; @@ -248,7 +257,7 @@ void AnimationNodeBlendSpace::_set_triangles(const Vector<int> &p_triangles) { } } -Vector<int> AnimationNodeBlendSpace::_get_triangles() const { +Vector<int> AnimationNodeBlendSpace2D::_get_triangles() const { Vector<int> t; if (auto_triangles && trianges_dirty) @@ -263,7 +272,7 @@ Vector<int> AnimationNodeBlendSpace::_get_triangles() const { return t; } -void AnimationNodeBlendSpace::_update_triangles() { +void AnimationNodeBlendSpace2D::_update_triangles() { if (!auto_triangles || !trianges_dirty) return; @@ -286,7 +295,7 @@ void AnimationNodeBlendSpace::_update_triangles() { } } -Vector2 AnimationNodeBlendSpace::get_closest_point(const Vector2 &p_point) { +Vector2 AnimationNodeBlendSpace2D::get_closest_point(const Vector2 &p_point) { _update_triangles(); @@ -323,7 +332,7 @@ Vector2 AnimationNodeBlendSpace::get_closest_point(const Vector2 &p_point) { return best_point; } -void AnimationNodeBlendSpace::_blend_triangle(const Vector2 &p_pos, const Vector2 *p_points, float *r_weights) { +void AnimationNodeBlendSpace2D::_blend_triangle(const Vector2 &p_pos, const Vector2 *p_points, float *r_weights) { if (p_pos.distance_squared_to(p_points[0]) < CMP_EPSILON2) { r_weights[0] = 1; @@ -369,7 +378,7 @@ void AnimationNodeBlendSpace::_blend_triangle(const Vector2 &p_pos, const Vector r_weights[2] = w; } -float AnimationNodeBlendSpace::process(float p_time, bool p_seek) { +float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { _update_triangles(); @@ -453,11 +462,11 @@ float AnimationNodeBlendSpace::process(float p_time, bool p_seek) { return mind; } -String AnimationNodeBlendSpace::get_caption() const { - return "BlendSpace"; +String AnimationNodeBlendSpace2D::get_caption() const { + return "BlendSpace2D"; } -void AnimationNodeBlendSpace::_validate_property(PropertyInfo &property) const { +void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &property) const { if (property.name.begins_with("blend_point_")) { String left = property.name.get_slicec('/', 0); int idx = left.get_slicec('_', 2).to_int(); @@ -468,57 +477,57 @@ void AnimationNodeBlendSpace::_validate_property(PropertyInfo &property) const { AnimationRootNode::_validate_property(property); } -void AnimationNodeBlendSpace::set_auto_triangles(bool p_enable) { +void AnimationNodeBlendSpace2D::set_auto_triangles(bool p_enable) { auto_triangles = p_enable; if (auto_triangles) { trianges_dirty = true; } } -bool AnimationNodeBlendSpace::get_auto_triangles() const { +bool AnimationNodeBlendSpace2D::get_auto_triangles() const { return auto_triangles; } -void AnimationNodeBlendSpace::_bind_methods() { +void AnimationNodeBlendSpace2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace::add_blend_point, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace::set_blend_point_position); - ClassDB::bind_method(D_METHOD("get_blend_point_position", "point"), &AnimationNodeBlendSpace::get_blend_point_position); - ClassDB::bind_method(D_METHOD("set_blend_point_node", "point", "node"), &AnimationNodeBlendSpace::set_blend_point_node); - ClassDB::bind_method(D_METHOD("get_blend_point_node", "point"), &AnimationNodeBlendSpace::get_blend_point_node); - ClassDB::bind_method(D_METHOD("remove_blend_point", "point"), &AnimationNodeBlendSpace::remove_blend_point); - ClassDB::bind_method(D_METHOD("get_blend_point_count"), &AnimationNodeBlendSpace::get_blend_point_count); + ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace2D::set_blend_point_position); + ClassDB::bind_method(D_METHOD("get_blend_point_position", "point"), &AnimationNodeBlendSpace2D::get_blend_point_position); + ClassDB::bind_method(D_METHOD("set_blend_point_node", "point", "node"), &AnimationNodeBlendSpace2D::set_blend_point_node); + ClassDB::bind_method(D_METHOD("get_blend_point_node", "point"), &AnimationNodeBlendSpace2D::get_blend_point_node); + ClassDB::bind_method(D_METHOD("remove_blend_point", "point"), &AnimationNodeBlendSpace2D::remove_blend_point); + ClassDB::bind_method(D_METHOD("get_blend_point_count"), &AnimationNodeBlendSpace2D::get_blend_point_count); - ClassDB::bind_method(D_METHOD("add_triangle", "x", "y", "z", "at_index"), &AnimationNodeBlendSpace::add_triangle, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("get_triangle_point", "triangle", "point"), &AnimationNodeBlendSpace::get_triangle_point); - ClassDB::bind_method(D_METHOD("remove_triangle", "triangle"), &AnimationNodeBlendSpace::remove_triangle); - ClassDB::bind_method(D_METHOD("get_triangle_count"), &AnimationNodeBlendSpace::get_triangle_count); + ClassDB::bind_method(D_METHOD("add_triangle", "x", "y", "z", "at_index"), &AnimationNodeBlendSpace2D::add_triangle, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("get_triangle_point", "triangle", "point"), &AnimationNodeBlendSpace2D::get_triangle_point); + ClassDB::bind_method(D_METHOD("remove_triangle", "triangle"), &AnimationNodeBlendSpace2D::remove_triangle); + ClassDB::bind_method(D_METHOD("get_triangle_count"), &AnimationNodeBlendSpace2D::get_triangle_count); - ClassDB::bind_method(D_METHOD("set_min_space", "min_space"), &AnimationNodeBlendSpace::set_min_space); - ClassDB::bind_method(D_METHOD("get_min_space"), &AnimationNodeBlendSpace::get_min_space); + ClassDB::bind_method(D_METHOD("set_min_space", "min_space"), &AnimationNodeBlendSpace2D::set_min_space); + ClassDB::bind_method(D_METHOD("get_min_space"), &AnimationNodeBlendSpace2D::get_min_space); - ClassDB::bind_method(D_METHOD("set_max_space", "max_space"), &AnimationNodeBlendSpace::set_max_space); - ClassDB::bind_method(D_METHOD("get_max_space"), &AnimationNodeBlendSpace::get_max_space); + ClassDB::bind_method(D_METHOD("set_max_space", "max_space"), &AnimationNodeBlendSpace2D::set_max_space); + ClassDB::bind_method(D_METHOD("get_max_space"), &AnimationNodeBlendSpace2D::get_max_space); - ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace::set_snap); - ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace::get_snap); + 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_pos", "pos"), &AnimationNodeBlendSpace::set_blend_pos); - ClassDB::bind_method(D_METHOD("get_blend_pos"), &AnimationNodeBlendSpace::get_blend_pos); + 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"), &AnimationNodeBlendSpace::set_x_label); - ClassDB::bind_method(D_METHOD("get_x_label"), &AnimationNodeBlendSpace::get_x_label); + 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); - ClassDB::bind_method(D_METHOD("set_y_label", "text"), &AnimationNodeBlendSpace::set_y_label); - ClassDB::bind_method(D_METHOD("get_y_label"), &AnimationNodeBlendSpace::get_y_label); + ClassDB::bind_method(D_METHOD("set_y_label", "text"), &AnimationNodeBlendSpace2D::set_y_label); + ClassDB::bind_method(D_METHOD("get_y_label"), &AnimationNodeBlendSpace2D::get_y_label); - ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace::_add_blend_point); + ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace2D::_add_blend_point); - ClassDB::bind_method(D_METHOD("_set_triangles", "triangles"), &AnimationNodeBlendSpace::_set_triangles); - ClassDB::bind_method(D_METHOD("_get_triangles"), &AnimationNodeBlendSpace::_get_triangles); + ClassDB::bind_method(D_METHOD("_set_triangles", "triangles"), &AnimationNodeBlendSpace2D::_set_triangles); + ClassDB::bind_method(D_METHOD("_get_triangles"), &AnimationNodeBlendSpace2D::_get_triangles); - ClassDB::bind_method(D_METHOD("set_auto_triangles", "enable"), &AnimationNodeBlendSpace::set_auto_triangles); - ClassDB::bind_method(D_METHOD("get_auto_triangles"), &AnimationNodeBlendSpace::get_auto_triangles); + 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); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_auto_triangles", "get_auto_triangles"); @@ -532,12 +541,12 @@ void AnimationNodeBlendSpace::_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_pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_blend_pos", "get_blend_pos"); + 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"); } -AnimationNodeBlendSpace::AnimationNodeBlendSpace() { +AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() { auto_triangles = true; blend_points_used = 0; @@ -549,10 +558,10 @@ AnimationNodeBlendSpace::AnimationNodeBlendSpace() { trianges_dirty = false; } -AnimationNodeBlendSpace::~AnimationNodeBlendSpace() { +AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() { for (int i = 0; i < blend_points_used; i++) { blend_points[i].node->set_parent(this); - blend_points[i].node->set_graph_player(get_graph_player()); + blend_points[i].node->set_tree(get_tree()); } } diff --git a/scene/animation/animation_blend_space.h b/scene/animation/animation_blend_space_2d.h index 3eda3d2d39..4778299df1 100644 --- a/scene/animation/animation_blend_space.h +++ b/scene/animation/animation_blend_space_2d.h @@ -1,10 +1,10 @@ -#ifndef ANIMATION_BLEND_SPACE_H -#define ANIMATION_BLEND_SPACE_H +#ifndef ANIMATION_BLEND_SPACE_2D_H +#define ANIMATION_BLEND_SPACE_2D_H -#include "scene/animation/animation_graph_player.h" +#include "scene/animation/animation_tree.h" -class AnimationNodeBlendSpace : public AnimationRootNode { - GDCLASS(AnimationNodeBlendSpace, AnimationRootNode) +class AnimationNodeBlendSpace2D : public AnimationRootNode { + GDCLASS(AnimationNodeBlendSpace2D, AnimationRootNode) enum { MAX_BLEND_POINTS = 64 @@ -47,6 +47,9 @@ protected: static void _bind_methods(); public: + + virtual void set_tree(AnimationTree *p_player); + 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); void set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node); @@ -70,8 +73,8 @@ public: void set_snap(const Vector2 &p_snap); Vector2 get_snap() const; - void set_blend_pos(const Vector2 &p_pos); - Vector2 get_blend_pos() 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; @@ -79,16 +82,16 @@ public: void set_y_label(const String &p_label); String get_y_label() const; - float process(float p_time, bool p_seek); - String get_caption() const; + virtual float process(float p_time, bool p_seek); + virtual String get_caption() const; Vector2 get_closest_point(const Vector2 &p_point); void set_auto_triangles(bool p_enable); bool get_auto_triangles() const; - AnimationNodeBlendSpace(); - ~AnimationNodeBlendSpace(); + AnimationNodeBlendSpace2D(); + ~AnimationNodeBlendSpace2D(); }; -#endif // ANIMATION_BLEND_SPACE_H +#endif // ANIMATION_BLEND_SPACE_2D_H diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index ced0cbbbba..946a1246ff 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -16,7 +16,7 @@ float AnimationNodeAnimation::get_playback_time() const { void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const { if (property.name == "animation") { - AnimationGraphPlayer *gp = get_graph_player(); + 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) { @@ -311,33 +311,33 @@ AnimationNodeOneShot::AnimationNodeOneShot() { //////////////////////////////////////////////// -void AnimationNodeAdd::set_amount(float p_amount) { +void AnimationNodeAdd2::set_amount(float p_amount) { amount = p_amount; } -float AnimationNodeAdd::get_amount() const { +float AnimationNodeAdd2::get_amount() const { return amount; } -String AnimationNodeAdd::get_caption() const { - return "Add"; +String AnimationNodeAdd2::get_caption() const { + return "Add2"; } -void AnimationNodeAdd::set_use_sync(bool p_sync) { +void AnimationNodeAdd2::set_use_sync(bool p_sync) { sync = p_sync; } -bool AnimationNodeAdd::is_using_sync() const { +bool AnimationNodeAdd2::is_using_sync() const { return sync; } -bool AnimationNodeAdd::has_filter() const { +bool AnimationNodeAdd2::has_filter() const { return true; } -float AnimationNodeAdd::process(float p_time, bool p_seek) { +float AnimationNodeAdd2::process(float p_time, bool p_seek) { 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); @@ -345,19 +345,19 @@ float AnimationNodeAdd::process(float p_time, bool p_seek) { return rem0; } -void AnimationNodeAdd::_bind_methods() { +void AnimationNodeAdd2::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeAdd::set_amount); - ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeAdd::get_amount); + 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"), &AnimationNodeAdd::set_use_sync); - ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd::is_using_sync); + 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"); } -AnimationNodeAdd::AnimationNodeAdd() { +AnimationNodeAdd2::AnimationNodeAdd2() { add_input("in"); add_input("add"); @@ -365,6 +365,63 @@ AnimationNodeAdd::AnimationNodeAdd() { sync = false; } +//////////////////////////////////////////////// + +void AnimationNodeAdd3::set_amount(float p_amount) { + amount = p_amount; +} + +float AnimationNodeAdd3::get_amount() const { + return amount; +} + +String AnimationNodeAdd3::get_caption() const { + return "Add3"; +} +void AnimationNodeAdd3::set_use_sync(bool p_sync) { + + sync = p_sync; +} + +bool AnimationNodeAdd3::is_using_sync() const { + + return sync; +} + +bool AnimationNodeAdd3::has_filter() const { + + return true; +} + +float AnimationNodeAdd3::process(float p_time, bool p_seek) { + + 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); + + return rem0; +} + +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_input("-add"); + add_input("in"); + add_input("+add"); + amount = 0; + sync = false; +} ///////////////////////////////////////////// void AnimationNodeBlend2::set_amount(float p_amount) { @@ -762,13 +819,13 @@ void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNod 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_graph_player() != NULL); + 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_graph_player(get_graph_player()); + p_node->set_tree(get_tree()); emit_changed(); } @@ -804,7 +861,7 @@ void AnimationNodeBlendTree::remove_node(const StringName &p_name) { node->set_input_connection(i, StringName()); } node->set_parent(NULL); - node->set_graph_player(NULL); + node->set_tree(NULL); } nodes.erase(p_name); @@ -965,13 +1022,13 @@ Vector2 AnimationNodeBlendTree::get_graph_offset() const { return graph_offset; } -void AnimationNodeBlendTree::set_graph_player(AnimationGraphPlayer *p_player) { +void AnimationNodeBlendTree::set_tree(AnimationTree *p_player) { - AnimationNode::set_graph_player(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_graph_player(p_player); + node->set_tree(p_player); } } @@ -1107,6 +1164,6 @@ AnimationNodeBlendTree::~AnimationNodeBlendTree() { for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { E->get()->set_parent(NULL); - E->get()->set_graph_player(NULL); + E->get()->set_tree(NULL); } } diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index 7623fd3e57..e86cc2e823 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -1,7 +1,7 @@ #ifndef ANIMATION_BLEND_TREE_H #define ANIMATION_BLEND_TREE_H -#include "scene/animation/animation_graph_player.h" +#include "scene/animation/animation_tree.h" class AnimationNodeAnimation : public AnimationRootNode { @@ -94,8 +94,8 @@ public: VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode) -class AnimationNodeAdd : public AnimationNode { - GDCLASS(AnimationNodeAdd, AnimationNode); +class AnimationNodeAdd2 : public AnimationNode { + GDCLASS(AnimationNodeAdd2, AnimationNode); float amount; bool sync; @@ -115,7 +115,31 @@ public: virtual bool has_filter() const; virtual float process(float p_time, bool p_seek); - AnimationNodeAdd(); + AnimationNodeAdd2(); +}; + +class AnimationNodeAdd3 : public AnimationNode { + GDCLASS(AnimationNodeAdd3, AnimationNode); + + float amount; + bool sync; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const; + + void set_amount(float p_amount); + float get_amount() const; + + void set_use_sync(bool p_sync); + bool is_using_sync() const; + + virtual bool has_filter() const; + virtual float process(float p_time, bool p_seek); + + AnimationNodeAdd3(); }; class AnimationNodeBlend2 : public AnimationNode { @@ -318,7 +342,7 @@ public: void set_graph_offset(const Vector2 &p_graph_offset); Vector2 get_graph_offset() const; - virtual void set_graph_player(AnimationGraphPlayer *p_player); + virtual void set_tree(AnimationTree *p_player); AnimationNodeBlendTree(); ~AnimationNodeBlendTree(); }; diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp new file mode 100644 index 0000000000..c5ad980806 --- /dev/null +++ b/scene/animation/animation_node_state_machine.cpp @@ -0,0 +1,790 @@ +#include "animation_node_state_machine.h" + +///////////////////////////////////////////////// + +void AnimationNodeStateMachineTransition::set_switch_mode(SwitchMode p_mode) { + + switch_mode = p_mode; +} + +AnimationNodeStateMachineTransition::SwitchMode AnimationNodeStateMachineTransition::get_switch_mode() const { + + return switch_mode; +} + +void AnimationNodeStateMachineTransition::set_auto_advance(bool p_enable) { + auto_advance = p_enable; +} + +bool AnimationNodeStateMachineTransition::has_auto_advance() const { + return auto_advance; +} + +void AnimationNodeStateMachineTransition::set_xfade_time(float p_xfade) { + + ERR_FAIL_COND(p_xfade < 0); + xfade = p_xfade; + emit_changed(); +} + +float AnimationNodeStateMachineTransition::get_xfade_time() const { + return xfade; +} + +void AnimationNodeStateMachineTransition::set_disabled(bool p_disabled) { + disabled = p_disabled; + emit_changed(); +} + +bool AnimationNodeStateMachineTransition::is_disabled() const { + return disabled; +} + +void AnimationNodeStateMachineTransition::set_priority(int p_priority) { + priority = p_priority; + emit_changed(); +} + +int AnimationNodeStateMachineTransition::get_priority() const { + return priority; +} + +void AnimationNodeStateMachineTransition::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_switch_mode", "mode"), &AnimationNodeStateMachineTransition::set_switch_mode); + ClassDB::bind_method(D_METHOD("get_switch_mode"), &AnimationNodeStateMachineTransition::get_switch_mode); + + ClassDB::bind_method(D_METHOD("set_auto_advance", "auto_advance"), &AnimationNodeStateMachineTransition::set_auto_advance); + ClassDB::bind_method(D_METHOD("has_auto_advance"), &AnimationNodeStateMachineTransition::has_auto_advance); + + ClassDB::bind_method(D_METHOD("set_xfade_time", "secs"), &AnimationNodeStateMachineTransition::set_xfade_time); + ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeStateMachineTransition::get_xfade_time); + + ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &AnimationNodeStateMachineTransition::set_disabled); + ClassDB::bind_method(D_METHOD("is_disabled"), &AnimationNodeStateMachineTransition::is_disabled); + + ClassDB::bind_method(D_METHOD("set_priority", "priority"), &AnimationNodeStateMachineTransition::set_priority); + ClassDB::bind_method(D_METHOD("get_priority"), &AnimationNodeStateMachineTransition::get_priority); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,AtEnd"), "set_switch_mode", "get_switch_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_advance"), "set_auto_advance", "has_auto_advance"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01"), "set_xfade_time", "get_xfade_time"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); + + BIND_CONSTANT(SWITCH_MODE_IMMEDIATE); + BIND_CONSTANT(SWITCH_MODE_SYNC); + BIND_CONSTANT(SWITCH_MODE_AT_END); +} + +AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() { + + switch_mode = SWITCH_MODE_IMMEDIATE; + auto_advance = false; + xfade = 0; + disabled = false; + priority = 1; +} + +/////////////////////////////////////////////////////// +void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<AnimationNode> p_node) { + + ERR_FAIL_COND(states.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(String(p_name).find("/") != -1); + states[p_name] = p_node; + + p_node->set_parent(this); + p_node->set_tree(get_tree()); + + emit_changed(); +} + +Ref<AnimationNode> AnimationNodeStateMachine::get_node(const StringName &p_name) const { + + ERR_FAIL_COND_V(!states.has(p_name), Ref<AnimationNode>()); + + return states[p_name]; +} + +StringName AnimationNodeStateMachine::get_node_name(const Ref<AnimationNode> &p_node) const { + for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) { + if (E->get() == p_node) { + return E->key(); + } + } + + ERR_FAIL_V(StringName()); +} + +bool AnimationNodeStateMachine::has_node(const StringName &p_name) const { + return states.has(p_name); +} +void AnimationNodeStateMachine::remove_node(const StringName &p_name) { + + ERR_FAIL_COND(!states.has(p_name)); + + { + //erase node connections + Ref<AnimationNode> node = states[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); + } + + states.erase(p_name); + path.erase(p_name); + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == p_name || transitions[i].to == p_name) { + transitions.remove(i); + i--; + } + } + + if (start_node == p_name) { + start_node = StringName(); + } + + if (end_node == p_name) { + end_node = StringName(); + } + + if (playing && current == p_name) { + stop(); + } + emit_changed(); +} + +void AnimationNodeStateMachine::rename_node(const StringName &p_name, const StringName &p_new_name) { + + ERR_FAIL_COND(!states.has(p_name)); + ERR_FAIL_COND(states.has(p_new_name)); + + states[p_new_name] = states[p_name]; + states.erase(p_name); + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == p_name) { + transitions[i].from = p_new_name; + } + + if (transitions[i].to == p_name) { + transitions[i].to = p_new_name; + } + } + + if (start_node == p_name) { + start_node = p_new_name; + } + + if (end_node == p_name) { + end_node = p_new_name; + } + + if (playing && current == p_name) { + current = p_new_name; + } + + path.clear(); //clear path +} + +void AnimationNodeStateMachine::get_node_list(List<StringName> *r_nodes) const { + + List<StringName> nodes; + for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) { + nodes.push_back(E->key()); + } + nodes.sort_custom<StringName::AlphCompare>(); + + for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { + r_nodes->push_back(E->get()); + } +} + +bool AnimationNodeStateMachine::has_transition(const StringName &p_from, const StringName &p_to) const { + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == p_from && transitions[i].to == p_to) + return true; + } + return false; +} + +int AnimationNodeStateMachine::find_transition(const StringName &p_from, const StringName &p_to) const { + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == p_from && transitions[i].to == p_to) + return i; + } + return -1; +} + +void AnimationNodeStateMachine::add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition) { + + ERR_FAIL_COND(p_from == p_to); + ERR_FAIL_COND(!states.has(p_from)); + ERR_FAIL_COND(!states.has(p_to)); + ERR_FAIL_COND(p_transition.is_null()); + + for (int i = 0; i < transitions.size(); i++) { + ERR_FAIL_COND(transitions[i].from == p_from && transitions[i].to == p_to); + } + + Transition tr; + tr.from = p_from; + tr.to = p_to; + tr.transition = p_transition; + + transitions.push_back(tr); +} + +Ref<AnimationNodeStateMachineTransition> AnimationNodeStateMachine::get_transition(int p_transition) const { + ERR_FAIL_INDEX_V(p_transition, transitions.size(), Ref<AnimationNodeStateMachineTransition>()); + return transitions[p_transition].transition; +} +StringName AnimationNodeStateMachine::get_transition_from(int p_transition) const { + + ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName()); + return transitions[p_transition].from; +} +StringName AnimationNodeStateMachine::get_transition_to(int p_transition) const { + + ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName()); + return transitions[p_transition].to; +} + +int AnimationNodeStateMachine::get_transition_count() const { + + return transitions.size(); +} +void AnimationNodeStateMachine::remove_transition(const StringName &p_from, const StringName &p_to) { + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == p_from && transitions[i].to == p_to) { + transitions.remove(i); + return; + } + } + + if (playing) { + path.clear(); + } +} + +void AnimationNodeStateMachine::remove_transition_by_index(int p_transition) { + + transitions.remove(p_transition); + if (playing) { + path.clear(); + } +} + +void AnimationNodeStateMachine::set_start_node(const StringName &p_node) { + + ERR_FAIL_COND(p_node != StringName() && !states.has(p_node)); + start_node = p_node; +} + +String AnimationNodeStateMachine::get_start_node() const { + + return start_node; +} + +void AnimationNodeStateMachine::set_end_node(const StringName &p_node) { + + ERR_FAIL_COND(p_node != StringName() && !states.has(p_node)); + end_node = p_node; +} + +String AnimationNodeStateMachine::get_end_node() const { + + return end_node; +} + +void AnimationNodeStateMachine::set_graph_offset(const Vector2 &p_offset) { + graph_offset = p_offset; +} + +Vector2 AnimationNodeStateMachine::get_graph_offset() const { + return graph_offset; +} + +float AnimationNodeStateMachine::process(float p_time, bool p_seek) { + + //if not playing and it can restart, then restart + if (!playing) { + if (start_node) { + start(start_node); + } else { + return 0; + } + } + + bool do_start = (p_seek && p_time == 0) || play_start || current == StringName(); + + if (do_start) { + + if (start_node != StringName() && p_seek && p_time == 0) { + current = start_node; + } + + len_current = blend_node(states[current], 0, true, 1.0, FILTER_IGNORE, false); + pos_current = 0; + loops_current = 0; + play_start = false; + } + + float fade_blend = 1.0; + + if (fading_from != StringName()) { + + if (!p_seek) { + fading_pos += p_time; + } + fade_blend = MIN(1.0, fading_pos / fading_time); + if (fade_blend >= 1.0) { + fading_from = StringName(); + } + } + + float rem = blend_node(states[current], p_time, p_seek, fade_blend, FILTER_IGNORE, false); + + if (fading_from != StringName()) { + + blend_node(states[fading_from], p_time, p_seek, 1.0 - fade_blend, FILTER_IGNORE, false); + } + + //guess playback position + if (rem > len_current) { // weird but ok + len_current = rem; + } + + { //advance and loop check + + float next_pos = len_current - rem; + + if (next_pos < pos_current) { + loops_current++; + } + pos_current = next_pos; //looped + } + + //find next + StringName next; + float next_xfade = 0; + AnimationNodeStateMachineTransition::SwitchMode switch_mode = AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE; + + if (path.size()) { + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == current && transitions[i].to == path[0]) { + next_xfade = transitions[i].transition->get_xfade_time(); + switch_mode = transitions[i].transition->get_switch_mode(); + next = path[0]; + } + } + } else { + float priority_best = 1e20; + int auto_advance_to = -1; + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == current && transitions[i].transition->has_auto_advance()) { + + if (transitions[i].transition->get_priority() < priority_best) { + auto_advance_to = i; + } + } + } + + if (auto_advance_to != -1) { + next = transitions[auto_advance_to].to; + next_xfade = transitions[auto_advance_to].transition->get_xfade_time(); + switch_mode = transitions[auto_advance_to].transition->get_switch_mode(); + } + } + + //if next, see when to transition + if (next != StringName()) { + + bool goto_next = false; + + if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE) { + goto_next = fading_from == StringName(); + } else { + goto_next = next_xfade >= (len_current - pos_current) || loops_current > 0; + if (loops_current > 0) { + next_xfade = 0; + } + } + + if (goto_next) { //loops should be used because fade time may be too small or zero and animation may have looped + + if (next_xfade) { + //time to fade, baby + fading_from = current; + fading_time = next_xfade; + fading_pos = 0; + } else { + fading_from = StringName(); + fading_pos = 0; + } + + if (path.size()) { //if it came from path, remove path + path.remove(0); + } + current = next; + if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) { + len_current = blend_node(states[current], 0, true, 0, FILTER_IGNORE, false); + pos_current = MIN(pos_current, len_current); + blend_node(states[current], pos_current, true, 0, FILTER_IGNORE, false); + + } else { + len_current = blend_node(states[current], 0, true, 0, FILTER_IGNORE, false); + pos_current = 0; + } + + rem = len_current; //so it does not show 0 on transition + loops_current = 0; + } + } + + //compute time left for transitions by using the end node + + if (end_node != StringName() && end_node != current) { + + rem = blend_node(states[end_node], 0, true, 0, FILTER_IGNORE, false); + } + + return rem; +} + +bool AnimationNodeStateMachine::travel(const StringName &p_state) { + ERR_FAIL_COND_V(!playing, false); + ERR_FAIL_COND_V(!states.has(p_state), false); + ERR_FAIL_COND_V(!states.has(current), false); + + path.clear(); //a new one will be needed + + if (current == p_state) + return true; //nothing to do + + loops_current = 0; // reset loops, so fade does not happen immediately + + Vector2 current_pos = states[current]->get_position(); + Vector2 target_pos = states[p_state]->get_position(); + + Map<StringName, AStarCost> cost_map; + + List<int> open_list; + + //build open list + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == current) { + open_list.push_back(i); + float cost = states[transitions[i].to]->get_position().distance_to(current_pos); + cost *= transitions[i].transition->get_priority(); + AStarCost ap; + ap.prev = current; + ap.distance = cost; + cost_map[transitions[i].to] = ap; + + if (transitions[i].to == p_state) { //prematurely found it! :D + path.push_back(p_state); + return true; + } + } + } + + //begin astar + bool found_route = false; + while (!found_route) { + + if (open_list.size() == 0) { + return false; //no path found + } + + //find the last cost transition + List<int>::Element *least_cost_transition = NULL; + float least_cost = 1e20; + + for (List<int>::Element *E = open_list.front(); E; E = E->next()) { + + float cost = cost_map[transitions[E->get()].to].distance; + cost += states[transitions[E->get()].to]->get_position().distance_to(target_pos); + + if (cost < least_cost) { + least_cost_transition = E; + } + } + + StringName transition_prev = transitions[least_cost_transition->get()].from; + StringName transition = transitions[least_cost_transition->get()].to; + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from != transition || transitions[i].to == transition_prev) { + continue; //not interested on those + } + + float distance = states[transitions[i].from]->get_position().distance_to(states[transitions[i].to]->get_position()); + distance *= transitions[i].transition->get_priority(); + distance += cost_map[transitions[i].from].distance; + + if (cost_map.has(transitions[i].to)) { + //oh this was visited already, can we win the cost? + if (distance < cost_map[transitions[i].to].distance) { + cost_map[transitions[i].to].distance = distance; + cost_map[transitions[i].to].prev = transitions[i].from; + } + } else { + //add to open list + AStarCost ac; + ac.prev = transitions[i].from; + ac.distance = distance; + cost_map[transitions[i].to] = ac; + + open_list.push_back(i); + + if (transitions[i].to == p_state) { + found_route = true; + break; + } + } + } + + if (found_route) { + break; + } + + open_list.erase(least_cost_transition); + } + + //make path + StringName at = p_state; + while (at != current) { + path.push_back(at); + at = cost_map[at].prev; + } + + path.invert(); + + return true; +} + +void AnimationNodeStateMachine::start(const StringName &p_state) { + + ERR_FAIL_COND(!states.has(p_state)); + path.clear(); + current = p_state; + playing = true; + play_start = true; +} +void AnimationNodeStateMachine::stop() { + playing = false; + play_start = false; + current = StringName(); +} +bool AnimationNodeStateMachine::is_playing() const { + + return playing; +} +StringName AnimationNodeStateMachine::get_current_node() const { + if (!playing) { + return StringName(); + } + + return current; +} + +StringName AnimationNodeStateMachine::get_blend_from_node() const { + if (!playing) { + return StringName(); + } + + return fading_from; +} + +float AnimationNodeStateMachine::get_current_play_pos() const { + return pos_current; +} +float AnimationNodeStateMachine::get_current_length() const { + return len_current; +} + +Vector<StringName> AnimationNodeStateMachine::get_travel_path() const { + return path; +} +String AnimationNodeStateMachine::get_caption() const { + return "StateMachine"; +} + +void AnimationNodeStateMachine::_notification(int p_what) { +} + +void AnimationNodeStateMachine::set_tree(AnimationTree *p_player) { + + AnimationNode::set_tree(p_player); + + for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) { + Ref<AnimationRootNode> node = E->get(); + node->set_tree(p_player); + } +} + +bool AnimationNodeStateMachine::_set(const StringName &p_name, const Variant &p_value) { + + String name = p_name; + if (name.begins_with("states/")) { + String node_name = name.get_slicec('/', 1); + String what = name.get_slicec('/', 2); + + if (what == "node") { + Ref<AnimationNode> anode = p_value; + if (anode.is_valid()) { + add_node(node_name, p_value); + } + return true; + } + + if (what == "position") { + + if (states.has(node_name)) { + states[node_name]->set_position(p_value); + } + return true; + } + } else if (name == "transitions") { + + Array trans = p_value; + ERR_FAIL_COND_V(trans.size() % 3 != 0, false); + + for (int i = 0; i < trans.size(); i += 3) { + add_transition(trans[i], trans[i + 1], trans[i + 2]); + } + return true; + } else if (name == "start_node") { + set_start_node(p_value); + return true; + } else if (name == "end_node") { + set_end_node(p_value); + return true; + } else if (name == "graph_offset") { + set_graph_offset(p_value); + return true; + } + + return false; +} + +bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) const { + + String name = p_name; + if (name.begins_with("states/")) { + String node_name = name.get_slicec('/', 1); + String what = name.get_slicec('/', 2); + + if (what == "node") { + if (states.has(node_name)) { + r_ret = states[node_name]; + return true; + } + } + + if (what == "position") { + + if (states.has(node_name)) { + r_ret = states[node_name]->get_position(); + return true; + } + } + } else if (name == "transitions") { + Array trans; + trans.resize(transitions.size() * 3); + + for (int i = 0; i < transitions.size(); i++) { + trans[i * 3 + 0] = transitions[i].from; + trans[i * 3 + 1] = transitions[i].to; + trans[i * 3 + 2] = transitions[i].transition; + } + + r_ret = trans; + return true; + } else if (name == "start_node") { + r_ret = get_start_node(); + return true; + } else if (name == "end_node") { + r_ret = get_end_node(); + return true; + } else if (name == "graph_offset") { + r_ret = get_graph_offset(); + return true; + } + + return false; +} +void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) const { + + List<StringName> names; + for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) { + names.push_back(E->key()); + } + names.sort_custom<StringName::AlphCompare>(); + + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + String name = E->get(); + p_list->push_back(PropertyInfo(Variant::OBJECT, "states/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "states/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + } + + p_list->push_back(PropertyInfo(Variant::ARRAY, "transitions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::STRING, "start_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::STRING, "end_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); +} + +void AnimationNodeStateMachine::_bind_methods() { + + ClassDB::bind_method(D_METHOD("add_node", "name", "node"), &AnimationNodeStateMachine::add_node); + ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeStateMachine::get_node); + ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeStateMachine::remove_node); + ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeStateMachine::rename_node); + ClassDB::bind_method(D_METHOD("has_node", "name"), &AnimationNodeStateMachine::has_node); + ClassDB::bind_method(D_METHOD("get_node_name", "node"), &AnimationNodeStateMachine::get_node_name); + + ClassDB::bind_method(D_METHOD("has_transition", "from", "to"), &AnimationNodeStateMachine::add_transition); + ClassDB::bind_method(D_METHOD("add_transition", "from", "to", "transition"), &AnimationNodeStateMachine::add_transition); + ClassDB::bind_method(D_METHOD("get_transition", "idx"), &AnimationNodeStateMachine::get_transition); + ClassDB::bind_method(D_METHOD("get_transition_from", "idx"), &AnimationNodeStateMachine::get_transition_from); + ClassDB::bind_method(D_METHOD("get_transition_to", "idx"), &AnimationNodeStateMachine::get_transition_to); + ClassDB::bind_method(D_METHOD("get_transition_count"), &AnimationNodeStateMachine::get_transition_count); + ClassDB::bind_method(D_METHOD("remove_transition_by_index", "idx"), &AnimationNodeStateMachine::remove_transition_by_index); + ClassDB::bind_method(D_METHOD("remove_transition", "from", "to"), &AnimationNodeStateMachine::remove_transition); + + ClassDB::bind_method(D_METHOD("set_start_node", "name"), &AnimationNodeStateMachine::set_start_node); + ClassDB::bind_method(D_METHOD("get_start_node"), &AnimationNodeStateMachine::get_start_node); + + ClassDB::bind_method(D_METHOD("set_end_node", "name"), &AnimationNodeStateMachine::set_end_node); + ClassDB::bind_method(D_METHOD("get_end_node"), &AnimationNodeStateMachine::get_end_node); + + ClassDB::bind_method(D_METHOD("set_graph_offset", "name"), &AnimationNodeStateMachine::set_graph_offset); + ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeStateMachine::get_graph_offset); + + ClassDB::bind_method(D_METHOD("travel", "to_node"), &AnimationNodeStateMachine::travel); + ClassDB::bind_method(D_METHOD("start", "node"), &AnimationNodeStateMachine::start); + ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeStateMachine::stop); + ClassDB::bind_method(D_METHOD("is_playing"), &AnimationNodeStateMachine::is_playing); + ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachine::get_current_node); + ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachine::get_travel_path); +} + +AnimationNodeStateMachine::AnimationNodeStateMachine() { + + play_start = false; + + playing = false; + len_current = 0; + + fading_time = 0; +} diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h new file mode 100644 index 0000000000..e7357e09ea --- /dev/null +++ b/scene/animation/animation_node_state_machine.h @@ -0,0 +1,142 @@ +#ifndef ANIMATION_NODE_STATE_MACHINE_H +#define ANIMATION_NODE_STATE_MACHINE_H + +#include "scene/animation/animation_tree.h" + +class AnimationNodeStateMachineTransition : public Resource { + GDCLASS(AnimationNodeStateMachineTransition, Resource) +public: + enum SwitchMode { + SWITCH_MODE_IMMEDIATE, + SWITCH_MODE_SYNC, + SWITCH_MODE_AT_END, + }; + +private: + SwitchMode switch_mode; + bool auto_advance; + float xfade; + bool disabled; + int priority; + +protected: + static void _bind_methods(); + +public: + void set_switch_mode(SwitchMode p_mode); + SwitchMode get_switch_mode() const; + + void set_auto_advance(bool p_enable); + bool has_auto_advance() const; + + void set_xfade_time(float p_xfade); + float get_xfade_time() const; + + void set_disabled(bool p_disabled); + bool is_disabled() const; + + void set_priority(int p_priority); + int get_priority() const; + + AnimationNodeStateMachineTransition(); +}; + +VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode) + +class AnimationNodeStateMachine : public AnimationRootNode { + + GDCLASS(AnimationNodeStateMachine, AnimationRootNode); + +private: + Map<StringName, Ref<AnimationRootNode> > states; + + struct Transition { + + StringName from; + StringName to; + Ref<AnimationNodeStateMachineTransition> transition; + }; + + 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; + float fading_time; + float fading_pos; + + Vector<StringName> path; + bool playing; + +protected: + void _notification(int p_what); + static void _bind_methods(); + + 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; + +public: + void add_node(const StringName &p_name, Ref<AnimationNode> p_node); + 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; + void get_node_list(List<StringName> *r_nodes) const; + + 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); + Ref<AnimationNodeStateMachineTransition> get_transition(int p_transition) const; + StringName get_transition_from(int p_transition) const; + StringName get_transition_to(int p_transition) const; + int get_transition_count() const; + void remove_transition_by_index(int p_transition); + void remove_transition(const StringName &p_from, const StringName &p_to); + + void set_start_node(const StringName &p_node); + String get_start_node() const; + + void set_end_node(const StringName &p_node); + String get_end_node() const; + + void set_graph_offset(const Vector2 &p_offset); + Vector2 get_graph_offset() const; + + 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); + + AnimationNodeStateMachine(); +}; + +#endif // ANIMATION_NODE_STATE_MACHINE_H diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 06aaeddf18..a4322bf713 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -419,14 +419,26 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float pa->capture = pa->object->get_indexed(pa->subpath); } - if (a->track_get_key_count(i) == 0) + int key_count = a->track_get_key_count(i); + if (key_count == 0) continue; //eeh not worth it float first_key_time = a->track_get_key_time(i, 0); + float transition = 1.0; + int first_key = 0; + + if (first_key_time == 0.0) { + //ignore, use for transition + if (key_count == 1) + continue; //with one key we cant do anything + transition = a->track_get_key_transition(i, 0); + first_key_time = a->track_get_key_time(i, 1); + first_key = 1; + } if (p_time < first_key_time) { - float c = p_time / first_key_time; - Variant first_value = a->track_get_key_value(i, 0); + float c = Math::ease(p_time / first_key_time, transition); + Variant first_value = a->track_get_key_value(i, first_key); Variant interp_value; Variant::interpolate(pa->capture, first_value, c, interp_value); diff --git a/scene/animation/animation_graph_player.cpp b/scene/animation/animation_tree.cpp index b8efecebe9..011c4eb470 100644 --- a/scene/animation/animation_graph_player.cpp +++ b/scene/animation/animation_tree.cpp @@ -1,4 +1,4 @@ -#include "animation_graph_player.h" +#include "animation_tree.h" #include "animation_blend_tree.h" #include "core/method_bind_ext.gen.inc" #include "engine.h" @@ -56,11 +56,11 @@ 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_graph_player(), 0); //should not happen, but used to catch bugs + ERR_FAIL_COND_V(!get_tree(), 0); //should not happen, but used to catch bugs Ref<AnimationNodeBlendTree> tree = get_parent(); - if (!tree.is_valid() && get_graph_player()->get_graph_root().ptr() != this) { + 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; } @@ -204,10 +204,10 @@ String AnimationNode::get_input_name(int p_input) { float AnimationNode::get_input_activity(int p_input) const { ERR_FAIL_INDEX_V(p_input, inputs.size(), 0); - if (!get_graph_player()) + if (!get_tree()) return 0; - if (get_graph_player()->get_last_process_pass() != inputs[p_input].last_pass) { + if (get_tree()->get_last_process_pass() != inputs[p_input].last_pass) { return 0; } return inputs[p_input].activity; @@ -225,6 +225,11 @@ void AnimationNode::set_input_connection(int p_input, const StringName &p_connec } String AnimationNode::get_caption() const { + + if (get_script_instance()) { + return get_script_instance()->call("get_caption"); + } + return "Node"; } @@ -253,8 +258,15 @@ 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 { @@ -265,7 +277,7 @@ Ref<AnimationNode> AnimationNode::get_parent() const { return Ref<AnimationNode>(); } -AnimationGraphPlayer *AnimationNode::get_graph_player() const { +AnimationTree *AnimationNode::get_tree() const { return player; } @@ -316,7 +328,7 @@ Vector2 AnimationNode::get_position() const { return position; } -void AnimationNode::set_graph_player(AnimationGraphPlayer *p_player) { +void AnimationNode::set_tree(AnimationTree *p_player) { if (player != NULL && p_player == NULL) { emit_signal("removed_from_graph"); @@ -375,10 +387,17 @@ void AnimationNode::_bind_methods() { 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_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); + 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"); 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")); BIND_ENUM_CONSTANT(FILTER_IGNORE); @@ -398,10 +417,10 @@ AnimationNode::AnimationNode() { //////////////////// -void AnimationGraphPlayer::set_graph_root(const Ref<AnimationNode> &p_root) { +void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) { if (root.is_valid()) { - root->set_graph_player(NULL); + root->set_tree(NULL); } if (p_root.is_valid()) { ERR_EXPLAIN("root node already set to another player"); @@ -410,17 +429,17 @@ void AnimationGraphPlayer::set_graph_root(const Ref<AnimationNode> &p_root) { root = p_root; if (root.is_valid()) { - root->set_graph_player(this); + root->set_tree(this); } update_configuration_warning(); } -Ref<AnimationNode> AnimationGraphPlayer::get_graph_root() const { +Ref<AnimationNode> AnimationTree::get_tree_root() const { return root; } -void AnimationGraphPlayer::set_active(bool p_active) { +void AnimationTree::set_active(bool p_active) { if (active == p_active) return; @@ -447,12 +466,12 @@ void AnimationGraphPlayer::set_active(bool p_active) { } } -bool AnimationGraphPlayer::is_active() const { +bool AnimationTree::is_active() const { return active; } -void AnimationGraphPlayer::set_process_mode(AnimationProcessMode p_mode) { +void AnimationTree::set_process_mode(AnimationProcessMode p_mode) { if (process_mode == p_mode) return; @@ -469,20 +488,20 @@ void AnimationGraphPlayer::set_process_mode(AnimationProcessMode p_mode) { } } -AnimationGraphPlayer::AnimationProcessMode AnimationGraphPlayer::get_process_mode() const { +AnimationTree::AnimationProcessMode AnimationTree::get_process_mode() const { return process_mode; } -void AnimationGraphPlayer::_node_removed(Node *p_node) { +void AnimationTree::_node_removed(Node *p_node) { cache_valid = false; } -bool AnimationGraphPlayer::_update_caches(AnimationPlayer *player) { +bool AnimationTree::_update_caches(AnimationPlayer *player) { setup_pass++; if (!player->has_node(player->get_root())) { - ERR_PRINT("AnimationGraphPlayer: AnimationPlayer root is invalid."); + ERR_PRINT("AnimationTree: AnimationPlayer root is invalid."); set_active(false); return false; } @@ -517,7 +536,7 @@ bool AnimationGraphPlayer::_update_caches(AnimationPlayer *player) { Node *child = parent->get_node_and_resource(path, resource, leftover_path); if (!child) { - ERR_PRINTS("AnimationGraphPlayer: '" + String(E->get()) + "', couldn't resolve track: '" + String(path) + "'"); + ERR_PRINTS("AnimationTree: '" + String(E->get()) + "', couldn't resolve track: '" + String(path) + "'"); continue; } @@ -547,7 +566,7 @@ bool AnimationGraphPlayer::_update_caches(AnimationPlayer *player) { Spatial *spatial = Object::cast_to<Spatial>(child); if (!spatial) { - ERR_PRINTS("AnimationGraphPlayer: '" + String(E->get()) + "', transform track does not point to spatial: '" + String(path) + "'"); + ERR_PRINTS("AnimationTree: '" + String(E->get()) + "', transform track does not point to spatial: '" + String(path) + "'"); continue; } @@ -666,7 +685,7 @@ bool AnimationGraphPlayer::_update_caches(AnimationPlayer *player) { return true; } -void AnimationGraphPlayer::_clear_caches() { +void AnimationTree::_clear_caches() { const NodePath *K = NULL; while ((K = track_cache.next(K))) { @@ -678,19 +697,20 @@ void AnimationGraphPlayer::_clear_caches() { cache_valid = false; } -void AnimationGraphPlayer::_process_graph(float p_delta) { +void AnimationTree::_process_graph(float p_delta) { //check all tracks, see if they need modification + root_motion_transform = Transform(); if (!root.is_valid()) { - ERR_PRINT("AnimationGraphPlayer: root AnimationNode is not set, disabling playback."); + ERR_PRINT("AnimationTree: root AnimationNode is not set, disabling playback."); set_active(false); cache_valid = false; return; } if (!has_node(animation_player)) { - ERR_PRINT("AnimationGraphPlayer: no valid AnimationPlayer path set, disabling playback"); + ERR_PRINT("AnimationTree: no valid AnimationPlayer path set, disabling playback"); set_active(false); cache_valid = false; return; @@ -699,7 +719,7 @@ void AnimationGraphPlayer::_process_graph(float p_delta) { AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player)); if (!player) { - ERR_PRINT("AnimationGraphPlayer: path points to a node not an AnimationPlayer, disabling playback"); + ERR_PRINT("AnimationTree: path points to a node not an AnimationPlayer, disabling playback"); set_active(false); cache_valid = false; return; @@ -770,6 +790,8 @@ void AnimationGraphPlayer::_process_graph(float p_delta) { continue; //may happen should not } + track->root_motion = root_motion_track == path; + ERR_CONTINUE(!state.track_map.has(path)); int blend_idx = state.track_map[path]; @@ -786,29 +808,85 @@ void AnimationGraphPlayer::_process_graph(float p_delta) { TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); - Vector3 loc; - Quat rot; - Vector3 scale; - - Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale); - //ERR_CONTINUE(err!=OK); //used for testing, should be removed - - scale -= Vector3(1.0, 1.0, 1.0); //helps make it work properly with Add nodes - - if (err != OK) - continue; - if (t->process_pass != process_pass) { t->process_pass = process_pass; t->loc = Vector3(); t->rot = Quat(); + t->rot_blend_accum = 0; t->scale = Vector3(); } - t->loc = t->loc.linear_interpolate(loc, blend); - t->rot = t->rot.slerp(rot, blend); - t->scale = t->scale.linear_interpolate(scale, blend); + if (track->root_motion) { + + float prev_time = time - delta; + if (prev_time < 0) { + if (!a->has_loop()) { + prev_time = 0; + } else { + prev_time = a->get_length() + prev_time; + } + } + + Vector3 loc[2]; + Quat rot[2]; + Vector3 scale[2]; + + if (prev_time > time) { + + Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]); + if (err != OK) { + continue; + } + + a->transform_track_interpolate(i, a->get_length(), &loc[1], &rot[1], &scale[1]); + + t->loc += (loc[1] - loc[0]) * blend; + t->scale += (scale[1] - scale[0]) * blend; + Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); + t->rot = (t->rot * q).normalized(); + + prev_time = 0; + } + + Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]); + if (err != OK) { + continue; + } + + a->transform_track_interpolate(i, time, &loc[1], &rot[1], &scale[1]); + + t->loc += (loc[1] - loc[0]) * blend; + t->scale += (scale[1] - scale[0]) * blend; + Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); + t->rot = (t->rot * q).normalized(); + + prev_time = 0; + + } else { + Vector3 loc; + Quat rot; + Vector3 scale; + + Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale); + //ERR_CONTINUE(err!=OK); //used for testing, should be removed + + scale -= Vector3(1.0, 1.0, 1.0); //helps make it work properly with Add nodes + + if (err != OK) + continue; + + t->loc = t->loc.linear_interpolate(loc, blend); + if (t->rot_blend_accum==0) { + t->rot = rot; + t->rot_blend_accum = blend; + } else { + float rot_total = t->rot_blend_accum + blend; + t->rot = rot.slerp(t->rot, t->rot_blend_accum / rot_total).normalized(); + t->rot_blend_accum = rot_total; + } + t->scale = t->scale.linear_interpolate(scale, blend); + } } break; case Animation::TYPE_VALUE: { @@ -1059,11 +1137,18 @@ void AnimationGraphPlayer::_process_graph(float p_delta) { Transform xform; xform.origin = t->loc; - t->scale += Vector3(1.0, 1.0, 1.0); //helps make it work properly with Add nodes + t->scale += Vector3(1.0, 1.0, 1.0); //helps make it work properly with Add nodes and root motion xform.basis.set_quat_scale(t->rot, t->scale); - if (t->skeleton && t->bone_idx >= 0) { + if (t->root_motion) { + + root_motion_transform = xform; + + if (t->skeleton && t->bone_idx >= 0) { + root_motion_transform = (t->skeleton->get_bone_rest(t->bone_idx) * root_motion_transform) * t->skeleton->get_bone_rest(t->bone_idx).affine_inverse(); + } + } else if (t->skeleton && t->bone_idx >= 0) { t->skeleton->set_bone_pose(t->bone_idx, xform); @@ -1093,7 +1178,7 @@ void AnimationGraphPlayer::_process_graph(float p_delta) { } } -void AnimationGraphPlayer::_notification(int p_what) { +void AnimationTree::_notification(int p_what) { if (active && p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_mode == ANIMATION_PROCESS_PHYSICS) { _process_graph(get_physics_process_delta_time()); @@ -1108,29 +1193,29 @@ void AnimationGraphPlayer::_notification(int p_what) { } } -void AnimationGraphPlayer::set_animation_player(const NodePath &p_player) { +void AnimationTree::set_animation_player(const NodePath &p_player) { animation_player = p_player; update_configuration_warning(); } -NodePath AnimationGraphPlayer::get_animation_player() const { +NodePath AnimationTree::get_animation_player() const { return animation_player; } -bool AnimationGraphPlayer::is_state_invalid() const { +bool AnimationTree::is_state_invalid() const { return !state.valid; } -String AnimationGraphPlayer::get_invalid_state_reason() const { +String AnimationTree::get_invalid_state_reason() const { return state.invalid_reasons; } -uint64_t AnimationGraphPlayer::get_last_process_pass() const { +uint64_t AnimationTree::get_last_process_pass() const { return process_pass; } -String AnimationGraphPlayer::get_configuration_warning() const { +String AnimationTree::get_configuration_warning() const { String warning = Node::get_configuration_warning(); @@ -1174,28 +1259,49 @@ String AnimationGraphPlayer::get_configuration_warning() const { return warning; } -void AnimationGraphPlayer::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationGraphPlayer::set_active); - ClassDB::bind_method(D_METHOD("is_active"), &AnimationGraphPlayer::is_active); +void AnimationTree::set_root_motion_track(const NodePath &p_track) { + root_motion_track = p_track; +} + +NodePath AnimationTree::get_root_motion_track() const { + return root_motion_track; +} + +Transform AnimationTree::get_root_motion_transform() const { + return root_motion_transform; +} + +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); + + ClassDB::bind_method(D_METHOD("set_tree_root", "root"), &AnimationTree::set_tree_root); + ClassDB::bind_method(D_METHOD("get_tree_root"), &AnimationTree::get_tree_root); + + ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &AnimationTree::set_process_mode); + ClassDB::bind_method(D_METHOD("get_process_mode"), &AnimationTree::get_process_mode); + + ClassDB::bind_method(D_METHOD("set_animation_player", "root"), &AnimationTree::set_animation_player); + ClassDB::bind_method(D_METHOD("get_animation_player"), &AnimationTree::get_animation_player); + + ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationTree::set_root_motion_track); + ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationTree::get_root_motion_track); - ClassDB::bind_method(D_METHOD("set_graph_root", "root"), &AnimationGraphPlayer::set_graph_root); - ClassDB::bind_method(D_METHOD("get_graph_root"), &AnimationGraphPlayer::get_graph_root); + ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform); - ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &AnimationGraphPlayer::set_process_mode); - ClassDB::bind_method(D_METHOD("get_process_mode"), &AnimationGraphPlayer::get_process_mode); - ClassDB::bind_method(D_METHOD("set_animation_player", "root"), &AnimationGraphPlayer::set_animation_player); - ClassDB::bind_method(D_METHOD("get_animation_player"), &AnimationGraphPlayer::get_animation_player); - ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationGraphPlayer::_node_removed); + ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationTree::_node_removed); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "graph_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_graph_root", "get_graph_root"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player"), "set_animation_player", "get_animation_player"); + 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::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"), "set_process_mode", "get_process_mode"); + ADD_GROUP("Root Motion", "root_motion_"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track"); } -AnimationGraphPlayer::AnimationGraphPlayer() { +AnimationTree::AnimationTree() { process_mode = ANIMATION_PROCESS_IDLE; active = false; @@ -1204,7 +1310,7 @@ AnimationGraphPlayer::AnimationGraphPlayer() { started = true; } -AnimationGraphPlayer::~AnimationGraphPlayer() { +AnimationTree::~AnimationTree() { if (root.is_valid()) { root->player = NULL; } diff --git a/scene/animation/animation_graph_player.h b/scene/animation/animation_tree.h index 8952be75c9..540c36437a 100644 --- a/scene/animation/animation_graph_player.h +++ b/scene/animation/animation_tree.h @@ -8,7 +8,7 @@ class AnimationNodeBlendTree; class AnimationPlayer; -class AnimationGraphPlayer; +class AnimationTree; class AnimationNode : public Resource { GDCLASS(AnimationNode, Resource) @@ -32,7 +32,7 @@ public: float process_input(int p_input, float p_time, bool p_seek, float p_blend); - friend class AnimationGraphPlayer; + friend class AnimationTree; struct AnimationState { @@ -62,7 +62,7 @@ public: Vector2 position; AnimationNode *parent; - AnimationGraphPlayer *player; + 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); @@ -82,11 +82,13 @@ protected: void _validate_property(PropertyInfo &property) const; + void _set_parent(Object *p_parent); + public: void set_parent(AnimationNode *p_parent); Ref<AnimationNode> get_parent() const; - virtual void set_graph_player(AnimationGraphPlayer *p_player); - AnimationGraphPlayer *get_graph_player() const; + virtual void set_tree(AnimationTree *p_player); + AnimationTree *get_tree() const; AnimationPlayer *get_player() const; virtual float process(float p_time, bool p_seek); @@ -125,8 +127,8 @@ public: AnimationRootNode() {} }; -class AnimationGraphPlayer : public Node { - GDCLASS(AnimationGraphPlayer, Node) +class AnimationTree : public Node { + GDCLASS(AnimationTree, Node) public: enum AnimationProcessMode { ANIMATION_PROCESS_PHYSICS, @@ -135,6 +137,8 @@ public: private: struct TrackCache { + + bool root_motion; uint64_t setup_pass; uint64_t process_pass; Animation::TrackType type; @@ -142,6 +146,7 @@ private: ObjectID object_id; TrackCache() { + root_motion = false; setup_pass = 0; process_pass = 0; object = NULL; @@ -156,6 +161,7 @@ private: int bone_idx; Vector3 loc; Quat rot; + float rot_blend_accum; Vector3 scale; TrackCacheTransform() { @@ -235,13 +241,16 @@ private: bool started; + NodePath root_motion_track; + Transform root_motion_transform; + protected: void _notification(int p_what); static void _bind_methods(); public: - void set_graph_root(const Ref<AnimationNode> &p_root); - Ref<AnimationNode> get_graph_root() const; + void set_tree_root(const Ref<AnimationNode> &p_root); + Ref<AnimationNode> get_tree_root() const; void set_active(bool p_active); bool is_active() const; @@ -257,11 +266,16 @@ public: bool is_state_invalid() const; String get_invalid_state_reason() const; + void set_root_motion_track(const NodePath &p_track); + NodePath get_root_motion_track() const; + + Transform get_root_motion_transform() const; + uint64_t get_last_process_pass() const; - AnimationGraphPlayer(); - ~AnimationGraphPlayer(); + AnimationTree(); + ~AnimationTree(); }; -VARIANT_ENUM_CAST(AnimationGraphPlayer::AnimationProcessMode) +VARIANT_ENUM_CAST(AnimationTree::AnimationProcessMode) #endif // ANIMATION_GRAPH_PLAYER_H diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 143684bdf9..026215508b 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -1814,7 +1814,7 @@ void AnimationTreePlayer::_bind_methods() { ADD_GROUP("Playback", "playback_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_animation_process_mode", "get_animation_process_mode"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "master_player"), "set_master_player", "get_master_player"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "master_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_master_player", "get_master_player"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "base_path"), "set_base_path", "get_base_path"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp new file mode 100644 index 0000000000..a28c63064a --- /dev/null +++ b/scene/animation/root_motion_view.cpp @@ -0,0 +1,178 @@ +#include "root_motion_view.h" +#include "scene/animation/animation_tree.h" +#include "scene/resources/material.h" +void RootMotionView::set_animation_path(const NodePath &p_path) { + path = p_path; + first = true; +} + +NodePath RootMotionView::get_animation_path() const { + return path; +} + +void RootMotionView::set_color(const Color &p_color) { + color = p_color; + first = true; +} + +Color RootMotionView::get_color() const { + return color; +} + +void RootMotionView::set_cell_size(float p_size) { + cell_size = p_size; + first = true; +} + +float RootMotionView::get_cell_size() const { + return cell_size; +} + +void RootMotionView::set_radius(float p_radius) { + radius = p_radius; + first = true; +} + +float RootMotionView::get_radius() const { + return radius; +} + +void RootMotionView::set_zero_y(bool p_zero_y) { + zero_y = p_zero_y; +} + +bool RootMotionView::get_zero_y() const { + return zero_y; +} + +void RootMotionView::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + + VS::get_singleton()->immediate_set_material(immediate, SpatialMaterial::get_material_rid_for_2d(false, true, false, false, false)); + first = true; + } + + if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { + Transform transform; + + if (has_node(path)) { + + Node *node = get_node(path); + + AnimationTree *tree = Object::cast_to<AnimationTree>(node); + if (tree && tree->is_active() && tree->get_root_motion_track() != NodePath()) { + if (is_processing_internal() && tree->get_process_mode() == AnimationTree::ANIMATION_PROCESS_PHYSICS) { + set_process_internal(false); + set_physics_process_internal(true); + } + + if (is_physics_processing_internal() && tree->get_process_mode() == AnimationTree::ANIMATION_PROCESS_IDLE) { + set_process_internal(true); + set_physics_process_internal(false); + } + + transform = tree->get_root_motion_transform(); + } + } + + if (!first && transform == Transform()) { + return; + } + + first = false; + + transform.orthonormalize(); //dont want scale, too imprecise + transform.affine_invert(); + + accumulated = transform * accumulated; + accumulated.origin.x = Math::fposmod(accumulated.origin.x, cell_size); + if (zero_y) { + accumulated.origin.y = 0; + } + accumulated.origin.z = Math::fposmod(accumulated.origin.z, cell_size); + + VS::get_singleton()->immediate_clear(immediate); + + int cells_in_radius = int((radius / cell_size) + 1.0); + + VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_LINES); + for (int i = -cells_in_radius; i < cells_in_radius; i++) { + for (int j = -cells_in_radius; j < cells_in_radius; j++) { + + Vector3 from(i * cell_size, 0, j * cell_size); + Vector3 from_i((i + 1) * cell_size, 0, j * cell_size); + Vector3 from_j(i * cell_size, 0, (j + 1) * cell_size); + from = accumulated.xform(from); + from_i = accumulated.xform(from_i); + from_j = accumulated.xform(from_j); + + Color c = color, c_i = color, c_j = color; + c.a *= MAX(0, 1.0 - from.length() / radius); + c_i.a *= MAX(0, 1.0 - from_i.length() / radius); + c_j.a *= MAX(0, 1.0 - from_j.length() / radius); + + VS::get_singleton()->immediate_color(immediate, c); + VS::get_singleton()->immediate_vertex(immediate, from); + + VS::get_singleton()->immediate_color(immediate, c_i); + VS::get_singleton()->immediate_vertex(immediate, from_i); + + VS::get_singleton()->immediate_color(immediate, c); + VS::get_singleton()->immediate_vertex(immediate, from); + + VS::get_singleton()->immediate_color(immediate, c_j); + VS::get_singleton()->immediate_vertex(immediate, from_j); + } + } + + VS::get_singleton()->immediate_end(immediate); + } +} + +AABB RootMotionView::get_aabb() const { + + return AABB(Vector3(-radius, 0, -radius), Vector3(radius * 2, 0.001, radius * 2)); +} +PoolVector<Face3> RootMotionView::get_faces(uint32_t p_usage_flags) const { + return PoolVector<Face3>(); +} + +void RootMotionView::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_animation_path", "path"), &RootMotionView::set_animation_path); + ClassDB::bind_method(D_METHOD("get_animation_path"), &RootMotionView::get_animation_path); + + ClassDB::bind_method(D_METHOD("set_color", "color"), &RootMotionView::set_color); + ClassDB::bind_method(D_METHOD("get_color"), &RootMotionView::get_color); + + ClassDB::bind_method(D_METHOD("set_cell_size", "size"), &RootMotionView::set_cell_size); + ClassDB::bind_method(D_METHOD("get_cell_size"), &RootMotionView::get_cell_size); + + ClassDB::bind_method(D_METHOD("set_radius", "size"), &RootMotionView::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &RootMotionView::get_radius); + + ClassDB::bind_method(D_METHOD("set_zero_y", "enable"), &RootMotionView::set_zero_y); + ClassDB::bind_method(D_METHOD("get_zero_y"), &RootMotionView::get_zero_y); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "animation_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationTree"), "set_animation_path", "get_animation_path"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell_size", PROPERTY_HINT_RANGE, "0.1,16,0.01,or_greater"), "set_cell_size", "get_cell_size"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.1,16,0.01,or_greater"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "zero_y"), "set_zero_y", "get_zero_y"); +} + +RootMotionView::RootMotionView() { + zero_y = true; + radius = 10; + cell_size = 1; + set_process_internal(true); + immediate = VisualServer::get_singleton()->immediate_create(); + set_base(immediate); + color = Color(0.5, 0.5, 1.0); +} + +RootMotionView::~RootMotionView() { + set_base(RID()); + VisualServer::get_singleton()->free(immediate); +} diff --git a/scene/animation/root_motion_view.h b/scene/animation/root_motion_view.h new file mode 100644 index 0000000000..611183d364 --- /dev/null +++ b/scene/animation/root_motion_view.h @@ -0,0 +1,47 @@ +#ifndef ROOT_MOTION_VIEW_H +#define ROOT_MOTION_VIEW_H + +#include "scene/3d/visual_instance.h" + +class RootMotionView : public VisualInstance { + GDCLASS(RootMotionView, VisualInstance) +public: + RID immediate; + NodePath path; + float cell_size; + float radius; + bool use_in_game; + Color color; + bool first; + bool zero_y; + + Transform accumulated; + +private: + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_animation_path(const NodePath &p_path); + NodePath get_animation_path() const; + + void set_color(const Color &p_path); + Color get_color() const; + + void set_cell_size(float p_size); + float get_cell_size() const; + + void set_radius(float p_radius); + float get_radius() const; + + void set_zero_y(bool p_zero_y); + bool get_zero_y() const; + + virtual AABB get_aabb() const; + virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + + RootMotionView(); + ~RootMotionView(); +}; + +#endif // ROOT_MOTION_VIEW_H diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index a738687a70..18a0cd13d9 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2888,12 +2888,12 @@ void Control::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip"); ADD_GROUP("Focus", "focus_"); - ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_left"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_LEFT); - ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_top"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_TOP); - ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_right"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_RIGHT); - ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_bottom"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_BOTTOM); - ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_next"), "set_focus_next", "get_focus_next"); - ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_previous"), "set_focus_previous", "get_focus_previous"); + ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_LEFT); + ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_top", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_TOP); + ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_right", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_RIGHT); + ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_bottom", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_BOTTOM); + ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_next", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_next", "get_focus_next"); + ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_previous", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_previous", "get_focus_previous"); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode"); ADD_GROUP("Mouse", "mouse_"); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 1236aea2dd..a894b82a94 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -144,7 +144,7 @@ void ViewportTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_viewport_path_in_scene", "path"), &ViewportTexture::set_viewport_path_in_scene); ClassDB::bind_method(D_METHOD("get_viewport_path_in_scene"), &ViewportTexture::get_viewport_path_in_scene); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path"), "set_viewport_path_in_scene", "get_viewport_path_in_scene"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Viewport"), "set_viewport_path_in_scene", "get_viewport_path_in_scene"); } ViewportTexture::ViewportTexture() { diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 244d95d9c7..55aa0024c8 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -63,11 +63,14 @@ #include "scene/2d/tile_map.h" #include "scene/2d/visibility_notifier_2d.h" #include "scene/2d/y_sort.h" -#include "scene/animation/animation_blend_space.h" +#include "scene/animation/animation_blend_space_1d.h" +#include "scene/animation/animation_blend_space_2d.h" #include "scene/animation/animation_blend_tree.h" -#include "scene/animation/animation_graph_player.h" +#include "scene/animation/animation_node_state_machine.h" #include "scene/animation/animation_player.h" +#include "scene/animation/animation_tree.h" #include "scene/animation/animation_tree_player.h" +#include "scene/animation/root_motion_view.h" #include "scene/animation/tween.h" #include "scene/audio/audio_player.h" #include "scene/gui/box_container.h" @@ -385,15 +388,22 @@ void register_scene_types() { ClassDB::register_class<NavigationMesh>(); ClassDB::register_class<Navigation>(); - ClassDB::register_class<AnimationGraphPlayer>(); + ClassDB::register_class<RootMotionView>(); + ClassDB::set_class_enabled("RootMotionView", false); //disabled by default, enabled by editor + + ClassDB::register_class<AnimationTree>(); ClassDB::register_class<AnimationNode>(); ClassDB::register_class<AnimationRootNode>(); ClassDB::register_class<AnimationNodeBlendTree>(); - ClassDB::register_class<AnimationNodeBlendSpace>(); + ClassDB::register_class<AnimationNodeBlendSpace1D>(); + ClassDB::register_class<AnimationNodeBlendSpace2D>(); + ClassDB::register_class<AnimationNodeStateMachine>(); + ClassDB::register_class<AnimationNodeStateMachineTransition>(); ClassDB::register_class<AnimationNodeOutput>(); ClassDB::register_class<AnimationNodeOneShot>(); ClassDB::register_class<AnimationNodeAnimation>(); - ClassDB::register_class<AnimationNodeAdd>(); + ClassDB::register_class<AnimationNodeAdd2>(); + ClassDB::register_class<AnimationNodeAdd3>(); ClassDB::register_class<AnimationNodeBlend2>(); ClassDB::register_class<AnimationNodeBlend3>(); ClassDB::register_class<AnimationNodeTimeScale>(); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index fe4d687c23..3185fb6768 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -134,8 +134,8 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { int um = d["update"]; if (um < 0) um = 0; - else if (um > 2) - um = 2; + else if (um > 3) + um = 3; vt->update_mode = UpdateMode(um); } diff --git a/scene/resources/default_theme/arrow_down.png b/scene/resources/default_theme/arrow_down.png Binary files differindex fc837d120a..bfb87a4761 100644 --- a/scene/resources/default_theme/arrow_down.png +++ b/scene/resources/default_theme/arrow_down.png diff --git a/scene/resources/default_theme/arrow_right.png b/scene/resources/default_theme/arrow_right.png Binary files differindex ebe6e26ace..1e4c8e5529 100644 --- a/scene/resources/default_theme/arrow_right.png +++ b/scene/resources/default_theme/arrow_right.png diff --git a/scene/resources/default_theme/background.png b/scene/resources/default_theme/background.png Binary files differindex 03cfab1de3..6c5f43e3ce 100644 --- a/scene/resources/default_theme/background.png +++ b/scene/resources/default_theme/background.png diff --git a/scene/resources/default_theme/base_green.png b/scene/resources/default_theme/base_green.png Binary files differindex d03d6f08d8..03a5b313d7 100644 --- a/scene/resources/default_theme/base_green.png +++ b/scene/resources/default_theme/base_green.png diff --git a/scene/resources/default_theme/button_disabled.png b/scene/resources/default_theme/button_disabled.png Binary files differindex d75e76989d..708748dfe9 100644 --- a/scene/resources/default_theme/button_disabled.png +++ b/scene/resources/default_theme/button_disabled.png diff --git a/scene/resources/default_theme/button_focus.png b/scene/resources/default_theme/button_focus.png Binary files differindex 44e354be95..70e16b953b 100644 --- a/scene/resources/default_theme/button_focus.png +++ b/scene/resources/default_theme/button_focus.png diff --git a/scene/resources/default_theme/button_hover.png b/scene/resources/default_theme/button_hover.png Binary files differindex 6e609f435f..ef226e3caf 100644 --- a/scene/resources/default_theme/button_hover.png +++ b/scene/resources/default_theme/button_hover.png diff --git a/scene/resources/default_theme/button_normal.png b/scene/resources/default_theme/button_normal.png Binary files differindex 92482aaf28..7d0bd16221 100644 --- a/scene/resources/default_theme/button_normal.png +++ b/scene/resources/default_theme/button_normal.png diff --git a/scene/resources/default_theme/checked.png b/scene/resources/default_theme/checked.png Binary files differindex 93e291a29e..bde031b6a2 100644 --- a/scene/resources/default_theme/checked.png +++ b/scene/resources/default_theme/checked.png diff --git a/scene/resources/default_theme/checker_bg.png b/scene/resources/default_theme/checker_bg.png Binary files differindex f58dfed29c..3eff2f0e08 100644 --- a/scene/resources/default_theme/checker_bg.png +++ b/scene/resources/default_theme/checker_bg.png diff --git a/scene/resources/default_theme/close.png b/scene/resources/default_theme/close.png Binary files differindex 5ac6357dcd..4d4ac4a551 100644 --- a/scene/resources/default_theme/close.png +++ b/scene/resources/default_theme/close.png diff --git a/scene/resources/default_theme/close_hl.png b/scene/resources/default_theme/close_hl.png Binary files differindex 5ac6357dcd..4d4ac4a551 100644 --- a/scene/resources/default_theme/close_hl.png +++ b/scene/resources/default_theme/close_hl.png diff --git a/scene/resources/default_theme/color_picker_sample.png b/scene/resources/default_theme/color_picker_sample.png Binary files differindex b145a3e384..e6ec28d307 100644 --- a/scene/resources/default_theme/color_picker_sample.png +++ b/scene/resources/default_theme/color_picker_sample.png diff --git a/scene/resources/default_theme/dosfont.png b/scene/resources/default_theme/dosfont.png Binary files differindex 814d2e9060..e2739b94ea 100644 --- a/scene/resources/default_theme/dosfont.png +++ b/scene/resources/default_theme/dosfont.png diff --git a/scene/resources/default_theme/dropdown.png b/scene/resources/default_theme/dropdown.png Binary files differindex 3a6a2ed778..b5d9ffbbb4 100644 --- a/scene/resources/default_theme/dropdown.png +++ b/scene/resources/default_theme/dropdown.png diff --git a/scene/resources/default_theme/error_icon.png b/scene/resources/default_theme/error_icon.png Binary files differindex f291362350..7741d00749 100644 --- a/scene/resources/default_theme/error_icon.png +++ b/scene/resources/default_theme/error_icon.png diff --git a/scene/resources/default_theme/focus.png b/scene/resources/default_theme/focus.png Binary files differindex 5d37028f2d..f51ea89e8f 100644 --- a/scene/resources/default_theme/focus.png +++ b/scene/resources/default_theme/focus.png diff --git a/scene/resources/default_theme/frame_focus.png b/scene/resources/default_theme/frame_focus.png Binary files differindex 9170db38ed..1b24ba47d8 100644 --- a/scene/resources/default_theme/frame_focus.png +++ b/scene/resources/default_theme/frame_focus.png diff --git a/scene/resources/default_theme/full_panel_bg.png b/scene/resources/default_theme/full_panel_bg.png Binary files differindex 7f02dc7259..85f753cc13 100644 --- a/scene/resources/default_theme/full_panel_bg.png +++ b/scene/resources/default_theme/full_panel_bg.png diff --git a/scene/resources/default_theme/graph_node_breakpoint.png b/scene/resources/default_theme/graph_node_breakpoint.png Binary files differindex 0e36f31bd4..e18c6f42e1 100644 --- a/scene/resources/default_theme/graph_node_breakpoint.png +++ b/scene/resources/default_theme/graph_node_breakpoint.png diff --git a/scene/resources/default_theme/graph_node_close.png b/scene/resources/default_theme/graph_node_close.png Binary files differindex 144a8b9c4c..5c962ae1c6 100644 --- a/scene/resources/default_theme/graph_node_close.png +++ b/scene/resources/default_theme/graph_node_close.png diff --git a/scene/resources/default_theme/graph_node_comment.png b/scene/resources/default_theme/graph_node_comment.png Binary files differindex f2d6daa259..cdec1d1eac 100644 --- a/scene/resources/default_theme/graph_node_comment.png +++ b/scene/resources/default_theme/graph_node_comment.png diff --git a/scene/resources/default_theme/graph_node_comment_focus.png b/scene/resources/default_theme/graph_node_comment_focus.png Binary files differindex a4b7b5a618..472a6b6f53 100644 --- a/scene/resources/default_theme/graph_node_comment_focus.png +++ b/scene/resources/default_theme/graph_node_comment_focus.png diff --git a/scene/resources/default_theme/graph_node_default.png b/scene/resources/default_theme/graph_node_default.png Binary files differindex e3a220301f..359bbdc205 100644 --- a/scene/resources/default_theme/graph_node_default.png +++ b/scene/resources/default_theme/graph_node_default.png diff --git a/scene/resources/default_theme/graph_node_default_focus.png b/scene/resources/default_theme/graph_node_default_focus.png Binary files differindex 9972b07593..204dd16ac0 100644 --- a/scene/resources/default_theme/graph_node_default_focus.png +++ b/scene/resources/default_theme/graph_node_default_focus.png diff --git a/scene/resources/default_theme/graph_node_position.png b/scene/resources/default_theme/graph_node_position.png Binary files differindex 7ec15e2ff4..24c2759be6 100644 --- a/scene/resources/default_theme/graph_node_position.png +++ b/scene/resources/default_theme/graph_node_position.png diff --git a/scene/resources/default_theme/graph_node_selected.png b/scene/resources/default_theme/graph_node_selected.png Binary files differindex f76c9703dd..cc4eb7f753 100644 --- a/scene/resources/default_theme/graph_node_selected.png +++ b/scene/resources/default_theme/graph_node_selected.png diff --git a/scene/resources/default_theme/graph_port.png b/scene/resources/default_theme/graph_port.png Binary files differindex 9d5082cfdb..f33ae3baf3 100644 --- a/scene/resources/default_theme/graph_port.png +++ b/scene/resources/default_theme/graph_port.png diff --git a/scene/resources/default_theme/hseparator.png b/scene/resources/default_theme/hseparator.png Binary files differindex 99609ac118..d4fd71ace5 100644 --- a/scene/resources/default_theme/hseparator.png +++ b/scene/resources/default_theme/hseparator.png diff --git a/scene/resources/default_theme/hslider_bg.png b/scene/resources/default_theme/hslider_bg.png Binary files differindex 9c2a2df62a..b402bd370d 100644 --- a/scene/resources/default_theme/hslider_bg.png +++ b/scene/resources/default_theme/hslider_bg.png diff --git a/scene/resources/default_theme/hslider_grabber.png b/scene/resources/default_theme/hslider_grabber.png Binary files differindex 2acd33879a..d273b491ee 100644 --- a/scene/resources/default_theme/hslider_grabber.png +++ b/scene/resources/default_theme/hslider_grabber.png diff --git a/scene/resources/default_theme/hslider_grabber_disabled.png b/scene/resources/default_theme/hslider_grabber_disabled.png Binary files differindex 0d75182b8f..dddd1a468e 100644 --- a/scene/resources/default_theme/hslider_grabber_disabled.png +++ b/scene/resources/default_theme/hslider_grabber_disabled.png diff --git a/scene/resources/default_theme/hslider_grabber_hl.png b/scene/resources/default_theme/hslider_grabber_hl.png Binary files differindex f8a011e64b..e3defb3610 100644 --- a/scene/resources/default_theme/hslider_grabber_hl.png +++ b/scene/resources/default_theme/hslider_grabber_hl.png diff --git a/scene/resources/default_theme/hslider_tick.png b/scene/resources/default_theme/hslider_tick.png Binary files differindex f7afd78529..1ba19c37a1 100644 --- a/scene/resources/default_theme/hslider_tick.png +++ b/scene/resources/default_theme/hslider_tick.png diff --git a/scene/resources/default_theme/hsplit_bg.png b/scene/resources/default_theme/hsplit_bg.png Binary files differindex 7dd1d48b29..a5749f6d5c 100644 --- a/scene/resources/default_theme/hsplit_bg.png +++ b/scene/resources/default_theme/hsplit_bg.png diff --git a/scene/resources/default_theme/hsplitter.png b/scene/resources/default_theme/hsplitter.png Binary files differindex 71a3914d7e..2287753c9d 100644 --- a/scene/resources/default_theme/hsplitter.png +++ b/scene/resources/default_theme/hsplitter.png diff --git a/scene/resources/default_theme/icon_add.png b/scene/resources/default_theme/icon_add.png Binary files differindex fa675045bc..eccb69b363 100644 --- a/scene/resources/default_theme/icon_add.png +++ b/scene/resources/default_theme/icon_add.png diff --git a/scene/resources/default_theme/icon_close.png b/scene/resources/default_theme/icon_close.png Binary files differindex 5ac6357dcd..4d4ac4a551 100644 --- a/scene/resources/default_theme/icon_close.png +++ b/scene/resources/default_theme/icon_close.png diff --git a/scene/resources/default_theme/icon_color_pick.png b/scene/resources/default_theme/icon_color_pick.png Binary files differindex 15679a9558..46953febb8 100644 --- a/scene/resources/default_theme/icon_color_pick.png +++ b/scene/resources/default_theme/icon_color_pick.png diff --git a/scene/resources/default_theme/icon_folder.png b/scene/resources/default_theme/icon_folder.png Binary files differindex cc05e98ebb..d1b308e88d 100644 --- a/scene/resources/default_theme/icon_folder.png +++ b/scene/resources/default_theme/icon_folder.png diff --git a/scene/resources/default_theme/icon_parent_folder.png b/scene/resources/default_theme/icon_parent_folder.png Binary files differindex 47fee1ad81..35d218722e 100644 --- a/scene/resources/default_theme/icon_parent_folder.png +++ b/scene/resources/default_theme/icon_parent_folder.png diff --git a/scene/resources/default_theme/icon_play.png b/scene/resources/default_theme/icon_play.png Binary files differindex 864e4e4fb9..b9ed6e6d5b 100644 --- a/scene/resources/default_theme/icon_play.png +++ b/scene/resources/default_theme/icon_play.png diff --git a/scene/resources/default_theme/icon_reload.png b/scene/resources/default_theme/icon_reload.png Binary files differindex 9303fabb9c..bec5f3f4f9 100644 --- a/scene/resources/default_theme/icon_reload.png +++ b/scene/resources/default_theme/icon_reload.png diff --git a/scene/resources/default_theme/icon_snap_grid.png b/scene/resources/default_theme/icon_snap_grid.png Binary files differindex 44db9bdfdc..0680317d86 100644 --- a/scene/resources/default_theme/icon_snap_grid.png +++ b/scene/resources/default_theme/icon_snap_grid.png diff --git a/scene/resources/default_theme/icon_stop.png b/scene/resources/default_theme/icon_stop.png Binary files differindex 1f194d0e14..0c1371ceb9 100644 --- a/scene/resources/default_theme/icon_stop.png +++ b/scene/resources/default_theme/icon_stop.png diff --git a/scene/resources/default_theme/icon_zoom_less.png b/scene/resources/default_theme/icon_zoom_less.png Binary files differindex 888ddc995d..03119c60ca 100644 --- a/scene/resources/default_theme/icon_zoom_less.png +++ b/scene/resources/default_theme/icon_zoom_less.png diff --git a/scene/resources/default_theme/icon_zoom_more.png b/scene/resources/default_theme/icon_zoom_more.png Binary files differindex fa675045bc..31467ec3de 100644 --- a/scene/resources/default_theme/icon_zoom_more.png +++ b/scene/resources/default_theme/icon_zoom_more.png diff --git a/scene/resources/default_theme/icon_zoom_reset.png b/scene/resources/default_theme/icon_zoom_reset.png Binary files differindex 953ae47d24..cac68c09fa 100644 --- a/scene/resources/default_theme/icon_zoom_reset.png +++ b/scene/resources/default_theme/icon_zoom_reset.png diff --git a/scene/resources/default_theme/line_edit.png b/scene/resources/default_theme/line_edit.png Binary files differindex bf2b91f1be..2b0c506f34 100644 --- a/scene/resources/default_theme/line_edit.png +++ b/scene/resources/default_theme/line_edit.png diff --git a/scene/resources/default_theme/line_edit_disabled.png b/scene/resources/default_theme/line_edit_disabled.png Binary files differindex a0fa505e4c..69d78febd9 100644 --- a/scene/resources/default_theme/line_edit_disabled.png +++ b/scene/resources/default_theme/line_edit_disabled.png diff --git a/scene/resources/default_theme/line_edit_focus.png b/scene/resources/default_theme/line_edit_focus.png Binary files differindex e66d7b60e3..1d74b74068 100644 --- a/scene/resources/default_theme/line_edit_focus.png +++ b/scene/resources/default_theme/line_edit_focus.png diff --git a/scene/resources/default_theme/logo.png b/scene/resources/default_theme/logo.png Binary files differindex 2161402438..d0ef9d8aa7 100644 --- a/scene/resources/default_theme/logo.png +++ b/scene/resources/default_theme/logo.png diff --git a/scene/resources/default_theme/mini_checkerboard.png b/scene/resources/default_theme/mini_checkerboard.png Binary files differindex 3e53183847..d8279bda80 100644 --- a/scene/resources/default_theme/mini_checkerboard.png +++ b/scene/resources/default_theme/mini_checkerboard.png diff --git a/scene/resources/default_theme/option_arrow.png b/scene/resources/default_theme/option_arrow.png Binary files differindex 007de16bfa..40590fd60a 100644 --- a/scene/resources/default_theme/option_arrow.png +++ b/scene/resources/default_theme/option_arrow.png diff --git a/scene/resources/default_theme/option_button_disabled.png b/scene/resources/default_theme/option_button_disabled.png Binary files differindex ce727d56e1..1961b673cd 100644 --- a/scene/resources/default_theme/option_button_disabled.png +++ b/scene/resources/default_theme/option_button_disabled.png diff --git a/scene/resources/default_theme/option_button_focus.png b/scene/resources/default_theme/option_button_focus.png Binary files differindex c76d91287e..402670f9a2 100644 --- a/scene/resources/default_theme/option_button_focus.png +++ b/scene/resources/default_theme/option_button_focus.png diff --git a/scene/resources/default_theme/option_button_hover.png b/scene/resources/default_theme/option_button_hover.png Binary files differindex fd1e987ceb..826fe1c9ca 100644 --- a/scene/resources/default_theme/option_button_hover.png +++ b/scene/resources/default_theme/option_button_hover.png diff --git a/scene/resources/default_theme/option_button_normal.png b/scene/resources/default_theme/option_button_normal.png Binary files differindex 9d7fb98d1c..2dadb40338 100644 --- a/scene/resources/default_theme/option_button_normal.png +++ b/scene/resources/default_theme/option_button_normal.png diff --git a/scene/resources/default_theme/option_button_pressed.png b/scene/resources/default_theme/option_button_pressed.png Binary files differindex 28b1d93468..68796f9d85 100644 --- a/scene/resources/default_theme/option_button_pressed.png +++ b/scene/resources/default_theme/option_button_pressed.png diff --git a/scene/resources/default_theme/panel_bg.png b/scene/resources/default_theme/panel_bg.png Binary files differindex 320819ad6d..b496e2177e 100644 --- a/scene/resources/default_theme/panel_bg.png +++ b/scene/resources/default_theme/panel_bg.png diff --git a/scene/resources/default_theme/popup_bg.png b/scene/resources/default_theme/popup_bg.png Binary files differindex 63f5994441..023029f936 100644 --- a/scene/resources/default_theme/popup_bg.png +++ b/scene/resources/default_theme/popup_bg.png diff --git a/scene/resources/default_theme/popup_bg_disabled.png b/scene/resources/default_theme/popup_bg_disabled.png Binary files differindex 611d949380..8eab5f27bc 100644 --- a/scene/resources/default_theme/popup_bg_disabled.png +++ b/scene/resources/default_theme/popup_bg_disabled.png diff --git a/scene/resources/default_theme/popup_checked.png b/scene/resources/default_theme/popup_checked.png Binary files differindex a24e0543c0..b7b05640e1 100644 --- a/scene/resources/default_theme/popup_checked.png +++ b/scene/resources/default_theme/popup_checked.png diff --git a/scene/resources/default_theme/popup_hover.png b/scene/resources/default_theme/popup_hover.png Binary files differindex 85d4e48475..bdb6ae8bd0 100644 --- a/scene/resources/default_theme/popup_hover.png +++ b/scene/resources/default_theme/popup_hover.png diff --git a/scene/resources/default_theme/popup_unchecked.png b/scene/resources/default_theme/popup_unchecked.png Binary files differindex c1137e6fbf..ff922335c3 100644 --- a/scene/resources/default_theme/popup_unchecked.png +++ b/scene/resources/default_theme/popup_unchecked.png diff --git a/scene/resources/default_theme/popup_window.png b/scene/resources/default_theme/popup_window.png Binary files differindex 59362a8ffd..174a29ef45 100644 --- a/scene/resources/default_theme/popup_window.png +++ b/scene/resources/default_theme/popup_window.png diff --git a/scene/resources/default_theme/progress_bar.png b/scene/resources/default_theme/progress_bar.png Binary files differindex bf81e3adea..057557e567 100644 --- a/scene/resources/default_theme/progress_bar.png +++ b/scene/resources/default_theme/progress_bar.png diff --git a/scene/resources/default_theme/progress_fill.png b/scene/resources/default_theme/progress_fill.png Binary files differindex 3a34dfdda6..e39bb2a021 100644 --- a/scene/resources/default_theme/progress_fill.png +++ b/scene/resources/default_theme/progress_fill.png diff --git a/scene/resources/default_theme/radio_checked.png b/scene/resources/default_theme/radio_checked.png Binary files differindex 95d472022f..0ce575c15f 100644 --- a/scene/resources/default_theme/radio_checked.png +++ b/scene/resources/default_theme/radio_checked.png diff --git a/scene/resources/default_theme/radio_unchecked.png b/scene/resources/default_theme/radio_unchecked.png Binary files differindex 7f0535c3a4..fe5bcf6ab1 100644 --- a/scene/resources/default_theme/radio_unchecked.png +++ b/scene/resources/default_theme/radio_unchecked.png diff --git a/scene/resources/default_theme/reference_border.png b/scene/resources/default_theme/reference_border.png Binary files differindex 96219676bf..6a680f393c 100644 --- a/scene/resources/default_theme/reference_border.png +++ b/scene/resources/default_theme/reference_border.png diff --git a/scene/resources/default_theme/scroll_bg.png b/scene/resources/default_theme/scroll_bg.png Binary files differindex cefadb2c08..fb151a48b1 100644 --- a/scene/resources/default_theme/scroll_bg.png +++ b/scene/resources/default_theme/scroll_bg.png diff --git a/scene/resources/default_theme/scroll_button_down.png b/scene/resources/default_theme/scroll_button_down.png Binary files differindex caeac9b286..1df4ef5b6b 100644 --- a/scene/resources/default_theme/scroll_button_down.png +++ b/scene/resources/default_theme/scroll_button_down.png diff --git a/scene/resources/default_theme/scroll_button_down_hl.png b/scene/resources/default_theme/scroll_button_down_hl.png Binary files differindex 48036e0297..ba79087393 100644 --- a/scene/resources/default_theme/scroll_button_down_hl.png +++ b/scene/resources/default_theme/scroll_button_down_hl.png diff --git a/scene/resources/default_theme/scroll_button_left.png b/scene/resources/default_theme/scroll_button_left.png Binary files differindex 3b50938d97..e430cb4673 100644 --- a/scene/resources/default_theme/scroll_button_left.png +++ b/scene/resources/default_theme/scroll_button_left.png diff --git a/scene/resources/default_theme/scroll_button_left_hl.png b/scene/resources/default_theme/scroll_button_left_hl.png Binary files differindex b3d348c24f..2a6ef17a34 100644 --- a/scene/resources/default_theme/scroll_button_left_hl.png +++ b/scene/resources/default_theme/scroll_button_left_hl.png diff --git a/scene/resources/default_theme/scroll_button_right.png b/scene/resources/default_theme/scroll_button_right.png Binary files differindex 1c622a41ad..4f61687aa4 100644 --- a/scene/resources/default_theme/scroll_button_right.png +++ b/scene/resources/default_theme/scroll_button_right.png diff --git a/scene/resources/default_theme/scroll_button_right_hl.png b/scene/resources/default_theme/scroll_button_right_hl.png Binary files differindex 108796ca02..10e2722509 100644 --- a/scene/resources/default_theme/scroll_button_right_hl.png +++ b/scene/resources/default_theme/scroll_button_right_hl.png diff --git a/scene/resources/default_theme/scroll_button_up.png b/scene/resources/default_theme/scroll_button_up.png Binary files differindex 2c8238ae4c..f425412f50 100644 --- a/scene/resources/default_theme/scroll_button_up.png +++ b/scene/resources/default_theme/scroll_button_up.png diff --git a/scene/resources/default_theme/scroll_button_up_hl.png b/scene/resources/default_theme/scroll_button_up_hl.png Binary files differindex 4283bd114a..615a236c52 100644 --- a/scene/resources/default_theme/scroll_button_up_hl.png +++ b/scene/resources/default_theme/scroll_button_up_hl.png diff --git a/scene/resources/default_theme/scroll_grabber.png b/scene/resources/default_theme/scroll_grabber.png Binary files differindex 1d625a9b7b..732725a28f 100644 --- a/scene/resources/default_theme/scroll_grabber.png +++ b/scene/resources/default_theme/scroll_grabber.png diff --git a/scene/resources/default_theme/scroll_grabber_hl.png b/scene/resources/default_theme/scroll_grabber_hl.png Binary files differindex 99eb24b7e7..006cfa3361 100644 --- a/scene/resources/default_theme/scroll_grabber_hl.png +++ b/scene/resources/default_theme/scroll_grabber_hl.png diff --git a/scene/resources/default_theme/scroll_grabber_pressed.png b/scene/resources/default_theme/scroll_grabber_pressed.png Binary files differindex a46d242ddd..f4886158fa 100644 --- a/scene/resources/default_theme/scroll_grabber_pressed.png +++ b/scene/resources/default_theme/scroll_grabber_pressed.png diff --git a/scene/resources/default_theme/selection.png b/scene/resources/default_theme/selection.png Binary files differindex 501877a8b4..7d1c985b35 100644 --- a/scene/resources/default_theme/selection.png +++ b/scene/resources/default_theme/selection.png diff --git a/scene/resources/default_theme/selection_oof.png b/scene/resources/default_theme/selection_oof.png Binary files differindex 9594fe0913..2da0538389 100644 --- a/scene/resources/default_theme/selection_oof.png +++ b/scene/resources/default_theme/selection_oof.png diff --git a/scene/resources/default_theme/spinbox_updown.png b/scene/resources/default_theme/spinbox_updown.png Binary files differindex b40b1e9fd2..74fab19f34 100644 --- a/scene/resources/default_theme/spinbox_updown.png +++ b/scene/resources/default_theme/spinbox_updown.png diff --git a/scene/resources/default_theme/submenu.png b/scene/resources/default_theme/submenu.png Binary files differindex ec727eecf1..8f7de446d4 100644 --- a/scene/resources/default_theme/submenu.png +++ b/scene/resources/default_theme/submenu.png diff --git a/scene/resources/default_theme/tab.png b/scene/resources/default_theme/tab.png Binary files differindex 3e4d792a48..895daa65e2 100644 --- a/scene/resources/default_theme/tab.png +++ b/scene/resources/default_theme/tab.png diff --git a/scene/resources/default_theme/tab_behind.png b/scene/resources/default_theme/tab_behind.png Binary files differindex 12f07c3a91..2803d9db65 100644 --- a/scene/resources/default_theme/tab_behind.png +++ b/scene/resources/default_theme/tab_behind.png diff --git a/scene/resources/default_theme/tab_close.png b/scene/resources/default_theme/tab_close.png Binary files differindex 20d9b5c810..af2775a132 100644 --- a/scene/resources/default_theme/tab_close.png +++ b/scene/resources/default_theme/tab_close.png diff --git a/scene/resources/default_theme/tab_container_bg.png b/scene/resources/default_theme/tab_container_bg.png Binary files differindex 92482aaf28..7d0bd16221 100644 --- a/scene/resources/default_theme/tab_container_bg.png +++ b/scene/resources/default_theme/tab_container_bg.png diff --git a/scene/resources/default_theme/tab_current.png b/scene/resources/default_theme/tab_current.png Binary files differindex 7289e032da..520d147217 100644 --- a/scene/resources/default_theme/tab_current.png +++ b/scene/resources/default_theme/tab_current.png diff --git a/scene/resources/default_theme/tab_menu.png b/scene/resources/default_theme/tab_menu.png Binary files differindex 148b64b8aa..fa4421a28a 100644 --- a/scene/resources/default_theme/tab_menu.png +++ b/scene/resources/default_theme/tab_menu.png diff --git a/scene/resources/default_theme/tab_menu_hl.png b/scene/resources/default_theme/tab_menu_hl.png Binary files differindex 148b64b8aa..fa4421a28a 100644 --- a/scene/resources/default_theme/tab_menu_hl.png +++ b/scene/resources/default_theme/tab_menu_hl.png diff --git a/scene/resources/default_theme/toggle_off.png b/scene/resources/default_theme/toggle_off.png Binary files differindex 71cd64b001..64b51c8c9d 100644 --- a/scene/resources/default_theme/toggle_off.png +++ b/scene/resources/default_theme/toggle_off.png diff --git a/scene/resources/default_theme/toggle_on.png b/scene/resources/default_theme/toggle_on.png Binary files differindex 6ea1b589c7..f0c699c181 100644 --- a/scene/resources/default_theme/toggle_on.png +++ b/scene/resources/default_theme/toggle_on.png diff --git a/scene/resources/default_theme/tool_button_pressed.png b/scene/resources/default_theme/tool_button_pressed.png Binary files differindex bcf70b486d..5494475792 100644 --- a/scene/resources/default_theme/tool_button_pressed.png +++ b/scene/resources/default_theme/tool_button_pressed.png diff --git a/scene/resources/default_theme/tooltip_bg.png b/scene/resources/default_theme/tooltip_bg.png Binary files differindex eca0675a98..07b7d942ca 100644 --- a/scene/resources/default_theme/tooltip_bg.png +++ b/scene/resources/default_theme/tooltip_bg.png diff --git a/scene/resources/default_theme/tree_bg.png b/scene/resources/default_theme/tree_bg.png Binary files differindex 839a6a272a..2b0c506f34 100644 --- a/scene/resources/default_theme/tree_bg.png +++ b/scene/resources/default_theme/tree_bg.png diff --git a/scene/resources/default_theme/tree_bg_disabled.png b/scene/resources/default_theme/tree_bg_disabled.png Binary files differindex a0fa505e4c..69d78febd9 100644 --- a/scene/resources/default_theme/tree_bg_disabled.png +++ b/scene/resources/default_theme/tree_bg_disabled.png diff --git a/scene/resources/default_theme/tree_bg_focus.png b/scene/resources/default_theme/tree_bg_focus.png Binary files differindex 692cf71926..aadc6b0db4 100644 --- a/scene/resources/default_theme/tree_bg_focus.png +++ b/scene/resources/default_theme/tree_bg_focus.png diff --git a/scene/resources/default_theme/tree_cursor.png b/scene/resources/default_theme/tree_cursor.png Binary files differindex 94d2a08818..2b8722d066 100644 --- a/scene/resources/default_theme/tree_cursor.png +++ b/scene/resources/default_theme/tree_cursor.png diff --git a/scene/resources/default_theme/tree_cursor_unfocus.png b/scene/resources/default_theme/tree_cursor_unfocus.png Binary files differindex 3f023bbabe..bfaebbea85 100644 --- a/scene/resources/default_theme/tree_cursor_unfocus.png +++ b/scene/resources/default_theme/tree_cursor_unfocus.png diff --git a/scene/resources/default_theme/tree_title.png b/scene/resources/default_theme/tree_title.png Binary files differindex b0ddcffbbe..e5f3f49695 100644 --- a/scene/resources/default_theme/tree_title.png +++ b/scene/resources/default_theme/tree_title.png diff --git a/scene/resources/default_theme/tree_title_pressed.png b/scene/resources/default_theme/tree_title_pressed.png Binary files differindex 746d10039e..35e2bb3008 100644 --- a/scene/resources/default_theme/tree_title_pressed.png +++ b/scene/resources/default_theme/tree_title_pressed.png diff --git a/scene/resources/default_theme/unchecked.png b/scene/resources/default_theme/unchecked.png Binary files differindex d6f790cbc2..8c818af755 100644 --- a/scene/resources/default_theme/unchecked.png +++ b/scene/resources/default_theme/unchecked.png diff --git a/scene/resources/default_theme/updown.png b/scene/resources/default_theme/updown.png Binary files differindex 916284a3cf..56f81921e8 100644 --- a/scene/resources/default_theme/updown.png +++ b/scene/resources/default_theme/updown.png diff --git a/scene/resources/default_theme/vseparator.png b/scene/resources/default_theme/vseparator.png Binary files differindex 498768c05b..51e79f3ac5 100644 --- a/scene/resources/default_theme/vseparator.png +++ b/scene/resources/default_theme/vseparator.png diff --git a/scene/resources/default_theme/vslider_bg.png b/scene/resources/default_theme/vslider_bg.png Binary files differindex 8d9ead3c5a..ba3244e3e5 100644 --- a/scene/resources/default_theme/vslider_bg.png +++ b/scene/resources/default_theme/vslider_bg.png diff --git a/scene/resources/default_theme/vslider_grabber.png b/scene/resources/default_theme/vslider_grabber.png Binary files differindex afc490be45..6c6bf93e68 100644 --- a/scene/resources/default_theme/vslider_grabber.png +++ b/scene/resources/default_theme/vslider_grabber.png diff --git a/scene/resources/default_theme/vslider_grabber_disabled.png b/scene/resources/default_theme/vslider_grabber_disabled.png Binary files differindex c830359f45..49cced5055 100644 --- a/scene/resources/default_theme/vslider_grabber_disabled.png +++ b/scene/resources/default_theme/vslider_grabber_disabled.png diff --git a/scene/resources/default_theme/vslider_grabber_hl.png b/scene/resources/default_theme/vslider_grabber_hl.png Binary files differindex 548972e115..28774fdbf8 100644 --- a/scene/resources/default_theme/vslider_grabber_hl.png +++ b/scene/resources/default_theme/vslider_grabber_hl.png diff --git a/scene/resources/default_theme/vslider_tick.png b/scene/resources/default_theme/vslider_tick.png Binary files differindex 873ebb00d8..bde788b563 100644 --- a/scene/resources/default_theme/vslider_tick.png +++ b/scene/resources/default_theme/vslider_tick.png diff --git a/scene/resources/default_theme/vsplit_bg.png b/scene/resources/default_theme/vsplit_bg.png Binary files differindex 7dd1d48b29..a5749f6d5c 100644 --- a/scene/resources/default_theme/vsplit_bg.png +++ b/scene/resources/default_theme/vsplit_bg.png diff --git a/scene/resources/default_theme/vsplitter.png b/scene/resources/default_theme/vsplitter.png Binary files differindex ec5542bf69..dde1f390df 100644 --- a/scene/resources/default_theme/vsplitter.png +++ b/scene/resources/default_theme/vsplitter.png diff --git a/scene/resources/default_theme/window_resizer.png b/scene/resources/default_theme/window_resizer.png Binary files differindex ed51968c4e..b06e6f5366 100644 --- a/scene/resources/default_theme/window_resizer.png +++ b/scene/resources/default_theme/window_resizer.png diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 8ee43ddc32..f2df7119e7 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -234,29 +234,6 @@ void AudioServer::_driver_process(int p_frames, int32_t *p_buffer) { todo -= to_copy; to_mix -= to_copy; } - -#ifdef DEBUG_ENABLED - if (OS::get_singleton() && OS::get_singleton()->is_stdout_verbose()) { - static uint64_t first_ticks = 0; - static uint64_t last_ticks = 0; - static uint64_t ticks = 0; - static int count = 0; - static int total = 0; - - ticks = OS::get_singleton()->get_ticks_msec(); - if ((ticks - first_ticks) > 10 * 1000 && count > 0) { - print_line("Audio Driver " + String(AudioDriver::get_singleton()->get_name()) + " average latency: " + itos(total / count) + "ms (frame=" + itos(p_frames) + ")"); - first_ticks = ticks; - total = 0; - count = 0; - } - - total += ticks - last_ticks; - count++; - - last_ticks = ticks; - } -#endif } void AudioServer::_mix_step() { |